Questions sur la POO dans MQL5 - page 17

 
Tu me fais peur.
 
L'important, ce n'est pas la forme, mais le sens.
 
fxsaber:

Regardez le format d'enregistrement CList. Vous l'ignorez.

C'est vrai ! Merci, je vais me pencher sur la question.

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

Je pense "Yay ! Ca marche !" (С)

#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

J'ai joint le modèle CDataBase lui-même, il serait pratique - n'importe quelle structure (classe) créée comme la mienne et la laisser soit stocker les données en mémoire(constructeur sans paramètre) ou, lors de l'ajout d'un nouvel élément, les vider sur le disque(constructeur avec paramètre).

SZZ : il y a probablement quelque chose d'autre que je doperai, mais en général, je suis satisfait du résultat.

Dossiers :
CDataBase.mqh  10 kb
 

J'utilise rarement les modificateurs const et static, et j'ai accidentellement essayé de "brancher" une classe dans le corps d'une fonction, je n'ai aucune idée de comment cela fonctionne, mais je n'ai pas trouvé d'erreur lors des tests.

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

J'ai intentionnellement mis les appels de SymbolInfoDouble() dans des fonctions séparées f1()-f3() pour le désimprimer.


Et la question elle-même, combien de ce code fonctionne, où peuvent être des bugs ? Je veux minimiser les appels inutiles, mais la classe fonctionne en quelque sorte à l'intérieur de la fonction, en général cela fonctionne, mais pour moi cela ne devrait pas fonctionner !

 
Igor Makanu:

J'utilise rarement les modificateurs const et static, et j'ai accidentellement essayé de "brancher" une classe dans le corps d'une fonction, je n'ai aucune idée de comment cela fonctionne, mais je n'ai pas trouvé d'erreur lors des tests.

J'ai intentionnellement mis les appels de SymbolInfoDouble() dans des fonctions séparées f1()-f3() pour le désimprimer.


Et la question elle-même, combien de ce code fonctionne, où peuvent être des bugs ? Je veux minimiser les appels inutiles, mais la classe fonctionne en quelque sorte à l'intérieur de la fonction, en général cela fonctionne, mais pour moi cela ne devrait pas fonctionner !

C'est bon. Ça va marcher.

 
Vladimir Simakov:

C'est bon. Ça va marcher.

Merci !

J'ai testé dans le code de l'EA de test, je n'ai vu aucun bug, j'ai déplacé les TFs et déchargé l'EA du graphique, cela fonctionne comme prévu, toutes les variables avec le modificateur const static sont initialisées une fois (il est intéressant que l'initialisation soit faite avant de lancer OnItin() - j'ai désynchronisé tous les appels).

J'ai amélioré le code, mais il se peut que quelqu'un ait besoin de normaliser le volume des ordres avec des arrondis(cela ne fonctionnera pas pour les Expert Advisors multi-devises!!!)

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

Vous pourriez aussi l'écrire comme ceci. Le sens est le même, mais il y a moins de lettres. La variable l_ sera supprimée par le compilateur.

 
Vladimir Simakov:

Vous pouvez aussi l'écrire de cette façon. Le sens est le même, mais il y a moins de lettres. Le compilateur supprimera la variable l_ elle-même.

Je viens d'écrire mon post et vous voilà... Je pense que les codes sont presque identiques )))) La variable L_ est nécessaire ci-dessous, c'est une partie du code pour passer une commande, j'ai décidé de mettre de l'ordre dans ma bibliothèque.

SZZ : J'ai vérifié, mais le modificateur const pour une instance de la classe vol ne peut pas être écrit... moins de lettres ))))

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

Pour trouver le nombre de caractères dans un lot et la taille du lot lui-même.

 
Vladimir Simakov:


Pour trouver le nombre de caractères dans un lot et la taille du lot lui-même.

J'ai vu des solutions similaires, mais ma fonction _OrderSend(....) est de style procédural, ce n'est pas toujours pratique d'utiliser la POO pour des EAs primitifs,

J'ai décidé de faire un minimum d'appelsSymbolInfoDouble() dans un premier temps, puis j'ai décidé de me débarrasser de l'appel supplémentaire NormalizeVolume() - J'ai essayé d'inclure _OrderSend() dans le corps, mais le but était de recevoir tout l'environnement de négociation une fois et ensuite, lorsqu'un ordre s'ouvre, de lire uniquement son volume,

Je vais l'essayer et en général je suis satisfait du résultat, si je trouve des bugs, je les signalerai dans le sujet