Programmation OOP vs programmation procédurale - page 33

 
Andrei:

Mais vous ne pouvez pas programmer avec la POO dans MQL4, c'est pourquoi il est toujours plus populaire.

J'ai déjà montré mon code, et je vais le montrer à nouveau :

class CTradeProcessorI : public CMyObject
{
public:
   void CTradeProcessorI() {    SetMyObjectType(MOT_TRADE_PROCESSOR_I); };
   virtual void ~CTradeProcessorI() {};
   
   // Настроечный интерфейс
   virtual void SetSlippage(uint uiSlippage) = 0;
   
   // Торговый интерфейс
   // Все функции возвращают код возврата торгового сервера
   virtual int Buy(long & lTicket,ECurrencySymbol csSymbol,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0;               // Всегда по цене Ask, если успешно - возвращается lTicket
   virtual int Sell(long & lTicket,ECurrencySymbol csSymbol,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0;              // Всегда по цене Bid, если успешно - возвращается lTicket  

   virtual int ModifyTPSL(CTradePosComponentI* ptpcComponent,double dTP=0,double dSL=0) = 0;       
   virtual int ModifyTPSL(long lTPCTicket,double dTP=0,double dSL=0) = 0;       

   virtual int CloseTradeComponent(CTradePosComponentI* ptpcComponent,double dCloseVolume=EMPTY_VALUE) = 0;              // dCloseVolume - закрываемый объем. Если равен EMPTY_VALUE или равен или больше, чем объем торговой компоненты с указанным тикетом - закрывается вся торговая компонента.   
   virtual int CloseTradeComponent(long lTPCTicket,double dCloseVolume=EMPTY_VALUE) = 0;              // dCloseVolume - закрываемый объем. Если равен EMPTY_VALUE или равен или больше, чем объем торговой компоненты с указанным тикетом - закрывается вся торговая компонента.   
   
   virtual int PendingSet(long & lTicket,ECurrencySymbol csSymbol,ENUM_ORDER_TYPE otOrderType,double dSetPrice,double dVolume,double dTP=0,double dSL=0,ulong ulMagic = 0,string strComment = NULL) = 0; // если успешно - возвращается lTicket
   virtual int PendingDelete(long lTicket) = 0; 
   virtual int PendingDelete(COrderInfoCore* poiOrder) = 0; 
   
   virtual int PendingModify(long lTicket,double dSetPrice,double dTP=0,double dSL=0) = 0;       
   virtual int PendingModify(COrderInfoCore* poiOrder,double dSetPrice,double dTP=0,double dSL=0) = 0;       
   
   // Проверка кода возврата
   virtual bool TradeOperationWasSuccessful(int iTradeResCode) = 0;
   
   // Если функция возвращает true, то при возникновении пользовательских ошибок (iTradeResCode > ERR_USER_ERROR_FIRST) советник прекратит работу
   // В случае false - работа будет продолжена
   virtual bool IsUserErrorsFalal() = 0;
};


Il s'agit de l'interface du processeur de transactions - elle est exactement la même pour MT4 et MT5.

L'utilisateur n'a que cette interface à sa disposition - et il dispose de toutes les possibilités d'actions commerciales. Vous n'avez même pas besoin de savoir si c'est sur MT4 ou MT5. Vous devez acheter - appelez la fonction Acheter, qui remplira le ticket du composant de négociation ouvert (pour MT4, il s'agit d'un ordre, pour MT5, d'une position), et renverra le code de retour du serveur de négociation.

Vous n'avez même pas besoin de réfléchir à la différence entre les protocoles MT4 et MT5 - l'interface fournit tout ce dont vous avez besoin.

Ce sont toutes des capacités OOP.

 
George Merts:

J'ai déjà montré mon code, et je vais le montrer à nouveau :

Il s'agit de l'interface du processeur de transactions - elle est exactement la même pour MT4 et MT5.

L'utilisateur reçoit simplement cette interface - et il dispose de toutes les possibilités d'actions de trading. Il n'a même pas besoin de savoir s'il est sur MT4 ou MT5.

Et c'est grâce à OOP.

Existe-t-il des exemples d'utilisation pour des cas typiques ?

 
Andrei:
Si votre théorie était que MQL4=MQL5, alors MQL4 pourrait être exécuté sur MT5 et vice versa.
Mon code fonctionne de manière totalement inchangée sur MT4 et MT5.
 
Andrei:

Avez-vous des exemples d'utilisation pour des cas typiques ?

Disons que ma fonction envoie une demande de changement de TP-SL en processeur de commerce :

EEAWorkRetcode CChngTPSLRequest::_ProceedRequestInto(CTradeProcessorI* ptpProcessor)
{
   ASSERT_MYPOINTER(ptpProcessor);
   
   m_uiServerRetCode = ptpProcessor.ModifyTPSL(m_lComponentTicket,m_dTP,m_dSL);

   if(ptpProcessor.TradeOperationWasSuccessful(m_uiServerRetCode) != true)
      {
      Print("Торговый запрос на изменение ТП-СЛ компоненты отработал с ошибкой, код возврата: ",m_uiServerRetCode);
      TRACE_INTEGER("Торговый запрос на изменение ТП-СЛ компоненты отработал с ошибкой, код возврата: ",m_uiServerRetCode);
      return(WR_SERVER_PROCEED_ERROR);
      };
   
   return(WR_SUCCEEDED);   
};

Tout d'abord, les objets de la partie EA - forment des demandes d'action commerciale (ici, une de ces demandes est de changer le TP-SL). Ensuite, la fonction ProceedRequestInto() est appelée pour toutes les demandes d'envoi d'informations sur une action commerciale au processeur commercial.

Le processeur commercial lui-même est un objet de la classe suivante :

// СTradeProcessor - переносимый класс торгового процессора
// Именно этот класс необходимо использовать для торговли. 
// Класс реализует интерфейс CTradeProcessorI

#ifdef __MQL5__
#include <MyLib\Trade\MT5TradeProcessor.mq5>
#else // __MQL5__
#include <MyLib\Trade\MT4TradeProcessor.mq5>
#endif //__MQL5__

#ifdef __MQL5__
class CTradeProcessor : public CMT5TradeProcessor
#else // __MQL5__
class CTradeProcessor : public CMT4TradeProcessor
#endif //__MQL5__

{
public:
   void CTradeProcessor(uint uiSlippage = DEFAULT_TRADE_POINT_SLIPPAGE);
   void ~CTradeProcessor() {};
 
   // Функции отложенных ордеров, которые используют платформоспецифические  
   virtual int PendingDelete(COrderInfoCore* poiOrder);
   virtual int PendingModify(COrderInfoCore* poiOrder,double dSetPrice,double dTP=0,double dSL=0);          
};

C'est-à-dire que, selon la plate-forme, la classe CTradeProcessor est héritée soit de la classe CMT5TradeProcessor, soit de la classe CMT4TradeProceccor.

Bien sûr, tout cela pourrait être fait sans POO, avec l'aide de commutateurs et de ifdefs. Mais à mon avis, l'approche de la POO est plus pratique et plus claire, et l'essentiel est qu'elle permet d'isoler les entités les unes des autres et de se débarrasser de la masse des variables globales.

D'ailleurs, un autre "écho de la POO" se trouve juste dans les fonctions supplémentaires de travail avec les commandes en cours. Le processeur de transaction - fonctionne avec le ticket de transaction, ce qui n'est pas pratique - la référence au ticket dans MT4 et MT5 est différente. C'est pourquoi il existe la classe commune COrderInfoCore - descendante de l'interface d'ordre. Il est beaucoup plus pratique de passer au processeur un simple pointeur vers cet objet. De cette façon, nous contournons les fragments dépendant de la plateforme.

 
George Merts:

Disons que ma fonction envoie une demande de changement de TP-SL en processeur de commerce :

Tout d'abord, les objets de la partie EA - forment des demandes d'action commerciale (ici, une de ces demandes est de changer le TP-SL). Ensuite, la fonction ProceedRequestInto() est appelée pour toutes les demandes d'envoi d'informations sur une action commerciale à un processeur commercial.

Cela me semble trop compliqué pour comprendre ce qui s'y passe réellement. Et si vous ne comprenez pas ce qui se passe à l'intérieur, vous avez peu de chances de l'utiliser... N'est-il pas plus facile d'écrire une version séparée pour MT5 et de la connecter lorsque cela est nécessaire ?
 
George Merts:
Mon code fonctionne de manière totalement inchangée sur MT4 et MT5.

Pourquoi courir dans des terminaux différents ?

 
Andrei:
Je pense que c'est trop compliqué de comprendre ce qui se passe vraiment à l'intérieur... Et sans comprendre comment il fonctionne, je ne pense pas que quiconque l'utilisera... N'est-il pas plus simple d'écrire une version distincte pour MT5 et de la brancher en cas de besoin ?
Pourquoi ai-je besoin de "comprendre ce qu'il y a vraiment à l'intérieur" ? Il existe une interface fixe qui exécute une action, quelle que soit la plateforme - c'est ce que nous utilisons. Et ce qui est là, à un faible niveau, quelle différence cela fait-il ?
 

George Merts:

Mais, à mon avis, l'approche OOP est beaucoup plus pratique et claire. Et surtout, elle permet d'isoler les entités les unes des autres, et de se débarrasser des masses de variables globales.

C'est le but, en ayant tout isolé de tout, il sera beaucoup plus difficile de traiter un tel code, sans parler de l'impossibilité d'un débogage adéquat du code lorsque vous avez besoin de connaître les valeurs actuelles de toutes les variables requises...

 
СанСаныч Фоменко:

Pourquoi courir dans des terminaux différents ?

Parce que mon compte principal est ouvert sur MT4, et mon testeur de stratégie est bien meilleur sur MT5.

C'est une demande courante des clients de Freelance - "il doit fonctionner à la fois sur MT4 et MT5" - cela signifie qu'il y a une raison à cela. Personnellement, je ne vois pas la raison de travailler en Freelance, mais vous pouvez demander à ceux qui y travaillent pourquoi les clients demandent du crossplatform.

 
George Merts:
Pourquoi avons-nous besoin de "comprendre ce qui se passe réellement à l'intérieur" ? Il existe une interface fixe qui exécute une action, quelle que soit la plate-forme - c'est ce que nous utilisons. Et ce qui est là, à un faible niveau, quelle différence cela fait-il ?
Il ne s'agit pas du bas niveau, mais de la logique de ce qui circule là où et dans quoi à chaque instant, y compris la connaissance de toutes les variables internes... Sans comprendre toute cette logique redondante, le sens de l'utilisation de ce code pour un non-auteur disparaît complètement...