Questions on OOP in MQL5 - page 17

 
You're scaring me.
 
The point, not the form, but the meaning.
 
fxsaber:

Look at the CList record format. You are ignoring it.

Right! Thanks, I'll look into it further.

...................

I think "Yay! It's working!" (С)

#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

I've attached the CDataBase template itself, it would be convenient - any structure (class) created like mine and let it either store data in memory (constructor without parameter) or, when adding a new element, dump it to disk (constructor with parameter)

SZZ: probably something else I will dopish, but in general I am satisfied with the result

Files:
CDataBase.mqh  10 kb
 

I rarely use const and static modifiers, and I accidentally tried to "plug" a class into function body, have no idea how it works, but I found no error when testing

#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));
  }
//+------------------------------------------------------------------+

I intentionally put calls of SymbolInfoDouble() into separate functions f1()-f3() to unprint it


And the question itself, how much of this code works, where can be bugs? I want to minimize unnecessary calls, but the class somehow works inside the function, in general it works, but to me it should not work!

 
Igor Makanu:

I rarely use const and static modifiers, and I accidentally tried to "plug" a class into function body, have no idea how it works, but I found no error when testing

I intentionally put calls of SymbolInfoDouble() into separate functions f1()-f3() to unprint it


And the question itself, how much of this code works, where can be bugs? I want to minimize unnecessary calls, but the class somehow works inside the function, in general it works, but for me it should not work!

It's OK. It will work.

 
Vladimir Simakov:

It's fine. It will work.

Thank you!

i have tested in the code of test EA, i haven't seen any bugs, i have shifted TFs and unloaded EA from chart, it works as i expected, all variables with const static modifier are initialized once (it is interesting, that initialization is done before starting OnItin() - i unsigned all calls)

I improved the code, may be someone may need normalization of order volume with rounding(will not work for multicurrency Expert Advisors!!!)

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_);
  }

You could also write it like this. The meaning is the same, but there are fewer letters. The l_ variable will be removed by the compiler.

 
Vladimir Simakov:

You may also write it that way. The sense is the same, but there are fewer letters. The compiler will remove the l_ variable itself.

I've just written my post and here you are... I think the codes are almost identical )))) , the L_ variable is needed below, it's a part of the code for placing an order, I decided to tidy up my library

SZZ: I checked, but modifier const for an instance of vol class may not be written... less letters ))))

 
   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);}

To find the number of characters in a lot and the lot size itself.

 
Vladimir Simakov:


To find the number of characters in a lot and the lot size itself.

I have seen similar solutions, but my function _OrderSend(....) is for procedural style, not always convenient to use OOP for primitive EAs,

I decided to make a minimum number of callsSymbolInfoDouble() at first, and then I decided to get rid of additional call NormalizeVolume() - I tried to include _OrderSend() into the body, but the purpose was to receive all the trading environment once and then, when an order opens, to read its volume only,

I will try it and in general I am satisfied with the result, if I find any bugs, I will report them in the topic