OOP与程序化编程 - 页 33

 
Andrei:

但你不能在MQL4中用OOP编程,所以它还是更受欢迎。

我已经展示了我的代码,现在我再展示一次。

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


这是交易处理器界面--它对MT4和MT5都完全一样。

用户只需得到这个界面--他就有所有交易行为的可能性。你甚至不需要知道是在MT4还是MT5上。你需要买入 - 调用函数Buy,它将填补开放交易组件的票据(对于MT4是订单,对于MT5是仓位),它将返回交易服务器的返回代码

你甚至不需要考虑MT4和MT5协议之间的区别--界面提供了你需要的一切。

这些都是OOP能力。

 
George Merts:

我以前展示过我的代码,现在我再展示一次。

这是交易处理器界面--它对MT4和MT5都是完全一样的。

用户只需接收这个界面--他就有了交易行动的所有可能性。他甚至不需要知道自己是使用MT4还是MT5。

而这一切都要归功于OOP。

是否有任何典型案例的使用实例?

 
Andrei:
如果你的理论是MQL4=MQL5,那么MQL4就可以在MT5上运行,反之亦然。
我的代码在MT4和MT5上运行完全没有变化。
 
Andrei:

你有典型案例的使用实例吗?

好吧,比方说,这里是我的函数发送请求,将TP-SL改为贸易处理器。

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

首先,EA部分对象--形成交易行动请求(这里,一个这样的请求是改变TP-SL)。之后,ProceedRequestInto()函数被调用,用于所有向交易处理器发送交易行动信息的请求。

交易处理器本身是以下类别的一个对象。

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

也就是说,根据平台的不同 - CTradeProcessor类是继承自CMT5TradeProcessor类或CMT4TradeProceccor类。

当然,所有这些都可以在没有OOP的情况下,通过开关和ifdefs的帮助完成。但在我看来,OOP方法更方便、更清晰,最主要的是它允许实体之间相互隔离,摆脱大量的全局变量。

顺便说一下,另一个 "OOP的回声 "只是在处理未决订单的额外功能中。交易处理器 - 使用交易票据,这很不方便 - MT4和MT5中对票据的参考是不同的。这就是为什么有一个共同的类COrderInfoCore--订单接口的后裔。把这个对象的一个指针传给处理器会更方便。因此,这种方式使我们绕过了依赖平台的片段。

 
George Merts:

好吧,比方说,这里是我的函数发送请求,将TP-SL改为贸易处理器。

首先,EA部分对象--形成交易行动请求(这里,一个这样的请求是改变TP-SL)。然后ProceedRequestInto()函数被调用,用于所有向交易处理器发送交易行动信息的请求。

对我来说,这似乎太复杂了,无法理解那里究竟发生了什么。而如果你不了解里面的情况,你就不太可能使用它......为MT5编写一个单独的版本,必要时将其连接起来,不是更容易吗?
 
George Merts:
我的代码在MT4和MT5上运行完全没有变化。

为什么在不同的终端运行?

 
Andrei:
我认为这太复杂了,无法理解里面到底发生了什么......而且,如果不了解它的工作原理,我认为没有人会使用它......。为MT5编写一个单独的版本,并在需要时将其插入,这不是更容易吗?
为什么我需要 "了解里面真正的东西"?有一个固定的界面,可以执行一个动作,不管是在什么平台上--这就是我们使用的东西。而那里的东西,在低水平上--它有什么区别呢?
 

George Merts:

但是,在我看来,OOP的方法更加方便和清晰。 最重要的是--它允许实体之间相互隔离,并摆脱大量的全局变量。

这就是问题的关键,如果把所有的东西都隔离开来,处理这样的代码就会更加困难,更不用说当你需要知道所有需要的变量的当前值时,不可能对代码进行充分的调试......

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

为什么在不同的终端运行?

因为我的主账户是在MT4上开的,而我的策略测试器 在MT5上要好很多。

这是自由职业者客户的一个共同要求--"它必须在MT4和MT5上运行"--这意味着这是有原因的。我自己看不出在自由职业者工作的理由,但你可以问问那些在那里工作的人,为什么客户要求跨平台。

 
George Merts:
为什么我们需要 "了解里面实际在做什么"?有一个固定的界面,执行一个动作,不管是什么平台--这就是我们所使用的。而那里的东西,在低水平上--它有什么区别呢?
这不是关于低级别的问题,而是关于在每个可能的时间点上,什么东西流向哪里,进入什么的逻辑,包括知道所有的内部变量......如果不理解所有这些多余的逻辑,对一个非作者使用这个代码的意义就完全消失了......
原因: