当您创建自动化交易系统时,有必要编写分析市场状况、生成交易信号的算法,以及追踪您的敞口仓位、资金管理与风险管理系统的算法。
模块代码编写完毕后,最难的环节就是把各个部分组合起来,并对交易机器人源代码实施调试。模块交互的架构是这里当之无愧的主角:如其构建不良,则大多数的时间都会花在查找和纠正错误方面;而且,如您更换任何模块的算法,都会造成整个源代码的重写。
在 MQL5 中,利用面向对象方法会明显方便自动化交易系统的编写和测试。
MetaQuotes Software Corp. 已经开发出了实施交易策略的类。现在,通过在 MetaEditor 中直接选择必要的交易信号(当前为 20 个)、追踪 (4) 和资金管理 (5) 模块,我们可以自动生成“EA 交易”代码。通过上述模块的组合,您就可以得到众多种类的即用型交易系统变体。
您还可以搭配上述任何模块的实现来使用自己的类。自行创建,或是通过任务服务订购。
本文中我们要研究的,是利用 MQL5 向导自动生成“EA 交易”源代码。而且无需任何编程!
在 MetaEditor 中使用 MQL5 Wizard 生成“EA 交易”的源代码。
交易策略的基类位于 '\<client_terminal_directory>\MQL5\Include\Expert\' 文件夹内。准备就绪的交易信号类、跟踪未平仓位类和资金与风险管理类的算法分别位于 Signal、Trailing 和 Money 子文件夹中。MQL5 向导解析这些文件夹中的文件,并用这些文件生成 EA 的代码。
要启动 MQL5 向导,您需要在工具栏上单击 "New"(新建),或从 "File"(文件)菜单选择 "New"(新建)(或按 Ctrl+N):
图 1. 启动 MQL5 向导
然后选择要创建的程序的类型。本例子中,选择 "Expert Advisor (generate)"(“EA 交易”(生成)) 选项:
图 2. 选择程序的类型
步骤 1. “EA 交易”的一般属性
接下来会打开一个对话框,您可以在其中设置“EA 交易”的一般属性:
图 3. “EA 交易”的一般属性
在 "Name"(名称)、"Author"(作者)和 "Link"(链接)字段中分别指定您的“EA 交易”的名称、作者姓名和您的网站的链接。
“EA 交易”还有以下输入参数:
下一步,选择 EA 据其进行交易的交易信号的类型。
步骤 2. 选择交易信号的模块
建仓和平仓的算法是由交易信号模块确定的。交易信号模块包含建仓/平仓/反向仓位的规则。
标准库拥有以下准备就绪的交易信号模块:
交易信号类型从 "Name" 下拉菜单列表中选择。
按下 Next 按钮后,就会出现一个窗口:
图 4. “EA 交易”交易信号的选择
要添加一个交易信号模块,则按 "Add" (添加)按钮。
我们基于移动平均线指标来添加交易信号。
图 5. 选择交易信号的算法
交易信号的每个模块都有自己的参数。您可以使用缺省值。
有两种参数创建模式。您可以用鼠标左键双击参数图标的方式,在两种模式间切换。如果参数有高亮图标 ,那么它可用作“EA 交易”的输入变量。而且,此类参数还可用于策略测试程序中的 EA 优化。如果参数呈灰色图标 ,则其拥有固定值,您不能通过“EA 交易”的属性进行修改。
交易信号的模块会显示于列表中:
图 6. 已添加的交易信号模块
步骤 3. 选择“跟踪敞口仓位”模块
下一步是选择跟踪敞口仓位的算法(跟踪止损)。使用跟踪让您能够兑现赚得的利润。
“标准库”提供跟踪敞口仓位的多种途径:
在我们的“EA 交易”中选择 "Trailing Stop based on fixed Stop Level"(基于固定止损水平的跟踪止损):
图 7. 选择“跟踪敞口仓位”算法
这种跟踪类型有两个参数:StopLevel 与 ProfitLevel (按逗号后面 2 位和 4 位报价的点数),将用于跟踪敞口仓位:
图 9. 敞口仓位跟踪选定算法的参数设定
步骤 4. 选择“资金与风险管理”模块
在最后一步中,您需要选择将在您的“EA 交易”中使用的资金与风险管理系统。
此算法的目的在于确定交易操作的交易量(手数),以及风险管理。如果损失值超过允许限制(比如资产净值的 10%),则资金与风险管理模块会强行关闭不盈利的仓位。
“标准库”会提供多种即用型资金与风险管理算法的实施办法:
图 9. 选择资金与风险管理的算法
选择 'Trading with fixed trade volume' (以固定的交易量交易)算法。
我们选择的模块有两个参数:
图 10. 选定资金与风险管理算法的参数设定
点击 "Finish"(完成) 后, \teminal_data_filder\MQL5\Experts\ 文件夹中就会出现 TestExpert.mq5 文件。文件名与“EA 交易”的指定名称相符。
利用 MQL5 向导生成的“EA 交易”源代码如下所示:
//+------------------------------------------------------------------+ //| TestExpert.mq5 | //| Copyright 2012, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2012, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| 包含文件 | //+------------------------------------------------------------------+ #include <Expert\Expert.mqh> //--- 可用信号 #include <Expert\Signal\SignalMA.mqh> //--- 可用追踪止损 #include <Expert\Trailing\TrailingFixedPips.mqh> //--- 可用资金管理 #include <Expert\Money\MoneyFixedLot.mqh> //+------------------------------------------------------------------+ //| 输入参数 | //+------------------------------------------------------------------+ //--- EA交易的输入参数 input string Expert_Title ="TestExpert"; // EA交易名称 ulong Expert_MagicNumber =23689; // bool Expert_EveryTick =false; // //--- 主要信号的参数 input int Signal_ThresholdOpen =10; // 建仓信号阈值 [0...100] input int Signal_ThresholdClose =10; // 平仓信号阈值 [0...100] input double Signal_PriceLevel =0.0; // 执行交易的价格水平 input double Signal_StopLevel =50.0; // 止损水平 (点数) input double Signal_TakeLevel =50.0; // 获利水平 (点数) input int Signal_Expiration =4; // 挂单过期时间 (柱数) input int Signal_MA_PeriodMA =85; // 移动平均(85,0,...) 平均周期数 input int Signal_MA_Shift =0; // 移动平均(85,0,...) 时间转换 input ENUM_MA_METHOD Signal_MA_Method =MODE_SMA; // 移动平均(85,0,...) 平均方法 input ENUM_APPLIED_PRICE Signal_MA_Applied =PRICE_CLOSE; // 移动平均(85,0,...) 价格序列 input double Signal_MA_Weight =1.0; // 移动平均(85,0,...) 权重 [0...1.0] //--- 追踪输入参数 input int Trailing_FixedPips_StopLevel =30; // 追踪止损水平 (点数) input int Trailing_FixedPips_ProfitLevel=50; // 追踪获利水平 (点数) //--- 资金输入参数 input double Money_FixLot_Percent =10.0; // 百分比 input double Money_FixLot_Lots =0.1; // 固定交易量 //+------------------------------------------------------------------+ //| 全局EA交易对象 | //+------------------------------------------------------------------+ CExpert ExtExpert; //+------------------------------------------------------------------+ //| EA交易初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- 初始化EA if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) { //--- 失败 printf(__FUNCTION__+": 初始化EA交易失败"); ExtExpert.Deinit(); return(-1); } //--- 创建信号 CExpertSignal *signal=new CExpertSignal; if(signal==NULL) { //--- 失败 printf(__FUNCTION__+": 创建信号错误"); ExtExpert.Deinit(); return(-2); } //--- ExtExpert.InitSignal(signal); signal.ThresholdOpen(Signal_ThresholdOpen); signal.ThresholdClose(Signal_ThresholdClose); signal.PriceLevel(Signal_PriceLevel); signal.StopLevel(Signal_StopLevel); signal.TakeLevel(Signal_TakeLevel); signal.Expiration(Signal_Expiration); //--- 创建 CSignalMA 过滤器 CSignalMA *filter0=new CSignalMA; if(filter0==NULL) { //--- 失败 printf(__FUNCTION__+": 创建过滤器 filter0 失败"); ExtExpert.Deinit(); return(-3); } signal.AddFilter(filter0); //--- 设置参数过滤器 filter0.PeriodMA(Signal_MA_PeriodMA); filter0.Shift(Signal_MA_Shift); filter0.Method(Signal_MA_Method); filter0.Applied(Signal_MA_Applied); filter0.Weight(Signal_MA_Weight); //--- 创建追踪对象 CTrailingFixedPips *trailing=new CTrailingFixedPips; if(trailing==NULL) { //--- 失败 printf(__FUNCTION__+": 创建追踪错误"); ExtExpert.Deinit(); return(-4); } //--- 给EA增加追踪功能 (将会自动删除)) if(!ExtExpert.InitTrailing(trailing)) { //--- 失败 printf(__FUNCTION__+": 初始化追踪错误"); ExtExpert.Deinit(); return(-5); } //--- 设置追踪参数 trailing.StopLevel(Trailing_FixedPips_StopLevel); trailing.ProfitLevel(Trailing_FixedPips_ProfitLevel); //--- 创建资金对象 CMoneyFixedLot *money=new CMoneyFixedLot; if(money==NULL) { //--- 失败 printf(__FUNCTION__+": 创建资金对象错误"); ExtExpert.Deinit(); return(-6); } //--- 把资金对象加到EA交易 (将被自动删除)) if(!ExtExpert.InitMoney(money)) { //--- 失败 printf(__FUNCTION__+": 初始化资金对象错误"); ExtExpert.Deinit(); return(-7); } //--- 设置资金参数 money.Percent(Money_FixLot_Percent); money.Lots(Money_FixLot_Lots); //--- 检查所有的交易对象 if(!ExtExpert.ValidationSettings()) { //--- 失败 ExtExpert.Deinit(); return(-8); } //--- 调整所有所需的指标 if(!ExtExpert.InitIndicators()) { //--- 失败 printf(__FUNCTION__+": 初始化指标错误"); ExtExpert.Deinit(); return(-9); } //--- ok return(0); } //+------------------------------------------------------------------+ //| EA交易去初始化函数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ExtExpert.Deinit(); } //+------------------------------------------------------------------+ //| "Tick" 事件处理函数 | //+------------------------------------------------------------------+ void OnTick() { ExtExpert.OnTick(); } //+------------------------------------------------------------------+ //| "Trade" 事件处理函数 | //+------------------------------------------------------------------+ void OnTrade() { ExtExpert.OnTrade(); } //+------------------------------------------------------------------+ //| "Timer" 事件处理函数 | //+------------------------------------------------------------------+ void OnTimer() { ExtExpert.OnTimer(); } //+------------------------------------------------------------------+
“EA 交易”的代码由多个部分构成。
描述程序属性的部分:
#property copyright "Copyright 2012, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00"
内含文件:
#include <Expert\Expert.mqh> //--- 可用信号 #include <Expert\Signal\SignalMA.mqh> //--- 可用追踪止损 #include <Expert\Trailing\TrailingFixedPips.mqh> //--- 可用资金管理 #include <Expert\Money\MoneyFixedLot.mqh>
CExpert 类(其用于“EA 交易”中的实例)的代码位于 Expert.mqh 文件中。
SignalMA.mqh 文件中包含选定交易信号类的源代码 - CSignalMA。TrailingFixedPips.mqh 文件中包含敞口仓位算法类的跟踪源代码 - CTrailingFixedPips。而资金与风险管理,则要靠 MoneyFixedLot.mqh 文件中包含的 CMoneyFixedLot 类来实现。
接下来是“EA 交易”的输入参数:
//--- EA交易的输入参数 input string Expert_Title ="TestExpert"; // EA交易名称 ulong Expert_MagicNumber =23689; // bool Expert_EveryTick =false; // //--- 主要信号的参数 input int Signal_ThresholdOpen =10; // 建仓信号阈值 [0...100] input int Signal_ThresholdClose =10; // 平仓信号阈值 [0...100] input double Signal_PriceLevel =0.0; // 执行交易的价格水平 input double Signal_StopLevel =50.0; // 止损水平 (点数) input double Signal_TakeLevel =50.0; // 获利水平 (点数) input int Signal_Expiration =4; // 挂单过期时间 (柱数) input int Signal_MA_PeriodMA =85; // 移动平均(85,0,...) 平均周期数 input int Signal_MA_Shift =0; // 移动平均(85,0,...) 时间转换 input ENUM_MA_METHOD Signal_MA_Method =MODE_SMA; // 移动平均(85,0,...) 平均方法 input ENUM_APPLIED_PRICE Signal_MA_Applied =PRICE_CLOSE; // 移动平均(85,0,...) 价格序列 input double Signal_MA_Weight =1.0; // 移动平均(85,0,...) 权重 [0...1.0] //--- 追踪输入参数 input int Trailing_FixedPips_StopLevel =30; // 追踪止损水平 (点数) input int Trailing_FixedPips_ProfitLevel=50; // 追踪获利水平 (点数) //--- 资金输入参数 input double Money_FixLot_Percent =10.0; // 百分比 input double Money_FixLot_Lots =0.1; // 固定交易量
前三个参数(Expert_Title、Expert_MagicNumber 和 Expert_EveryTick)为常规参数。不管选定的是交易信号、跟踪还是资金与风险管理算法,它们始终存在。
字符串 Expert_Title 参数会指定“EA 交易”的名称,Expert_MagicNumber 会指定其 ID (该值会被用于交易请求参数中),而 Expert_EveryTick 参数则用于设置 EA 的工作模式。如将 Expert_EveryTick 设置为 true,则每当有效交易品种出现新的价格变动时,“EA 交易”都可以调用处理程序函数(检查有无交易条件、执行交易操作、跟踪敞口仓位)。
继“EA 交易”常规参数之后到来的是选定交易信号算法的输入参数(本例中是用于 CSignalMA 类的参数)。
我们选择了跟踪敞口仓位的 CTrailingStopFixedPips 类。它会以止损和获利水平确定的固定距离跟踪敞口仓位,其值以 "normal" 2/4 位点数的形式定义。如果价格按距离向敞口仓位移动,超过了 Trailing_FixedPips_StopLevel 水平设定的点数,则“EA 交易”会修改止损与获利水平值(如果 Trailing_FixedPips_ProfitLevel > 0)。
Money_FixLot_Percent 与 Money_FixLot_Lots 输入参数,与在 CMoneyFixedLot 类中实施、带有固定交易手数算法的参数相对应。本例中,将利用与 Money_FixLot_Lots 值相同的固定交易量执行交易。
CMoneyFixedLot 类还会实施风险管理算法:如果 Inp_Money_FixLot_Percent 参数中指定了一个损失(作为当前资产净值一个给定的百分比),则 CMoneyFixedLot 类会建议“EA 交易”强行为不盈利仓位平仓,而且也会这样执行。
CExpert 类的 ExtExpert 对象,会在“EA 交易”的输入参数之后声明:
CExpert ExtExpert;
此为交易策略类的实例。
作为 CExpert 类的一个实例,ExtExpert 对象中包含对于 CExpertSignal (交易信号的基类)、CExpertMoney (资金与风险管理基类)以及 CExpertTrailing (追踪敞口仓位基类)类子对象的引用。此外,CExpert 类还包含 CExpertTrade、SSymbolInfo、CAccountInfo、CPositionInfo、COrderInfo 类以及 CIndicators 容器的实例。
要设置“EA 交易”的参数,您必须要创建对应类的实例,并指定对于 ExtExpert 类中创建对象的引用。
我们来看看“EA 交易”初始化的 OnInit 函数。我们在此完成 ExtExpert 类的初始化和属性配置。
1. ExtExpert 类的初始化:
//--- 初始化EA if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber)) { //--- 失败 printf(__FUNCTION__+": 初始化EA交易失败"); ExtExpert.Deinit(); return(-1); }
ExtExpert 对象利用 Init 方法初始化。我们在这里设定了交易品种、时间表、每次价格变动调用方法的标志、“EA 交易”的 ID,而且还完成了类的私人对象的创建和初始化(在此阶段,CExpertSignal、CExpertMoney 和 CExpertTrailing 类被用作信号、跟踪与资金管理对象)。
如果 ExtExpert 对象未能成功初始化,则“EA 交易”在返回代码 -1 的同时被中止。
2. 信号对象的创建及属性配置
//--- 创建信号 CExpertSignal *signal=new CExpertSignal; if(signal==NULL) { //--- 失败 printf(__FUNCTION__+": 创建信号错误"); ExtExpert.Deinit(); return(-2); } //--- ExtExpert.InitSignal(signal); signal.ThresholdOpen(Signal_ThresholdOpen); signal.ThresholdClose(Signal_ThresholdClose); signal.PriceLevel(Signal_PriceLevel); signal.StopLevel(Signal_StopLevel); signal.TakeLevel(Signal_TakeLevel); signal.Expiration(Signal_Expiration); //--- 创建 CSignalMA 过滤器 CSignalMA *filter0=new CSignalMA; if(filter0==NULL) { //--- 失败 printf(__FUNCTION__+": 创建过滤器 filter0 失败"); ExtExpert.Deinit(); return(-3); } signal.AddFilter(filter0); //--- 设置参数过滤器 filter0.PeriodMA(Signal_MA_PeriodMA); filter0.Shift(Signal_MA_Shift); filter0.Method(Signal_MA_Method); filter0.Applied(Signal_MA_Applied); filter0.Weight(Signal_MA_Weight);
交易信号对象的配置步骤如下:
如果 ExtExpert 对象未能成功初始化,“EA 交易”会被中止且返回代码(从 -2 到 -3),是何代码则取决于错误在哪个步骤发生。
根据参数在 MQL5 向导中被指定的方式,生成相应的代码。
//--- 设置信号参数 filter0.PeriodMA(85); //--- 参数由MQL5 向导设置固定 //--- (灰色图标 - 固定值等于 85) filter0.SlowPeriod(Signal_MA_Shift); //--- 参数根据输入变量设置 //--- (蓝色图标 - EA交易的输入参数)
如果参数固定、且其值与缺省值没有区别,则其不会被写入生成的代码。这种情况下,就会采用参数的缺省值(已于相应类中指定)。
3. 跟踪对象的创建及属性配置
//--- 创建追踪对象 CTrailingFixedPips *trailing=new CTrailingFixedPips; if(trailing==NULL) { //--- 失败 printf(__FUNCTION__+": 创建追踪错误"); ExtExpert.Deinit(); return(-4); } //--- 给EA增加追踪功能 (将会自动删除)) if(!ExtExpert.InitTrailing(trailing)) { //--- 失败 printf(__FUNCTION__+": 初始化追踪错误"); ExtExpert.Deinit(); return(-5); } //--- 设置追踪参数 trailing.StopLevel(Trailing_FixedPips_StopLevel); trailing.ProfitLevel(Trailing_FixedPips_ProfitLevel);跟踪对象的配置步骤如下:
如果跟踪对象未能成功初始化,“EA 交易”会被中止且返回代码(从 -4 到 -5),是何代码则取决于错误在哪个步骤发生。
4. 资金对象的创建及属性配置
//--- 创建资金对象 CMoneyFixedLot *money=new CMoneyFixedLot; if(money==NULL) { //--- 失败 printf(__FUNCTION__+": 创建资金对象错误"); ExtExpert.Deinit(); return(-6); } //--- 把资金对象加到EA交易 (将被自动删除)) if(!ExtExpert.InitMoney(money)) { //--- 失败 printf(__FUNCTION__+": 初始化资金对象错误"); ExtExpert.Deinit(); return(-7); } //--- 设置资金参数 money.Percent(Money_FixLot_Percent); money.Lots(Money_FixLot_Lots);
资金与风险管理对象的配置有 4 步:
如果资金对象未能成功初始化,“EA 交易”会被中止且返回代码(从 -6 到 -7),是何代码则取决于错误在哪个步骤发生。
5. 类中用到的所有指标的初始化
//--- 检查所有的交易对象 if(!ExtExpert.ValidationSettings()) { //--- 失败 ExtExpert.Deinit(); return(-8); } //--- 调整所有所需的指标 if(!ExtExpert.InitIndicators()) { //--- 失败 printf(__FUNCTION__+": 初始化指标错误"); ExtExpert.Deinit(); return(-9); } //--- ok return(0);
待您完成交易信号、跟踪及资金管理对象的创建和初始化后,ExtExpert 的 ValidationSettings() 方法就会被调用。此后,又会调用 ExtExpert 对象的 InitIndicators() 方法。它会初始化信号、跟踪及资金对象中使用的指标。
而 OnDeinit、OnTick、OnTrade 和 OnTimer 事件的处理,都是通过调用 ExtExpert 类的相应方法来执行。
如果您想知道 CExpert 方法的实施详情,可以查看指标的源代码,路径为 '\<client_terminal_directory>\MQL5\Include\Expert\expert.mqh'。
如果存在标准库的所有组件,则生成的“EA 交易”的代码将会成功编译:
图 10. 在 MQL5 向导中创建的“EA 交易”源代码的成功编译
作为结果的“EA 交易”会根据选定的交易信号、跟踪敞口仓位以及资金与风险管理的算法进行交易。
您可以看看,自己新创建的交易系统,如何利用来自 MetaTrader 5 客户端的策略测试程序工作。图 11 所示为默认设置下根据历史数据得到的测试结果 (EURUSD, H1, 2010.01.01-2011.06.01) :
图 11. 根据历史数据 (EURUSD, H1) 得到的“EA 交易”测试结果
可以在 MetaTrader 5 策略测试程序中进行优化之后找出一组最佳的 EA 交易程序参数。
利用交易策略类为您交易理念的创建和测试提供了极大的便利。现在,“EA 交易”的整个源代码,都可以利用 MQL5 向导、基于即用型“标准库”模块或您自己的模块,直接在 MetaEditor 中构造。
如果您不想或不能编写自己的交易信号模块,您任何时候都可以从任务服务以及通过订购整个交易机器人或所需的模块来获取。此方法还能实现以下其他好处:
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程