MetaTrader 5 提供了一款强大的工具用于快速检验交易理念。这就是 MQL5 向导的交易策略生成器。使用 MQL5 向导自动创建 EA 交易源代码的做法已在《MQL5 向导:无需编程即可创建 EA 交易》一文中进行了介绍。由于代码生成系统的开放性,您能够使用交易信号、资金管理系统和追踪模块的自定义类来补充标准类。
本文介绍了追踪未平仓位模块的编写原则,以便在 MQL5 向导中能够进一步使用。
通过 MQL5 向导创建的 EA 交易基于四个基类:
图 1. CExpert 基类的结构。
CExpert 类(或其子类)是交易机器人的主要“引擎”。CExpert 类的实例包含 CExpertSignal、CExpertMoney 和 CExpertTrailing 类(或其子类)的实例:
此外,下述类实例是 CExpert 类的成员:
在下文中,当提及 EA 交易时,我们指的是 CExpert 类或其子类的实例。
有关 CExpert 类及其使用过程的更详细介绍将在另一章节中提供。
1. CExpertTrailing 基类
CExpertTrailing 构成了追踪未平仓位模块的基础。CExpertTrailing 类具有一组公共虚拟方法,以便和外界进行交互。
初始化 |
说明 |
虚拟 Init |
类实例的初始化可实现模块数据和 EA 交易数据的同步 |
虚拟 ValidationSettings |
参数设定验证 |
虚拟 InitIndicators |
创建并初始化操作交易信号生成器所需的所有指标和时间序列 |
仓位修改信号 |
|
虚拟 CheckTrailingStopLong |
生成买入持仓修改信号,同时确定止损订单的新价格 |
虚拟 CheckTrailingStopShort |
生成卖出持仓修改信号,同时确定止损订单的新价格 |
1.1. 初始化方法
1.1.1 Init
Init() 方法在类实例添加至 EA 交易后立即被自动调用。无需覆盖该方法。
virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);
1.1.2 ValidationSettings
ValidationSettings() 方法在设置所有参数后从 EA 交易调用。如果存在设置参数,则必须覆盖该方法。
virtual bool ValidationSettings();
如果所有参数都正确无误(表明其适合使用),则覆盖方法必须返回 true。如果存在任何无效参数(无法进一步操作),则该参数必须返回 false。
1.1.3 InitIndicators
InitIndicators() 方法用于创建和初始化所需的全部指标和时间序列。在设置和验证完所有参数后,该方法会从 EA 交易中调用。如果交易信号生成器使用了至少一个指标或时间序列,则应覆盖该方法。
virtual bool InitIndicators(CIndicators* indicators);
指标和/或时间序列应通过标准库中的对应物予以使用。所有指标和/或时间序列的指针都应添加至 EA 交易的指标集(指向其的指针作为参数传递)。
如果对指标和/或时间序列的所有操作均已成功(表明其适合使用),则覆盖方法应返回 true。如果对指标和/或时间序列的操作至少有一次失败,则该方法必须返回 false(无法进一步操作)。
1.2. 检查仓位修改信号的方法
1.2.1 CheckTrailingStopLong
CheckTrailingStopLong() 方法会生成买入持仓修改信号,同时定义止损订单(必要时定义获利订单)的新价格。该方法通过 EA 交易调用,以确定是否有必要修改买入持仓。如果您希望生成买入持仓修改信号,则应覆盖该方法。
virtual bool CheckTrailingStopLong(CPositionInfo* position,double& sl,double& tp)
该方法必须实现检查买入持仓修改条件的算法。如果满足条件,则必须为变量 sl(必要时为 tp)赋予相应的值,且该方法应返回 true。连接至 sl 和 tp 变量的链接必须作为参数传递。如果不满足条件,则该方法必须返回 false。
1.2.2 CheckTrailingStopShort
CheckTrailingStopShort() 方法可生成卖出持仓修改信号,同时确定止损订单(必要时定义获利订单)的新价格。该方法通过 EA 交易调用,以确定是否有必要修改卖出持仓。如果您希望生成卖出持仓修改信号,则应覆盖该方法。
virtual bool CheckTrailingStopShort(CPositionInfo* position,double& sl,double& tp)
该方法必须实现检查卖出持仓修改条件的算法。如果满足条件,则必须为变量 sl(必要时为 tp)赋予相应的值,且该方法应返回 true。连接至 sl 和 tp 变量的链接必须作为参数传递。如果不满足条件,则该方法必须返回 false。
在了解 CExpertTrailing 基类的结构后,现在您就可着手创建自己的未平仓位追踪模块了!
如上所述,CExpertTrailing 类是一套公共虚拟方法,EA 交易通过其了解未平仓位追踪模块在保护订单修改必要性方面的“意见”。
因此,我们的主要目标是创建自己的未平仓位追踪类,使其派生于 CExpertTrailing 类并覆盖相应的虚拟方法,同时实现所需算法。
我们的次要目标(具有同等重要性)是让我们的类对于 MQL5 向导呈“可视”状态。先说最重要的吧。
2.1. 创建交易信号生成器类
我们开始吧。
首先创建(例如,使用同一 MQL5 向导)一个扩展名为 mqh 的包含文件。
在 File(文件)菜单中选择 Create(创建)(或按 Ctrl+N 组合键),并指明创建一个包含文件:
图 2. 使用 MQL5 向导创建一个包含文件。
应该注意的是,为了方便 MQL5 向导以后将文件识别为未平仓位追踪模块,应在文件夹 Include\Expert 中创建该文件。。
为了避免与标准库发生冲突,应创建自己的文件夹 Include\Expert\Trailing\MyTrailing,并在其中创建文件 SampleTrailing.mqh,同时在 MQL5 向导中指定这些参数:
图 3. 设置包含文件的位置。
MQL5 向导的运行结果显示如下情形:
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| defines | //+------------------------------------------------------------------+ // #define MacrosHello "Hello, world!" // #define MacrosYear 2010 //+------------------------------------------------------------------+ //| DLL imports | //+------------------------------------------------------------------+ // #import "user32.dll" // int SendMessageA(int hWnd,int Msg,int wParam,int lParam); // #import "my_expert.dll" // int ExpertRecalculate(int wParam,int lParam); // #import //+------------------------------------------------------------------+ //| EX5 imports | //+------------------------------------------------------------------+ // #import "stdlib.ex5" // string ErrorDescription(int error_code); // #import //+------------------------------------------------------------------+
接下来完全是“手工”操作。删除不必要部分,并加入所需部分(即标准库的包含文件 ExpertTrailing.mqh 和目前为空的类说明)。
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| include files | //+------------------------------------------------------------------+ #include <Expert\ExpertTrailing.mqh> //+------------------------------------------------------------------+ //| Class CSampleTrailing. | //| Purpose: Class for trailing of open positions. | //| Is derived from the CExpertTrailing class. | //+------------------------------------------------------------------+ class CSampleTrailing : public CExpertTrailing { }; //+------------------------------------------------------------------+
现在有必要选择算法了。
我们将下述算法作为未平仓位追踪模块的基础:如果价格沿期望的方向移动一段特定距离,则将止损订单移入无损水平。这反映在我们的文件中。
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| include files | //+------------------------------------------------------------------+ #include <Expert\ExpertTrailing.mqh> //+------------------------------------------------------------------+ //| Class CSampleTrailing. | //| Purpose: Class for trailing of open positions by | //| moving the Stop order "to the loseless level". | //| Is derived from the CExpertTrailingclass. | //+------------------------------------------------------------------+ class CSampleTrailing : public CExpertTrailing { }; //+------------------------------------------------------------------+
现在,我们来详细说明确定保护订单的修改需要用到哪些数据。在本例中 - 这些数据是修改仓位的获利点位。
定义设置未平仓位追踪模块的参数列表。我们需要两个参数:
模块的设置将存储在该类的受保护数据成员中。将通过相应的公共方法实现对设置的访问。
让我们将这些更改包含在文件中:
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| include files | //+------------------------------------------------------------------+ #include <Expert\ExpertTrailing.mqh> //+------------------------------------------------------------------+ //| Class CSampleTrailing. | //| Purpose: Class for trailing of open positions | //| by moving Stop order to a lossless level. | //| Is derived from the CExpertTrailing class. | //+------------------------------------------------------------------+ class CSampleTrailing : public CExpertTrailing { protected: int m_profit; //threshold level of profit int m_stop_level; // lossless level public: //--- methods of setting adjustable parameters void Profit(int value) { m_profit=value; } void StopLevel(int value) { m_stop_level=value; } }; //+------------------------------------------------------------------+
要使用默认值初始化可调节参数,我们需要添加类构造函数。
要验证设置,可根据基类说明来覆盖虚拟方法 ValidationSettings。
类的说明:
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| include files | //+------------------------------------------------------------------+ #include <Expert\ExpertTrailing.mqh> //+------------------------------------------------------------------+ //| Class CSampleTrailing. | //| Purpose: Class for trailing of open positions | //| by moving Stop order to a lossless level. | //| Is derived from the CExpertTrailing class. | //+------------------------------------------------------------------+ class CSampleTrailing : public CExpertTrailing { protected: int m_profit; // threshold level of profit int m_stop_level; // lossless level public: CSampleTrailing(); //--- methods of setting adjustable parameters void Profit(int value) { m_profit=value; } void StopLevel(int value) { m_stop_level=value; } //--- method of validating the adjustable parameters virtual bool ValidationSettings(); }; //+------------------------------------------------------------------+
ValidationSettings() 方法的实现:
//+------------------------------------------------------------------+ //| Validation of adjustable parameters. | //| INPUT: no. | //| OUTPUT: true if parameter are correct, false - if not. | //| REMARK: no. | //+------------------------------------------------------------------+ bool CSampleTrailing::ValidationSettings() { if(!CExpertTrailing::ValidationSettings()) return(false); //--- check wheter the Init method is called if(m_symbol==NULL) return(false); //--- check parameters if((m_profit-m_stop_level)*m_adjusted_point<=m_symbol.StopsLevel()*m_symbol.Point() && m_profit!=0.0) { printf(__FUNCTION__+": threshold level of profit must be greater than the level of setting of orders"); return(false); } //--- ok return(true); }
所有准备工作均已就绪。
让我们再仔细考虑下这些算法。
1. 满足下列条件时,会生成买入持仓修改信号:
在这种情况下,建议根据设置来修改止损订单。为此,我们覆盖了虚拟方法 CheckTrailingStopLong 并赋予其相应功能。
2. ,满足下列条件时,会生成卖出持仓修改信号:
在这种情况下,建议根据设置来修改止损订单。为此,我们覆盖了虚拟方法 CheckTrailingStopShort 并赋予其相应功能。
类的说明:
class CSampleTrailing : public CExpertTrailing { protected: int m_profit; // threshold level of profit int m_stop_level; // lossless level public: CSampleTrailing(); //--- methods of setting adjustable parameters void Profit(int value) { m_profit=value; } void StopLevel(int value) { m_stop_level=value; } //--- method of validation of adjustable parameters virtual bool ValidationSettings(); //--- methods of generation of position modification signals virtual bool CheckTrailingStopLong(CPositionInfo* position,double& sl,double& tp); virtual bool CheckTrailingStopShort(CPositionInfo* position,double& sl,double& tp); };
CheckTrailingStopLong 和 CheckTrailingStopShort 方法的实现:
//+------------------------------------------------------------------+ //| Check for modification of stop orders of a long position. | //| INPUT: position - pointer to a position object, | //| sl - link for a new price of stop loss order, | //| tp - link for a new price of take profit order. | //| OUTPUT: true if condition is satisfied, false - if not. | //| REMARK: no. | //+------------------------------------------------------------------+ bool CSampleTrailing::CheckTrailingStopLong(CPositionInfo* position,double& sl,double& tp) { //--- check of pointer if(position==NULL) return(false); //--- check of parameter if(m_profit==0.0) return(false); //--- already in a lossless zone? double open=position.PriceOpen(); if(position.StopLoss()>=open) return(false); //--- check of profit sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(m_symbol.Bid()-open>m_profit*m_adjusted_point) sl=m_symbol.NormalizePrice(open+m_stop_level*m_adjusted_point); //--- return(sl!=EMPTY_VALUE); } //+------------------------------------------------------------------+ //| Check for modification of stop orders of a short position. | //| INPUT: position - pointer to a position object, | //| sl - link to a new price of stop loss order, | //| tp - link to a new price of take profit order. | //| OUTPUT: true if condition is satisfied, false - if not. | //| REMARK: нет. | //+------------------------------------------------------------------+ bool CSampleTrailing::CheckTrailingStopShort(CPositionInfo* position,double& sl,double& tp) { //--- check of pointer if(position==NULL) return(false); //--- check of parameter if(m_profit==0.0) return(false); //--- already in a lossless zone? double open=position.PriceOpen(); if(position.StopLoss()<=open) return(false); //--- check of profit sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(open-m_symbol.Ask()>m_profit*m_adjusted_point) sl=m_symbol.NormalizePrice(open-m_stop_level*m_adjusted_point); //--- return(sl!=EMPTY_VALUE); }
2.2. 为 MQL5 向导编写所创建交易信号类的说明
我们现在开始解决第二个问题。我们的未平仓位追踪模块应能被 MQL5 向导的交易策略生成器所识别。
我们已完成了第一个必要条件:我们将文件放置在 MQL5 向导能够找到的位置。但这还不够。MQL5 向导不仅要能找到文件,还要能识别它。为此,我们必须根据 MQL5 向导的要求将类描述符添加至原始文本。
我们来看一下这些规则:
1. 注释块应以下面的代码行开头:
// wizard description start //+------------------------------------------------------------------+ //| Description of the class |
2. 下一行是一个文本描述符(我们会在 MQL5 向导中选择信号时见到),格式为 "//| Title=<Text> |"。如果代码文本过多而无法显示在一行,您可以在后面再添加一行代码(但不能超过此数)。</p>
在本例中,即下述代码行:
//| Title=Signal on the crossing of a price and the MA | //| entering on its back movement |
3. 接下来是以格式 "//| Type=<Type> |" 指定类的类型的代码行。<Type> 字段必须具有信号值(除了信号,MQL5 向导也能识别其他类的类型)。
输入:
//| Type=Trailing |
4. 接下来一行呈 "//| Name=<Name> |" 格式的代码是信号的简称(MQL5 向导用其来生成 EA 交易全局变量的名称)。
我们得到下列内容:
//| Name=BreakEven |
5. 类的名称是说明中的一个重要要素。在呈 "//| Class=<ClassNameа> |" 格式的代码行中,<ClassName> 参数必须与类的名称相匹配:
//| Class=CSampleTrailing |
6. 我们不会在此行填入任何内容,但该行必须存在(这是到语言参考部分的链接):
//| Page= |
7. 此外还有关于模块设置参数的说明。
这是一组代码行(行数等于参数的个数)。
每一行的格式均为 "//| Parameter=<NameOfMethod>,<TypeOfParameter>,<DefaultValue> |"。
下面是我们的参数集:
//| Parameter=Profit,int,20 | //| Parameter=StopLevel,int,0 |
8. 注释块应以下面的代码行结束:
//+------------------------------------------------------------------+ // wizard description end
让我们将描述符添加到源代码。
//+------------------------------------------------------------------+ //| SampleTrailing.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" //+------------------------------------------------------------------+ //| include files | //+------------------------------------------------------------------+ #include <Expert\ExpertTrailing.mqh> // wizard description start //+------------------------------------------------------------------+ //| Description of the class | //| Title=Moving a position to a lossless level | //| Type=Trailing | //| Name=BreakEven | //| Class=CSampleTrailing | //| Page= | //| Parameter=Profit,int,20 | //| Parameter=StopLevel,int,0 | //+------------------------------------------------------------------+ // wizard description end //+------------------------------------------------------------------+ //| Class CSampleTrailing. | //| Purpose: Class for trailing of open positions | //| by moving Stop order to a lossless level. | //| Is derived from the CExpertTrailing class. | //+------------------------------------------------------------------+ class CSampleTrailing : public CExpertTrailing { protected: int m_profit; // threshold level of profit int m_stop_level; // lossless level public: CSampleTrailing(); //--- method of setting adjustable parameters void Profit(int value) { m_profit=value; } void StopLevel(int value) { m_stop_level=value; } //--- method of validation of adjustable settings virtual bool ValidationSettings(); //--- methods of generation of position modification signals virtual bool CheckTrailingStopLong(CPositionInfo* position,double& sl,double& tp); virtual bool CheckTrailingStopShort(CPositionInfo* position,double& sl,double& tp); }; //+------------------------------------------------------------------+ //| Constructor CSampleTrailing. | //| INPUT: no. | //| OUTPUT: no. | //| REMARK: no. | //+------------------------------------------------------------------+ void CSampleTrailing::CSampleTrailing() { //--- setting default values m_profit =20; m_stop_level=0; } //+------------------------------------------------------------------+ //| Check of adjustable parameters. | //| INPUT: no. | //| OUTPUT: true if the parameters are correct, false if not. | //| REMARK: no. | //+------------------------------------------------------------------+ bool CSampleTrailing::ValidationSettings() { //--- what if the Init has not been called? if(m_symbol==NULL) return(false); //--- check of parameters if((m_profit-m_stop_level)*m_adjusted_point<=m_symbol.StopsLevel()*m_symbol.Point() && m_profit!=0.0) { printf(__FUNCTION__+": threshold level of profit must be greater than the level of setting stop orders"); return(false); } //--- ok return(true); } //+------------------------------------------------------------------+ //| Check for modification of stop orders of a long position. | //| INPUT: position - pointer to a position object, | //| sl - link for a new price of stop loss order, | //| tp - link for a new price of take profit order. | //| OUTPUT: true if condition is satisfied, false if not. | //| REMARK: no. | //+------------------------------------------------------------------+ bool CSampleTrailing::CheckTrailingStopLong(CPositionInfo* position,double& sl,double& tp) { //--- check of pointer if(position==NULL) return(false); //--- check of parameters if(m_profit==0.0) return(false); //--- already in a lossless zone? double open=position.PriceOpen(); if(position.StopLoss()>=open) return(false); //--- check of profit sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(m_symbol.Bid()-open>m_profit*m_adjusted_point) sl=m_symbol.NormalizePrice(open+m_stop_level*m_adjusted_point); //--- return(sl!=EMPTY_VALUE); } //+------------------------------------------------------------------+ //| Check for modification of stop orders of a short position. | //| INPUT: position - pointer to a position object, | //| sl - link for a new price of stop loss order, | //| tp - link for a new take profit order. | //| OUTPUT: true if condition is satisfied, false if not. | //| REMARK: no. | //+------------------------------------------------------------------+ bool CSampleTrailing::CheckTrailingStopShort(CPositionInfo* position,double& sl,double& tp) { //--- check of pointer if(position==NULL) return(false); //--- check of parameters if(m_profit==0.0) return(false); //--- already in a lossless zone? double open=position.PriceOpen(); if(position.StopLoss()<=open) return(false); //--- check of profit sl=EMPTY_VALUE; tp=EMPTY_VALUE; if(open-m_symbol.Ask()>m_profit*m_adjusted_point) sl=m_symbol.NormalizePrice(open-m_stop_level*m_adjusted_point); //--- return(sl!=EMPTY_VALUE); } //+------------------------------------------------------------------+
以上便是全部内容。追踪模块已经可以使用了。
为了让 MQL5 向导的交易策略生成器能够使用我们的模块,我们应重启 MetaEditor(MQL5 向导仅在启动时扫描文件夹 Include\Expert)。
重启 MetaEditor 后,创建的未平仓位管理模块就可以在 MQL5 向导中使用了:
图 5. MQL5 向导中创建的未平仓位管理模块。
现在可以使用未平仓位管理模块参数说明部分指定的输入参数了:
图 6. MQL5 向导中创建的未平仓位管理模块的输入参数。
可使用 MetaTrader 5 终端的策略测试程序找出所实现交易策略的输入参数的最佳值。
总结
MQL5 向导的交易策略生成器极大简化了交易理念的检验过程。生成的 EA 交易的代码基于标准库的交易策略类,用于实现某些交易信号类、资金和风险管理类以及持仓支持类。
本文介绍了如何编写自己的未平仓位管理类,以及如何将其连接至 MQL5 向导的交易策略生成器;当价格呈持仓方向移动时,该类可将止损水平移入无损区域,从而在交易过程中减少亏损。本文还介绍了为 MQL5 向导创建的类的说明的结构和格式。
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程