下载MetaTrader 5

使用面向对象的方法来编写EA的模式

19 八月 2015, 14:06
Dennis Kirichenko
0
1 587

简介

本文中我们将讨论MQL5EA能够运行的编程模式。本文的目标是阐释“每种模式都以其自有的方式实现”的想法。作者相信此方法能够让EA不同阶段的开发工作更具效率。

首先,我们要考虑一个EA的开发由哪些阶段组成。然后,探讨MetaTrader 5中EA的运行模式及其辅助应用。最后,以实现上述想法的各层次类的实现结束本文。


1. 开发步骤

开发一个自动交易系统(EA)是一件涉及多方面的工作。关键部分是算法的实现和测试。需要注意的是,EA的交易逻辑和算法代码都需严格测试。

实现步骤如下(图1)。

图1. 开发步骤及EA的实现

图1. 开发步骤及EA的实现

第五阶段的“算法交易”阶段需要开发者,程序员,分析师和其他专业人员的介入。只有当所有这些工作都由一个人完成时才可能实现。让我们假设这是一个程序化交易者。

这个方案能够得到更新和扩展。在我看来,这是在EA开发中最为重要的地方。这种循环模式能够让EA在整个开发周期中得到改进和修正。

在开发的每个阶段都需要特定的工具,知识和技能。

在我看来,开发者会遇到如下简单的变量矩阵(图2)。

图2. 变量矩阵

图2. 变量矩阵

很清楚,只有以高的代码质量实现的盈利策略才能称之为第五阶段的“算法交易”。


2. MQL5中的EA模式

MQL5环境下,EA能够运行于不同的模式。共有7种模式。下面我们逐一分析。

以程序文件类型来分,有大两类:

  1. 需要源文件和可执行文件的模式;
  2. 和仅需要可执行文件的模式。

调试和分析模式属于第一类。

另一种区分模式的方法是看EA运行于真实数据上还是历史数据上。所有的测试模式都使用历史数据。

有6种模式由编程定义。可以根据结果来确定EA是否运行于标准(发布)模式。一个成型的可用于市场交易的EA程序(*.ex5后缀文件)应该在此模式下运行。同时,程序也允许在策略测试器中使用其他模式。

让我们来创建一个MQL程序的执行模式枚举值ENUM_MQL_MODE

//+------------------------------------------------------------------+
//| MQL 模式                                                          |
//+------------------------------------------------------------------+
enum ENUM_MQL_MODE
  {
   MQL_MODE_RELEASE=0,       // 发布
   MQL_MODE_DEBUG=1,         // 调试
   MQL_MODE_PROFILER=2,      // 分析 
   MQL_MODE_TESTER=3,        // 测试
   MQL_MODE_OPTIMIZATION=4,  // 优化
   MQL_MODE_VISUAL=5,        // 可视化测试 
   MQL_MODE_FRAME=6,         // 时间框架集结
  };

后面将用这些值来判断EA当前的运行模式。


2.1. 确定和检验模式的函数

写一个简单的函数来检测所有模式并在日志中打印信息。

//+------------------------------------------------------------------+
//| 检验所有MQL程序模式                                                |
//+------------------------------------------------------------------+
void CheckMqlModes(void)
  {
//--- 如果是调试模式
   if(MQLInfoInteger(MQL_DEBUG))
      Print("Debug mode: yes");
   else
      Print("Debug mode: no");
//--- 如果是分析模式
   if(MQLInfoInteger(MQL_PROFILER))
      Print("Profile mode: yes");
   else
      Print("Profile mode: no");
//--- 如果是测试模式
   if(MQLInfoInteger(MQL_TESTER))
      Print("Tester mode: yes");
   else
      Print("Tester mode: no");
//--- 如果是优化模式
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      Print("Optimization mode: yes");
   else
      Print("Optimization mode: no");
//--- 如果是可视化测试模式
   if(MQLInfoInteger(MQL_VISUAL_MODE))
      Print("Visual mode: yes");
   else
      Print("Visual mode: no");
//--- 如果是时间框架聚集的优化结果模式
   if(MQLInfoInteger(MQL_FRAME_MODE))
      Print("Frame mode: yes");
   else
      Print("Frame mode: no");
  }


我们将检查函数中的每个模式。它可以在OnInit()事件句柄中调用。

为了测试,我们创建一个EA模板Test1_Modes_EA.mq5

在输入参数中有确定EA将要运行在何种模式下的选项。确保模式被正确的命名非常重要,否则信息将不正确。就像这样。

下面是发布模式。

CL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_RELEASE
QD      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
KM      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
EK      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CS      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
RJ      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no


对于发布模式,其他所有模式的标识为0。因此,函数确定这既不是调试模式(Debug mode:no),也不是分析模式(Profile mode:no)等等。由此我们得出结论,当前是在发布模式下运行。

现在我们来看看是如何确定调试模式的。

HG      0       17:27:47.709    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_DEBUG
LD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: yes
RS      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
HE      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
NJ      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
KD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
RR      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no


调试模式被正确识别。

在任何编程手册中都会提到在调式模式下便于查找和定位错误。它还强调了程序的特殊性。在MQL5环境下调试程序的更多细节可参见“调试MQL5程序”一文。

此模式最常用于交易策略的形成和算法构建阶段。

在程序中,调试模式可以通过IS_DEBUG_MODE宏或者MQLInfoInteger()函数的MQL_DEBUG标识来设置。

接下来我们来考察分析模式。

GS      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_PROFILER
OR      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
GE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: yes
QM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
FM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GJ      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no


函数正确识别出当前为分析模式。

在此模式下能够检测程序的运行速度。分析模式能够将时间开销信息传给程序段。此功能能检测出算法的瓶颈。虽然往往可能无法消除瓶颈,但至少这些信息是非常有用的。

分析模式可以通过IS_PROFILE_MODE宏或者 MQLInfoInteger()函数的MQL_PROFILER标识符来设置。

现在让我们来看看测试模式。策略测试器的信息将在“日志”标签页下显示。

EG      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Current mode: MQL_MODE_TESTER
OS      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Debug mode: no
GJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Profile mode: no
ER      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Tester mode: yes
ED      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Optimization mode: no
NL      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Visual mode: no
EJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Frame mode: no


测试模式被正确识别。

当策略测试器开启后,这是EA的默认模式。

没有宏对应此模式,在MQL5中我们只能通过MQLInfoInteger()函数的MQL_TESTER标识符来设置。

现在我们来看看优化模式。日志将保存在测试器的文件夹内。在我的情况下,保存目录为: %Program Files\MetaTrader5\tester\Agent-127.0.0.1-3000\logs

OH      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_OPTIMIZATION
KJ      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
NO      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
FI      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
KE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
LS      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
QE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no


如果优化模式激活了,测试模式默认开启。

如果“优化”字段在“设置”标签中未被禁止,那么优化模式在策略测试器中被开启。

要确认MQL5中EA是否在优化模式下进行测试,使用MQL_OPTIMIZATION 标识符调用MQLInfoInteger()函数。

再来看可视化模式。

JQ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_VISUAL
JK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
KF      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
CP      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
HJ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: no
LK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: yes
KS      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no


这里我们可以看到可视化模式和标准测试模式开启了。

如果策略测试器“设置”页下的“可视化”字段选中,EA将在此模式下运行。

MQL5程序要运行在可视化测试模式下,可以通过MQLInfoInteger()函数的MQL_VISUAL_MODE 标识符来设置。

最后一个模式是时间框架控制模式。

HI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_FRAME
GR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
JR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
JG      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
GM      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
HR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
MI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no


有意思的是,函数仅仅识别出测试和优化模式,时间框架集聚模式的标识为0。如果通过OnTesterInit()句柄来调用函数,那么“智能交易”日志将包含以下内容:

IO      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_FRAME
GE      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
ML      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
CJ      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
QR      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
PL      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GS      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: yes


现在仅检测到时间框架集聚模式。

如果“设置”页中的“优化”字段未被禁用的话,策略测试器将启动此模式。经验显示,此模式在OnTesterInit()OnTesterPass()OnTesterDeinit() 函数内定义。

MQLInfoInteger() 函数配合MQL_FRAME_MODE标识符,能够方便的定义EA在时间框架聚集模式下进行测试。

下面是能够自动确定EA在何种模式下运行的函数MqlMode()

//+------------------------------------------------------------------+
//| 确定当前MQL模式                                                    |
//+------------------------------------------------------------------+
ENUM_MQL_MODE MqlMode(void)
  {
   ENUM_MQL_MODE curr_mode=WRONG_VALUE;

//--- 如果是调试模式
   if(MQLInfoInteger(MQL_DEBUG))
      curr_mode=MQL_MODE_DEBUG;
//--- 如果是分析模式
   else if(MQLInfoInteger(MQL_PROFILER))
      curr_mode=MQL_MODE_PROFILER;
//--- 如果是可视化测试模式
   else if(MQLInfoInteger(MQL_VISUAL_MODE))
      curr_mode=MQL_MODE_VISUAL;
//--- 如果是优化模式
   else if(MQLInfoInteger(MQL_OPTIMIZATION))
      curr_mode=MQL_MODE_OPTIMIZATION;
//--- 如果是测试模式
   else if(MQLInfoInteger(MQL_TESTER))
      curr_mode=MQL_MODE_TESTER;
//--- 如果是时间框架聚集的优化结果模式
   else if(MQLInfoInteger(MQL_FRAME_MODE))
      curr_mode=MQL_MODE_FRAME;
//--- 如果是发布模式
   else
      curr_mode=MQL_MODE_RELEASE;
//---
   return curr_mode;
  }

由于标准测试模式被优化和可视化测试模式定义,那么标准测试模式将在优化和可视化模式后再检测。

如果看下第二个模板EATest2_Modes_EA.mq5中的函数的运作方式,我们可以看到当模板加载时有一行新的日志出现。例如,分析模式下有如下日志:

HG      0       11:23:52.992    Test2_Modes_EA (EURUSD.e,H1)    Current mode: MQL_MODE_PROFILER

我们讨论一下MQL5 EA模式的细节,以便创建特定类的模型。我们将在本文的另一部分实现之。


3. 设计用于不同模式的EA模板

我建议再来审视一遍EA的开发步骤。

在算法阶段,程序开发者经常要调试和分析代码。在历史数据回测阶段,他们会尝试所有的策略测试器模式。最终模式(发布模式)用于在线交易。

在我看来,EA必须是包含多种模式的,因为开发和测试阶段的需求必须反映在代码中。

这样主要的算法逻辑将被保持,EA在不同的模式下也将会有不同的表现。面向对象的编程工具非常合适实现这个想法。

图2.用于设计在不同模式下运行EA的类的层次结构

图 3. 用于设计在不同模式下运行EA的类的层次结构

图3表示实现不同模式的类的层次结构。

基础类CModeBase封装了所有常用对象,它有2个子类:CModeReleaseCModeTester 类。第一个是调试类的父类,第二个是用于EA进行历史数据回测的类。

在分模式的背景下开发类方法时,让我们用过程和模块化组合来完成开发构想。作为例子,让我们考虑下面的交易逻辑:

  1. 如果没有持仓,根据信号开仓。
  2. 如果有未平仓订单,根据信号平仓。
  3. 如果有未平仓订单,开启滑动止损。

当新的柱形到来时,交易信号由标准指标MACD发出。

买入信号出现在MACD的主线在负值区域从下往上穿越信号线(图4)。

图4 买入信号

图4. 买入信号

卖出信号出现在MACD的主线在正值区域从上往下穿越信号线(图5)。

图5 卖出信号

图5. 卖出信号

当出现反向信号或者止损时平仓。

CModeBase类的定义如下:

//+------------------------------------------------------------------+
//| CModeBase 类                                                     |
//| 目的: MQL-模式基类                                                |            
//+------------------------------------------------------------------+
class CModeBase
  {
//--- === 数据成员 === --- 
private:
   //--- macd对象
   CiMACD            m_macd_obj;
   double            m_macd_main_vals[2];
   double            m_macd_sig_vals[2];

protected:
   long              m_pos_id;
   bool              m_is_new_bar;
   uint              m_trailing_stop;
   uint              m_trail_step;
   //--- 交易对象
   CSymbolInfo       m_symbol_info;
   CTrade            m_trade;
   CPositionInfo     m_pos_info;
   CDealInfo         m_deal_info;
   //--- mql 模式
   ENUM_MQL_MODE     m_mql_mode;

   //--- 新柱形对象
   CisNewBar         m_new_bar;
   //--- 当前tick标识
   bool              m_is_curr_tick_signal;
   //--- 平仓订单类型
   ENUM_ORDER_TYPE   m_close_ord_type;
   
//--- === 方法 === --- 
public:
   //--- 构造函数/析构函数
   void              CModeBase();
   void             ~CModeBase(void){};
   //--- 初始化
   virtual bool      Init(int _fast_ema,int slow_ema,int _sig,ENUM_APPLIED_PRICE _app_price);
   virtual void      Deinit(void){};

   //--- 模块
   virtual void      Main(void){};

   //--- 程序
   virtual void      Open(void){};
   virtual void      Close(void){};
   virtual void      Trail(void){};

   //--- 服务
   static ENUM_MQL_MODE CheckMqlMode(void);
   ENUM_MQL_MODE     GetMqlMode(void);
   void              SetMqlMode(const ENUM_MQL_MODE _mode);
   void              SetTrailing(const uint _trailing,const uint _trail_step);

protected:
   //--- 函数
   ENUM_ORDER_TYPE   CheckOpenSignal(const ENUM_ORDER_TYPE _open_sig);
   ENUM_ORDER_TYPE   CheckCloseSignal(const ENUM_ORDER_TYPE _close_sig);
   ENUM_ORDER_TYPE   CheckTrailSignal(const ENUM_ORDER_TYPE _trail_sig,double &_sl_pr);
   //---
   double            GetMacdVal(const int _idx,const bool _is_main=true);

private:
   //--- 宏
   bool              RefreshIndicatorData(void);
   //--- 标准化
   double            NormalPrice(double d);
   double            NormalDbl(double d,int n=-1);
   double            NormalSL(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint SL,double stop);
   double            NormalTP(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint _TP,double stop);
   double            NormalLot(const double _lot);
  };


任何只要在继承类中要使用的,都可以在基础类中引入。

MACD指标数据将不能被后续类使用,因为他们是私有变量。

必须注意到在这些方法中的 Main(), Open(), Close(), Trail()虚拟方法。他们的实现取决于EA当前的运行模式。在基类中这些方法的方法体将为空。

此外,基本类包括了对所有MQL模式相同的交易逻辑方法。包含所有的信号方法:

  • CModeBase::CheckOpenSignal(),
  • CModeBase::CheckCloseSignal(),
  • CModeBase::CheckTrailSignal().

本文的目的不是为了提供所有MQL模式类型的代码。用标准和可视化测试模式作例子。


3.1. 测试模式

当算法代码完成并通过编译后,我通常用策略测试器在历史数据上检验运行效果。

往往需要检查系统对交易信号的执行准确性。不管怎样,在这个阶段EA的基本目标是要能够正确运行并交易。

用于常规测试的CModeTester类的实现如下:

//+------------------------------------------------------------------+
//| CModeTester 类                                                   |
//| 目的:用于测试模式的类                                              |            
//| 继承于CModeBase类                                                 |
//+------------------------------------------------------------------+
class CModeTester : public CModeBase
  {
//--- === 方法 === --- 
public:
   //--- 构造函数/析构函数
   void              CModeTester(void){};
   void             ~CModeTester(void){};

   //--- 模块
   virtual void      Main(void);

   //--- 程序
   virtual void      Open(void);
   virtual void      Close(void);
   virtual void      Trail(void);
  };


主模块实现如下:

//+------------------------------------------------------------------+
//| 主模块                                                            |
//+------------------------------------------------------------------+
void CModeTester::Main(void)
  {
//--- 1) 平仓
   this.Close();
//--- 2) 开仓
   this.Open();
//--- 3) 滑动止损
   this.Trail();
  }


对于常规测试模式,在日志中将交易信号产生的信息打印出来。

将作为交易信号来源的指标值以字符串形式打印出来。

下面是从日志中摘取的一个开仓信号和随后的平仓信号。

HE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   ---=== Signal to open: SELL===---
FI      0       13:34:04.118    Core 1  2014.11.14 22:15:00   A bar before the last one, main: 0.002117; signal: 0.002109
DL      0       13:34:04.118    Core 1  2014.11.14 22:15:00   The last bar, main: 0.002001; signal: 0.002118
LO      0       13:34:04.118    Core 1  2014.11.14 22:15:00   market sell 0.03 EURUSD.e (1.25242 / 1.25251 / 1.25242)
KH      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal #660 sell 0.03 EURUSD.e at 1.25242 done (based on order #660)
GE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal performed [#660 sell 0.03 EURUSD.e at 1.25242]
OD      0       13:34:04.118    Core 1  2014.11.14 22:15:00   order performed sell 0.03 at 1.25242 [#660 sell 0.03 EURUSD.e at 1.25242]
IK      0       13:34:04.118    Core 1  2014.11.14 22:15:00   CTrade::OrderSend: market sell 0.03 EURUSD.e [done at 1.25242]
IL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   
CJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   ---=== Signal to close: SELL===---
GN      0       13:34:04.118    Core 1  2014.11.17 13:30:20   A bar before the last one, main: -0.001218; signal: -0.001148
QL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   The last bar, main: -0.001123; signal: -0.001189
EP      0       13:34:04.118    Core 1  2014.11.17 13:30:20   market buy 0.03 EURUSD.e (1.25039 / 1.25047 / 1.25039)
FG      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal #661 buy 0.03 EURUSD.e at 1.25047 done (based on order #661)
OJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal performed [#661 buy 0.03 EURUSD.e at 1.25047]
PD      0       13:34:04.118    Core 1  2014.11.17 13:30:20   order performed buy 0.03 at 1.25047 [#661 buy 0.03 EURUSD.e at 1.25047]
HE      0       13:34:04.118    Core 1  2014.11.17 13:30:20   CTrade::OrderSend: market buy 0.03 EURUSD.e [done at 1.25047]

请注意,策略测试器的日志不在“智能交易”标签页中。所有的信息都能在“日志”标签页找到,包含了策略测试器在测试及优化阶段所有的运行记录。

这也是为什么要通过搜索来找到想查看的字符串信息。如果想要分离相关信息,可以将其记录在一个文件中。

标准测试策略在TestMode_tester.mq5 EA中实现。


3.2. 可视化测试模式

有时想要通过实时图表来观察EA是如果处理当前行情的。

可视化测试不仅能够顾观察交易系统对报价是如何反应的,并且能够在测试结束时比较相似的价格模型。

可视化测试CModeVisual类定义如下:

//+------------------------------------------------------------------+
//| CModeVisual类                                                    |
//| 目的:用于测试模式的类                                              |            
//| 继承于CModeBase                                                   |
//+------------------------------------------------------------------+
class CModeVisual : public CModeTester
  {
//--- === 数据成员 === --- 
private:
   CArrayObj         m_objects_arr;
   double            m_subwindow_max;
   double            m_subwindow_min;
   
//--- === 方法 === --- 
public:
   //--- 构造函数/析构函数
   void              CModeVisual(void);
   void             ~CModeVisual(void);

   //--- 程序
   virtual void      Open(void);
   virtual void      Close(void);

private:
   bool              CreateSignalLine(const bool _is_open_sig,const bool _is_new_bar=true);
   bool              CreateRectangle(const ENUM_ORDER_TYPE _signal);
   void              RefreshRectangles(void);
  };


本类含有私有成员。m_objects_arr类的成员有一个CArrayObj类型的动态数组。图形对象,例如线和长方形属于此。另外两个类的成员(m_subwindow_max, m_subwindow_min)控制指标窗口的最大化和最小化。

图形对象通过私有方法来控制。

这个类中不包含Main()Trail()方法。他们的父函数CModeTester::Main()CModeTester::Trail()将被分别调用。

图形对象可以在可视化测试模式下创建。不能在策略测试器的其他模式下实现。

当入场信号出现时在图表上绘制红色垂直线,当出场信号出现时绘制蓝色垂直线。在指标窗口中,用相应颜色的矩形填充入场和出场点之间的区域。

如果是多单,矩形为浅蓝色。如果是空单,矩形为粉色(图6)。

图6. 可视化测试模式下的图形对象

图6. 可视化测试模式下的图形对象

矩形的高度取决于其创建时图表子窗口的最大和最小值。如果图表子窗口的大小改变,那么需要添加改变矩形坐标的代码,以便将所有矩形设置为一样的尺寸。

因此在MACD指标子窗口我们有如下区域:未标颜色的(没有持仓),粉色的(空单),浅蓝色(多单)。

常规测试模式在TestMode_visual_tester.mq5 EA中实现。


总结

在本文中我试图介绍MetaTrader 5和MQL5语言创建不同模式程序的能力。不得不提的是,虽然创建多模式程序编写交易算法会增加开销,但也是一次逐步了解每一个开发阶段的良机。在这种情况下面向对象的编程是开发者的好帮手。

优化和时间框架聚集模式将在后续关于交易系统的统计特性的文章中介绍。


本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/1246

附加的文件 |
CisNewBar.mqh (6.99 KB)
Modes.mqh (31.24 KB)
Test1_Modes_EA.mq5 (4.75 KB)
Test2_Modes_EA.mq5 (5.04 KB)
MQL5 秘籍之:OCO订单 MQL5 秘籍之:OCO订单

任何交易者的交易活动都会包含各种交易机制和内在联系,包括订单之间的关系。本文提出一种处理OCO订单的解决方案。将广泛采用标准类库来实现,同时也会新建一些数据类型。

在市场中购买商品的技巧。循序渐进的操作手册 在市场中购买商品的技巧。循序渐进的操作手册

本手册提供一些技巧和窍门,帮助你更好的理解和寻找满足需求的商品。本文将探讨一些不同的方法来寻找合适的产品,滤除不需要的,找到高效以及适合你的产品。

使用MQL4和MQL5绘制基于分形指标的趋势线 使用MQL4和MQL5绘制基于分形指标的趋势线

本文介绍一种使用MQL4和MQL5语言,自动绘制基于分形指标趋势线的方法。本文以比较的视角,提供两种语言的解决方案。使用最近的两个分形来绘制趋势线。

研究CCanvas类如何绘制透明的图形对象 研究CCanvas类如何绘制透明的图形对象

你是不是想要更加好看的移动平均线?你想要在终端中绘制更加漂亮的而不是简单的实心矩形吗?终端中能够绘制出更有吸引力的图形。这可以通过CCanvas类来实现,该类用于创建自定义图形对象。用这个类你能够实现透明化,混合色以及通过重叠和混合颜色产生透明的效果。