OOP vs procedural programming - page 33

 
Andrei:

But you can't program with OOP in MQL4, so it's still more popular.

I've already shown my code, and I'll show it again:

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


This is the trade processor interface - it's exactly the same for both MT4 and MT5.

The user just gets this interface - and he has all the possibilities for trading actions. You don't even have to know whether it's on MT4 or MT5. You need to buy - call the function Buy, which will fill the ticket of the open trading component (for MT4 it is an order, for MT5 it is a position), and it will return the return code of the trade server.

You don't even need to think about the difference between MT4 and MT5 protocols - the interface provides everything you need.

These are all OOP capabilities.

 
George Merts:

I've shown my code before and I'll show it again:

This is the trade processor interface - it is exactly the same for both MT4 and MT5.

The user simply receives this interface - and he has all the possibilities for trading actions. He doesn't even need to know whether he is on MT4 or MT5.

And it's all thanks to OOP.

Are there any examples of use for typical cases?

 
Andrei:
If your theory was that MQL4=MQL5, then MQL4 could be run on MT5 and vice versa.
My code runs completely unchanged on MT4 and MT5.
 
Andrei:

Do you have examples of usage for typical cases?

Well, let's say, here is my function sending request to change TP-SL to trade processor:

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

First, EA part objects - form trade action requests (here, one such request is to change TP-SL). After that, ProceedRequestInto() function is called for all requests to send information about a trade action to the trade processor.

The trade processor itself is an object of the following class:

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

That is, depending on the platform - CTradeProcessor class is inherited either from CMT5TradeProcessor class or from CMT4TradeProceccor class.

Of course, all this could be done without OOP, with help of switches and ifdefs. But to my mind, OOP-approach is more convenient and clear, and the main thing is that it allows to isolate entities from each other and to get rid of mass of global variables.

By the way, another "echo of OOP" is just in the additional functions of working with the pending orders. The trade processor - works with ticket of deals, which is inconvenient - the reference to the ticket in MT4 and MT5 is different. That's why there is the common class COrderInfoCore - descendant of the order interface. It is much more convenient to pass to the processor just a pointer to this object. Accordingly, this way we bypass the platform-dependent fragments.

 
George Merts:

Well, let's say, here is my function sending request to change TP-SL to trade processor:

First, EA part objects - form trade action requests (here, one such request is to change TP-SL). Then ProceedRequestInto() function is called for all requests to send information about a trade action to a trade processor.

It seems too complicated to me to understand what is actually happening there. And if you don't understand what's going on inside it, you're unlikely to use it... Isn't it easier to write a separate version for MT5 and hook it up when necessary?
 
George Merts:
My code runs completely unchanged on MT4 and MT5.

Why run in different terminals?

 
Andrei:
I think it's too complicated to understand what's really going on inside... And without an understanding of how it works, I don't think anyone will use it... Isn't it easier to write a separate version for MT5 and plug it in when needed?
Why do I need to "understand what's really inside"? There is a fixed interface that performs an action, regardless of the platform - that's what we use. And what is there, at a low level - what difference does it make ?
 

George Merts:

But, in my opinion, OOP approach is much more convenient and clear. And most importantly - it allows to isolate entities from each other, and get rid of masses of global variables.

That's the point, having isolated everything from everything, it will be much more difficult to deal with such code, not to mention the impossibility of adequate debugging of code when you need to know current values of all required variables...

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

Why run in different terminals?

Because my main account is open on MT4, and my strategy tester is much better on MT5.

It is a common request of the clients in Freelance - "it must work on both MT4 and MT5" - it means that there is a reason for that. I myself do not see the reason for working in Freelance, but you can ask those who work there why customers request crossplatform.

 
George Merts:
Why do we need to "understand what's actually being done inside"? There is a fixed interface that performs an action, regardless of platform - that's what we use. And what is there, at a low level - what difference does it make ?
It's not about the low level, it's about the logic of what's flowing there where and into what at every possible point in time, including knowing all the internal variables... Without understanding all this redundant logic, the meaning of using this code for a non-author disappears completely...
Reason: