OOP vs programmazione procedurale - pagina 33

 
Andrei:

Ma non si può programmare con OOP in MQL4, quindi è ancora più popolare.

Ho già mostrato il mio codice e lo mostrerò di nuovo:

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


Questa è l'interfaccia del processore di trading - è esattamente la stessa sia per MT4 che per MT5.

L'utente ottiene solo questa interfaccia - e ha tutte le possibilità di azioni di trading. Non devi nemmeno sapere se è su MT4 o MT5. Avete bisogno di comprare - chiamate la funzione Buy, che riempirà il ticket del componente di trading aperto (per MT4 è un ordine, per MT5 è una posizione), e restituirà il codice di ritorno del trade server.

Non hai nemmeno bisogno di pensare alla differenza tra i protocolli MT4 e MT5 - l'interfaccia fornisce tutto il necessario.

Queste sono tutte capacità OOP.

 
George Merts:

Ho già mostrato il mio codice e lo mostrerò di nuovo:

Questa è l'interfaccia del processore di trading - è esattamente la stessa sia per MT4 che per MT5.

L'utente riceve semplicemente questa interfaccia - e ha tutte le possibilità di azioni di trading. Non ha nemmeno bisogno di sapere se è su MT4 o MT5.

Ed è tutto grazie all'OOP.

Ci sono esempi di utilizzo per casi tipici?

 
Andrei:
Se la tua teoria era che MQL4=MQL5, allora MQL4 potrebbe essere eseguito su MT5 e viceversa.
Il mio codice funziona completamente invariato su MT4 e MT5.
 
Andrei:

Avete esempi di utilizzo per casi tipici?

Bene, diciamo, ecco la mia funzione che invia la richiesta di cambiare TP-SL al processore commerciale:

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

In primo luogo, gli oggetti della parte EA - formano richieste di azioni commerciali (qui, una di queste richieste è quella di cambiare TP-SL). Dopo di che, la funzione ProceedRequestInto() è chiamata per tutte le richieste per inviare informazioni su un'azione di compravendita al processore di compravendita.

Il processore commerciale stesso è un oggetto della seguente 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);          
};

Cioè, a seconda della piattaforma - la classe CTradeProcessor è ereditata o dalla classe CMT5TradeProcessor o dalla classe CMT4TradeProceccor.

Naturalmente, tutto questo potrebbe essere fatto senza OOP, con l'aiuto di switch e ifdef. Ma a mio avviso, l'approccio OOP è più conveniente e chiaro, e la cosa principale è che permette di isolare le entità l'una dall'altra e di sbarazzarsi della massa di variabili globali.

A proposito, un altro "eco di OOP" è proprio nelle funzioni aggiuntive di lavoro con gli ordini pendenti. Il processore di trade - lavora con ticket di operazioni, il che è scomodo - il riferimento al ticket in MT4 e MT5 è diverso. Ecco perché esiste la classe comune COrderInfoCore - discendente dell'interfaccia dell'ordine. È molto più conveniente passare al processore solo un puntatore a questo oggetto. Di conseguenza, in questo modo bypassiamo i frammenti dipendenti dalla piattaforma.

 
George Merts:

Bene, diciamo, ecco la mia funzione che invia la richiesta di cambiare TP-SL al processore commerciale:

In primo luogo, gli oggetti della parte EA - formano richieste di azioni commerciali (qui, una di queste richieste è quella di cambiare TP-SL). Poi la funzione ProceedRequestInto() è chiamata per tutte le richieste di inviare informazioni su un'azione di trading a un processore di trade.

Mi sembra troppo complicato per capire cosa sta realmente accadendo lì. E se non capite cosa succede al suo interno, è improbabile che lo usiate... Non è più facile scrivere una versione separata per MT5 e collegarla quando necessario?
 
George Merts:
Il mio codice funziona completamente invariato su MT4 e MT5.

Perché correre in terminali diversi?

 
Andrei:
Penso che sia troppo complicato per capire cosa sta realmente accadendo all'interno... E senza capire come funziona, non credo che qualcuno lo userà... Non è più facile scrivere una versione separata per MT5 e collegarla quando necessario?
Perché ho bisogno di "capire cosa c'è veramente dentro"? C'è un'interfaccia fissa che esegue un'azione, indipendentemente dalla piattaforma - è quella che usiamo noi. E quello che c'è, a un livello basso, che differenza fa?
 

George Merts:

Ma, a mio parere, l'approccio OOP è molto più conveniente e chiaro. E soprattutto - permette di isolare le entità l'una dall'altra, e di sbarazzarsi delle masse di variabili globali.

Questo è il punto, avendo isolato tutto da tutto, sarà molto più difficile trattare con tale codice, per non parlare dell'impossibilità di un adeguato debugging del codice quando è necessario conoscere i valori attuali di tutte le variabili richieste...

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

Perché correre in terminali diversi?

Perché il mio conto principale è aperto su MT4, e il mio tester di strategie è molto meglio su MT5.

È una richiesta comune dei clienti in Freelance - "deve funzionare sia su MT4 che su MT5" - significa che c'è una ragione per questo. Io stesso non vedo la ragione per lavorare in Freelance, ma si può chiedere a chi ci lavora perché i clienti richiedono la multipiattaforma.

 
George Merts:
Perché abbiamo bisogno di "capire cosa si fa realmente all'interno"? C'è un'interfaccia fissa che esegue un'azione, indipendentemente dalla piattaforma - è quella che usiamo noi. E quello che c'è, a un livello basso, che differenza fa?
Non si tratta del basso livello, si tratta della logica di ciò che scorre lì dove e in cosa in ogni momento possibile, compresa la conoscenza di tutte le variabili interne... Senza capire tutta questa logica ridondante, il senso di usare questo codice per un non autore scompare completamente...