Domande su OOP in MQL5 - pagina 17

 
Mi stai spaventando.
 
Il punto, non è la forma, ma il significato.
 
fxsaber:

Guardate il formato del record CList. Lo state ignorando.

Bene, grazie, approfondirò la questione.

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

Penso "Evviva, sta funzionando!". (С)

#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

Ho allegato il modello CDataBase stesso, sarebbe conveniente - qualsiasi struttura (classe) creata come la mia e lasciare che memorizzi i dati in memoria(costruttore senza parametro) o, quando si aggiunge un nuovo elemento, scaricarlo su disco(costruttore con parametro)

SZZ: probabilmente c'è qualcos'altro che dropperò, ma in generale sono soddisfatto del risultato

File:
CDataBase.mqh  10 kb
 

Uso raramente i modificatori const e static, e ho provato accidentalmente a "inserire" una classe nel corpo della funzione, non ho idea di come funzioni, ma non ho trovato nessun errore durante i test

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

Ho intenzionalmente messo le chiamate di SymbolInfoDouble() in funzioni separate f1()-f3() per non stamparle


E la domanda stessa, quanto di questo codice funziona, dove possono essere i bug? Voglio ridurre al minimo le chiamate inutili, ma la classe in qualche modo funziona dentro la funzione, in generale funziona, ma per me non dovrebbe funzionare!

 
Igor Makanu:

Uso raramente i modificatori const e static, e ho provato accidentalmente a "inserire" una classe nel corpo della funzione, non ho idea di come funzioni, ma non ho trovato nessun errore durante i test

Ho intenzionalmente messo le chiamate di SymbolInfoDouble() in funzioni separate f1()-f3() per non stamparle


E la domanda stessa, quanto di questo codice funziona, dove possono essere i bug? Voglio ridurre al minimo le chiamate inutili, ma la classe in qualche modo funziona dentro la funzione, in generale funziona, ma per me non dovrebbe funzionare!

È tutto a posto. Funzionerà.

 
Vladimir Simakov:

Va bene. Funzionerà.

Grazie!

Ho testato il codice dell'EA di prova, non ho visto alcun bug, ho spostato i TF e scaricato l'EA dal grafico, funziona come mi aspettavo, tutte le variabili con modificatore const static sono inizializzate una volta (è interessante, che l'inizializzazione è fatta prima di avviare OnItin() - ho ignorato tutte le chiamate)

Ho migliorato il codice, forse qualcuno potrebbe aver bisogno della normalizzazione del volume degli ordini con arrotondamento(non funzionerà per gli Expert Advisors multivaluta!!!)

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

Si potrebbe anche scrivere così. Il significato è lo stesso, ma ci sono meno lettere. La variabile l_ sarà rimossa dal compilatore.

 
Vladimir Simakov:

Si può anche scrivere in questo modo. Il senso è lo stesso, ma ci sono meno lettere. Il compilatore rimuoverà la variabile l_ stessa.

Ho appena scritto il mio post ed eccoti qui... Penso che i codici siano quasi identici )))) la variabile L_ è necessaria qui sotto, è una parte del codice per piazzare un ordine, ho deciso di riordinare la mia libreria

SZZ: ho controllato, ma il modificatore const per un'istanza della classe vol non può essere scritto... meno lettere ))))

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

Per trovare il numero di caratteri in un lotto e la dimensione del lotto stesso.

 
Vladimir Simakov:


Per trovare il numero di caratteri in un lotto e la dimensione del lotto stesso.

Ho visto soluzioni simili, ma la mia funzione _OrderSend(....) è per lo stile procedurale, non sempre è conveniente usare OOP per gli EA primitivi,

Ho deciso di fare un numero minimo di chiamateSymbolInfoDouble() all'inizio, e poi ho deciso di sbarazzarmi della chiamata aggiuntiva NormalizeVolume() - ho provato a includere _OrderSend() nel corpo, ma lo scopo era di ricevere tutto l'ambiente di trading una volta e poi, quando un ordine si apre, leggere solo il suo volume,

Lo proverò e in generale sono soddisfatto del risultato, se trovo qualche bug, lo segnalerò nel topic