Programação OOP vs procedimento - página 33

 
Andrei:

Mas você não pode programar com OOP em MQL4, por isso ainda é mais popular.

Eu já mostrei meu código e vou mostrá-lo novamente:

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 é a interface do processador comercial - é exatamente a mesma tanto para o MT4 quanto para o MT5.

O usuário apenas obtém esta interface - e ele tem todas as possibilidades de ações comerciais. Você nem precisa saber se está no MT4 ou MT5. Você precisa comprar - ligue para a função Comprar, que preencherá o ticket do componente de negociação aberto (para MT4 é uma ordem, para MT5 é uma posição), e retornará o código de retorno do servidor de negociação.

Você não precisa nem pensar na diferença entre os protocolos MT4 e MT5 - a interface fornece tudo o que você precisa.

Todas estas são capacidades do OOP.

 
George Merts:

Eu já mostrei meu código antes e vou mostrá-lo novamente:

Esta é a interface do processador comercial - é exatamente a mesma tanto para o MT4 quanto para o MT5.

O usuário simplesmente recebe esta interface - e ele tem todas as possibilidades de ações comerciais. Ele nem precisa saber se está no MT4 ou MT5.

E tudo isso graças ao OOP.

Há alguns exemplos de uso para casos típicos?

 
Andrei:
Se sua teoria fosse que MQL4=MQL5, então a MQL4 poderia ser executada no MT5 e vice-versa.
Meu código funciona completamente inalterado em MT4 e MT5.
 
Andrei:

Você tem exemplos de uso para casos típicos?

Bem, digamos, aqui está minha função enviando pedido de mudança de TP-SL para processador comercial:

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

Primeiro, os objetos da parte EA - formam pedidos de ação comercial (aqui, um desses pedidos é para mudar o TP-SL). Depois disso, a função ProceedRequestInto() é chamada para todos os pedidos de envio de informações sobre uma ação comercial para o processador comercial.

O próprio processador comercial é um objeto da seguinte classe:

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

Isto é, dependendo da plataforma - a classe CTradeProcessor é herdada da classe CMT5TradeProcessor ou da classe CMT4TradeProceccor.

É claro que tudo isso poderia ser feito sem OOP, com a ajuda de interruptores e ifdefs. Mas, para mim, a abordagem OOP é mais conveniente e clara, e o principal é que ela permite isolar as entidades umas das outras e se livrar da massa de variáveis globais.

A propósito, outro "eco do OOP" está apenas nas funções adicionais de trabalhar com as ordens pendentes. O processador comercial - trabalha com bilhete de negócios, o que é inconveniente - a referência ao bilhete em MT4 e MT5 é diferente. É por isso que existe a classe comum COrderInfoCore - descendente da interface do pedido. É muito mais conveniente passar para o processador apenas um ponteiro para este objeto. Desta forma, contornamos assim os fragmentos dependentes da plataforma.

 
George Merts:

Bem, digamos, aqui está minha função enviando pedido de mudança de TP-SL para processador comercial:

Primeiro, os objetos da parte EA - formam pedidos de ação comercial (aqui, um desses pedidos é para mudar o TP-SL). Então a função ProceedRequestInto() é chamada para todas as solicitações para enviar informações sobre uma ação comercial a um processador comercial.

Parece-me complicado demais para entender o que está realmente acontecendo ali. E se você não entende o que está acontecendo dentro dele, é improvável que você o use... Não é mais fácil escrever uma versão separada para o MT5 e ligá-lo quando necessário?
 
George Merts:
Meu código funciona completamente inalterado em MT4 e MT5.

Por que funcionar em terminais diferentes?

 
Andrei:
Acho que é muito complicado entender o que realmente se passa lá dentro... E sem entender como funciona, acho que ninguém vai usá-lo... Não é mais fácil escrever uma versão separada para o MT5 e conectá-la quando você precisar dela?
Por que eu preciso "entender o que está realmente dentro"? Há uma interface fixa que realiza uma ação, independentemente da plataforma - é o que usamos. E o que existe, a um nível baixo - que diferença faz?
 

George Merts:

Mas, na minha opinião, a abordagem OOP é muito mais conveniente e clara. E o mais importante - ela permite isolar entidades umas das outras, e se livrar de massas de variáveis globais.

Esse é o ponto, tendo isolado tudo de tudo, será muito mais difícil lidar com tal código, sem mencionar a impossibilidade de depuração adequada do código quando você precisar conhecer os valores atuais de todas as variáveis necessárias...

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

Por que funcionar em terminais diferentes?

Porque minha conta principal está aberta no MT4, e meu testador de estratégia é muito melhor no MT5.

É um pedido comum dos clientes em Freelance - "deve funcionar tanto no MT4 quanto no MT5" - significa que há uma razão para isso. Eu mesmo não vejo a razão de trabalhar em Freelance, mas você pode perguntar àqueles que trabalham lá por que os clientes solicitam uma plataforma cruzada.

 
George Merts:
Por que precisamos "entender o que está realmente sendo feito por dentro"? Há uma interface fixa que realiza uma ação, independentemente da plataforma - é o que usamos. E o que existe, a um nível baixo - que diferença faz?
Não se trata do nível baixo, trata-se da lógica do que está fluindo lá onde e em quê em todos os momentos possíveis, incluindo o conhecimento de todas as variáveis internas... Sem entender toda essa lógica redundante, o significado de usar esse código para um não-autor desaparece completamente...