OOP vs. programación procedimental - página 33

 
Andrei:

Pero no se puede programar con OOP en MQL4, por lo que sigue siendo más popular.

Ya he mostrado mi código, y lo mostraré de nuevo:

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


Esta es la interfaz del procesador de operaciones - es exactamente la misma para MT4 y MT5.

El usuario sólo tiene esta interfaz, y dispone de todas las posibilidades para realizar acciones comerciales. Ni siquiera tienes que saber si está en MT4 o MT5. Necesita comprar - llame a la función Comprar, que llenará el ticket del componente de comercio abierto (para MT4 es una orden, para MT5 es una posición), y devolverá el código de retorno del servidor de comercio.

Ni siquiera tiene que pensar en la diferencia entre los protocolos MT4 y MT5: la interfaz le proporciona todo lo que necesita.

Todas estas son capacidades OOP.

 
George Merts:

Ya he mostrado mi código, y lo mostraré de nuevo:

Esta es la interfaz del procesador de operaciones - es exactamente la misma para MT4 y MT5.

El usuario simplemente recibe esta interfaz - y tiene todas las posibilidades para las acciones de comercio. Ni siquiera necesita saber si está en MT4 o MT5.

Y todo gracias a la OOP.

¿Hay ejemplos de uso para casos típicos?

 
Andrei:
Si su teoría era que MQL4=MQL5, entonces MQL4 podría ejecutarse en MT5 y viceversa.
Mi código funciona completamente sin cambios en MT4 y MT5.
 
Andrei:

¿Tiene ejemplos de uso para casos típicos?

Bien, digamos que aquí está mi función enviando la solicitud de cambio de TP-SL a procesador de comercio:

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

En primer lugar, los objetos de la parte de EA - forman solicitudes de acción comercial (aquí, una de esas solicitudes es cambiar el TP-SL). A continuación, se llama a la función ProceedRequestInto() para que todas las solicitudes envíen información sobre una acción comercial al procesador de operaciones.

El propio procesador de comercio es un objeto de la siguiente clase:

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

Es decir, dependiendo de la plataforma - la clase CTradeProcessor se hereda de la clase CMT5TradeProcessor o de la clase CMT4TradeProceccor.

Por supuesto, todo esto podría hacerse sin OOP, con la ayuda de interruptores y ifdefs. Pero en mi opinión, el enfoque OOP es más conveniente y claro, y lo principal es que permite aislar las entidades entre sí y deshacerse de la masa de variables globales.

Por cierto, otro "eco de OOP" está justo en las funciones adicionales de trabajar con las órdenes pendientes. El procesador de operaciones - trabaja con el ticket de las operaciones, lo cual es un inconveniente - la referencia al ticket en MT4 y MT5 es diferente. Por eso existe la clase común COrderInfoCore - descendiente de la interfaz de órdenes. Es mucho más conveniente pasar al procesador sólo un puntero a este objeto. De este modo, evitamos los fragmentos dependientes de la plataforma.

 
George Merts:

Bien, digamos que aquí está mi función enviando la solicitud de cambio de TP-SL a procesador de comercio:

En primer lugar, los objetos de la parte de EA - forman solicitudes de acción comercial (aquí, una de esas solicitudes es cambiar el TP-SL). A continuación, se llama a la función ProceedRequestInto() para todas las solicitudes de envío de información sobre una acción comercial a un procesador comercial.

Me parece demasiado complicado entender lo que realmente está sucediendo allí. Y si no entiendes lo que ocurre en su interior, es poco probable que lo utilices... ¿No es más fácil escribir una versión separada para MT5 y conectarla cuando sea necesario?
 
George Merts:
Mi código funciona completamente sin cambios en MT4 y MT5.

¿Por qué correr en diferentes terminales?

 
Andrei:
Creo que es demasiado complicado entender lo que realmente sucede en el interior... Y sin entender cómo funciona, no creo que nadie lo use... ¿No es más fácil escribir una versión separada para MT5 y conectarla cuando sea necesario?
¿Por qué necesito "entender lo que realmente hay dentro"? Hay una interfaz fija que realiza una acción, independientemente de la plataforma - eso es lo que usamos. Y lo que hay, a bajo nivel, ¿qué diferencia hay?
 

George Merts:

Pero, en mi opinión, el enfoque OOP es mucho más conveniente y claro. Y lo más importante - permite aislar las entidades entre sí, y deshacerse de las masas de variables globales.

Esa es la cuestión, al haber aislado todo de todo, será mucho más difícil tratar con ese código, por no hablar de la imposibilidad de depurar adecuadamente el código cuando se necesita conocer los valores actuales de todas las variables necesarias...

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

¿Por qué correr en diferentes terminales?

Porque mi cuenta principal está abierta en MT4, y mi probador de estrategias es mucho mejor en MT5.

Es una petición común de los clientes en Freelance - "debe funcionar tanto en MT4 como en MT5" - significa que hay una razón para ello. Yo mismo no veo la razón de trabajar en Freelance, pero puedes preguntar a los que trabajan allí por qué los clientes piden multiplataforma.

 
George Merts:
¿Por qué necesitamos "entender lo que realmente se hace dentro"? Hay una interfaz fija que realiza una acción, independientemente de la plataforma - eso es lo que usamos. Y lo que hay, a bajo nivel, ¿qué diferencia hay?
No se trata del bajo nivel, sino de la lógica de lo que fluye allí, dónde y hacia qué en cada momento posible, incluyendo el conocimiento de todas las variables internas... Sin entender toda esta lógica redundante, el sentido de utilizar este código para un no autor desaparece por completo...
Razón de la queja: