MQL5におけるOOPに関する質問 - ページ 17

 
怖いよ
 
ポイントは、形ではなく、意味。
 
fxsaber:

CListのレコード形式を見てください。無視してるんですね。

そうなんですね!ありがとうございます、さらに調べてみます。

"やった!効いてる!"と思うんです。(С)

#include <IgorM\CDataBase.mqh>
//+------------------------------------------------------------------+
class COrderBase : public CObject
  {
public: COrderBase(){};
   //-------------------------------------
   int               OrderTicket;
   double            OrderLots;
   string            OrderComment;
                     COrderBase(int ival,double dval);
   virtual bool      Save(const int file_handle);
   virtual bool      Load(const int file_handle);
  };
//+------------------------------------------------------------------+
void COrderBase::COrderBase(int ival,double dval)
  {
   this.OrderTicket=ival;
   this.OrderLots=dval;
   OrderComment="qwerty_"+IntegerToString(ival,2);
  }
//|                                                                  |
//+------------------------------------------------------------------+
bool COrderBase::Save(const int file_handle)
  {
   uint len=StringLen(OrderComment);
   return(::FileWriteInteger (file_handle,this.OrderTicket) &&
          ::FileWriteDouble  (file_handle,this.OrderLots)   &&
          ::FileWriteInteger( file_handle,len,INT_VALUE)    &&
          (len>0 ? ::FileWriteString(file_handle,OrderComment,len)==len : true)
          );
  }
//-------------------------------------
bool COrderBase::Load(const int file_handle)
  {
   ::ResetLastError();
   this.OrderTicket=::FileReadInteger(file_handle);
   this.OrderLots=::FileReadDouble(file_handle);
   uint len=FileReadInteger(file_handle,INT_VALUE);
   this.OrderComment=len>0 ? FileReadString(file_handle,len) : "";
   return(!::GetLastError());
  }
//+------------------------------------------------------------------+
void OnStart()
  {
   int i;
   CDataBase<COrderBase>data(31);
   for(i=0; i<5; i++) data.AddValue(new COrderBase(i,i*2.0));     // сюда вообще только тикет ордера нужно передавать!!!
   Print("1. Тип БД : ",data.TypeName()," , количествоо записей = ",data.ArraySize(),",  чтение данных :");
   for(i=0; i<data.ArraySize(); i++) Print(i," : ",data[i].OrderTicket," , ",data[i].OrderLots,",",data[i].OrderComment);
  }
//+------------------------------------------------------------------+
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	1. Тип БД : COrderBase , количествоо записей = 5,  чтение данных :
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	0 : 0 , 0.0,qwerty_ 0
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	1 : 1 , 2.0,qwerty_ 1
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	2 : 2 , 4.0,qwerty_ 2
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	3 : 3 , 6.0,qwerty_ 3
//2019.07.09 17:26:14.829	tst_CDataBase (EURUSD,H1)	4 : 4 , 8.0,qwerty_ 4

CDataBaseのテンプレートそのものを添付しておきます。私のような構造体(クラス)を作って、データをメモリに保存するか(パラメータなしのコンストラクタ)、新しい要素を追加するときに、それをディスクにダンプするか(パラメータ付きのコンストラクタ)をさせると便利だと思います。

SZZ:おそらく、もっと別のことをやるかもしれませんが、全般的には満足しています。

ファイル:
CDataBase.mqh  10 kb
 

私はconstやstatic修飾子をほとんど使いませんが、誤ってクラスを関数本体に「プラグイン」してしまいました。

#property strict
//+------------------------------------------------------------------+
void OnStart()
  {
   double lot=0.0;
   for(int i=0;i<50; i++)
     {
      Print(lot," = ",_OrderSend(lot));
      lot+=0.003;
     }
  }
//+------------------------------------------------------------------+
double _OrderSend(double lot_)
  {
   class CDig
     {
   public:
                        CDig(double vs){long i=10000000,k=long(vs/0.0000001);dig=0;while(dig<7 && k%i>0){i/=10;dig++;}Print(__FUNCSIG__);}
      int               dig;
     };
   const static double vol_step_= f1();
   const static double vol_max_ = f2();
   const static double vol_min_ = f3();
   const static CDig ld_(vol_step_);
   const static int vol_dig_=ld_.dig;
   double l_=NormalizeDouble(fmax(fmin(vol_step_*round(lot_/vol_step_),vol_max_),vol_min_),vol_dig_);
   return(l_);
  }
//+------------------------------------------------------------------+
double f1()
  {
   Print(__FUNCSIG__);
   return(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP));
  }
//+------------------------------------------------------------------+
double f2()
  {
   Print(__FUNCSIG__);
   return(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX));
  }
//+------------------------------------------------------------------+
double f3()
  {
   Print(__FUNCSIG__);
   return(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN));
  }
//+------------------------------------------------------------------+

SymbolInfoDouble()の呼び出しをわざと別の関数f1()〜f3()に入れて、アンプリントするようにしました。


また、質問自体も、このコードがどの程度機能しているか、どこにバグがあるのか?私 は不必要な呼び出しを最小限にしたいのですが、クラスはなぜか関数の中で動作します。

 
Igor Makanu:

私はconstやstatic修飾子をほとんど使いませんが、誤ってクラスを関数本体に「プラグイン」してしまいました。

SymbolInfoDouble()の呼び出しをわざと別の関数f1()〜f3()に入れて、アンプリントするようにしました。


また、質問自体も、このコードがどの程度機能しているか、どこにバグがあるのか?私 は不必要な呼び出しを最小限にしたいのですが、クラスはなぜか関数の中で動作します。

いいんです。きっとうまくいく。

 
Vladimir Simakov:

大丈夫です。きっとうまくいく。

ありがとうございました。

テストEAのコードでテストしてみましたが、特にバグもなく、TFをずらし、チャートからEAをアンロードすると、予想通り動作し、const static修飾子を持つすべての変数は一度初期化されます(興味深いのは、初期化はOnItin()を始める前に行われることです - 私はすべての呼び出しを符号なしにしています)。

私は、コードを改善し、誰かが丸めを使用して注文数量の正規化を必要とするかもしれない多通貨のExpert Advisorの ために動作しません!!!)。

double _OrderSend2(double lot_)
  {
   const static double vol_step_= SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   const static double vol_max_ = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   const static double vol_min_ = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   static class CDig{public:int digits(double v){long i=10000000,k=long(v/0.0000001);int d=0;while(d<7 && k%i>0){i/=10;d++;}return(d);}}vol;
   const static int vol_dig_=vol.digits(vol_step_);
   double l_=NormalizeDouble(fmax(fmin(vol_step_*round(lot_/vol_step_),vol_max_),vol_min_),vol_dig_);
// еуе код открытия ордера
   return(l_);
  }
 
double _OrderSend(double lot_)
  {
   const static double vol_step_= f1();
   const static double vol_max_ = f2();
   const static double vol_min_ = f3();
   const static class CDig
     {
   public:
                        CDig(double vs){long i=10000000,k=long(vs/0.0000001);dig=0;while(dig<7 && k%i>0){i/=10;dig++;}Print(__FUNCSIG__);}
      int               dig;
     } ld_(vol_step_);
   const static int vol_dig_=ld_.dig;
   return NormalizeDouble(fmax(fmin(vol_step_*round(lot_/vol_step_),vol_max_),vol_min_),vol_dig_);
  }

こんな風に書くこともできます。意味は同じですが、文字数が少なくなっています。l_ 変数は、コンパイラによって削除されます。

 
Vladimir Simakov:

そのように書いてもよい。感覚は同じだが、文字数が少ない。コンパイラは l_ 変数自体を削除します。

せっかく書き込みをしたのに、これでは...。コードはほとんど同じだと思います ))))L_という変数が必要なのは、注文するコードの一部なので、ライブラリを整理することにしました。

SZZ:確認しましたが、volクラスのインスタンスに対するモディファイアconstは書かれていないかもしれません...。文字数が少ない )))

 
   lotDigits=MathMax(-(int)MathFloor(MathLog10(lotStep)),0);


double CBaseTrade::NormalizeVolume(double mVolume,bool mMinIsAlways=true){
   double x=MathPow(10,_lotDigits);
   mVolume=MathFloor(MathRound(mVolume*x)/_lotStep/x)*_lotStep;
   if (mVolume<_lotMin) return mMinIsAlways?_lotMin:0.0;
   if (mVolume>_lotMax) return _lotMax;
   return NormalizeDouble(mVolume,_lotDigits);}

ロットの文字数やロットサイズそのものを求める場合。

 
Vladimir Simakov:


ロットの文字数やロットサイズそのものを求める場合。

似たような解決策を見たことがありますが、私の関数 _OrderSend(...) は手続き型なので、原始的なEAにOOPを使うのは必ずしも便利ではありません。

最初はSymbolInfoDouble()の 呼び出しを最小限にし、追加のNormalizeVolume()の呼び出しをなくすことにしました。_OrderSend()をボディに含めようとしましたが、目的はすべての取引環境を一度受信し、注文開始時にそのボリュームだけを読み取ることでした。

試してみますが、概ね満足です。もしバグを発見したら、トピックで報告します