- 发布者:
- MetaQuotes
- 显示:
- 9155
- 等级:
- 已发布:
- 2014.06.13 13:57
- 已更新:
- 2016.11.22 07:33
-
需要基于此代码的EA交易或指标吗?请在自由职业者服务中订购 进入自由职业者服务
此 MACD 样本 EA 包括在 MetaTrader 5 客户终端的标准派发包装里,并且是使用 MACD 指标进行交易的 EA 例样。
这个 EA 文件 MACD Sample.mq5 位于客户端数据文件夹\MQL5\Experts\Examples\MACD\" 中。此 EA 是面向对象开发 EA 的例样。
我们来分析 EA 的结构以及它是如何工作的。
1 EA 属性
1.1. EA 属性
//+------------------------------------------------------------------+ //| MACD Sample.mq5 | //| Copyright 2009-2013, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2009-2013, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "5.20" #property description "重要的是确认 EA 可以工作在正常的" #property description "图表中,并且用户没有造成任何输入" #property description "变量 (手数, 止盈, 尾随止损) 的错误," #property description "我们检查图表上的止盈大于 2*trend_period 柱线"
前 5 行包括一个注释, 之下七行使用预编译指令 #property 设置 MQL5 程序的属性 (版权, 链接, 版本, 描述)。
当您运行这个 EA 时,它们将显示在"通用"选项中:
图例 1 MACD 样本 EA 的常用属性
1.2. 包括文件
下一步, 这个 #include 语句告诉编译器包括含有 交易类 的标准库文件。
- Trade.mqh (CTrade - 交易操作类);
- SymbolInfo.mqh (CSymbolInfo - 交易工具属性的工具类);
- PositionInfo.mqh (CPositionInfo - 仓位属性的工具类);
- AccountInfo.mqh (CAccountInfo - 帐户属性的工具类)。
//--- 包括文件 #include <Trade\Trade.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\AccountInfo.mqh>
适当类型的类实例,之后将会被用于 CExpert 类 (第 3 部分)。
1.3. 输入
之后来到类型, 名称, 省缺值和注释。它们的角色显示在图例. 2。
//--- EA 输入参数 input double InpLots =0.1; // 手数 input int InpTakeProfit =50; // 止盈 (标准点) input int InpTrailingStop =30; // 尾随止损级别 (标准点) input int InpMACDOpenLevel =3; // MACD 开仓级别 (标准点) input int InpMACDCloseLevel=2; // MACD 平仓级别 (标准点) input int InpMATrendPeriod =26; // 均线趋势周期
注意输入参数名称都有前缀 "Inp"。同样,注意全局变量都有前缀 "Ext"。这种变量命名方法可以简化使用大量不同的变量名。
InpLots - 交易量, InpTakeProfit 和 InpTrailingStop 确定止盈和尾随止损级别。
输入参数中注释的文本, 使用省缺值, 显示在 "选项" 选卡替代输入参数名称:
图例 2. MACD 样本 EA 的输入参数
1.4. 全局变量
之后是声明全局变量 ExtTimeOut。它将用于控制交易操作执行的时间。
int ExtTimeOut=10; // 时间 (单位秒) 交易操作时间间隔
在声明 CSampleExpert 类之后, 在第 76 行,另一个全局变量被声明: ExtExpert - CSampleExpert 类实例:
//--- ExtExpert 全局变量
CSampleExpert ExtExpert;
这个 ExtExpert 对象 (CSampleExpert 类样本) 包含交易策略的基本逻辑 (第 3 部分)。
2. 时间处理函数
时间处理函数
2.1. OnInit() 初始化函数
OnInit() 函数在 EA 首次开始运行时被调用一次。通常在 OnInit() 事件处理器中 EA 进行操作准备: 输入参数检查, 指标和参数初始化等。在出现严重错误情况下,当进一步的工作没有了意义,函数退出,返回代码 INIT_FAILED。
//+------------------------------------------------------------------+ //| EA 函数初始化 | //+------------------------------------------------------------------+ int OnInit(void) { //--- 初始化并创建所需的对象 if(!ExtExpert.Init()) return(INIT_FAILED); //--- 初始化成功 return(INIT_SUCCEEDED); }
在这种情况下, ExtExpert 对象的 Init() 会被调用, 依据操作所需的所有对象的准备情况返回真或假 (参看第 3.4 部分)。在出现错误情况下, OnInit() 退出并返回 INIT_FAILED - 若初始化不成功,这是一个正确的方式来完成 EA 或指标的操作。
2.2. OnTick() 函数
这个 OnTick() 函数在运行 EA 的图表中,每次收到新的即时价格时被调用。
//+------------------------------------------------------------------+ //| EA 的新即时价格处理函数 | //+------------------------------------------------------------------+ void OnTick(void) { static datetime limit_time=0; // 保存最后调用时间 + 过期 //--- 在请求时间未耗尽之前不要操作 if(TimeCurrent()>=limit_time) { //--- 检查数据 if(Bars(Symbol(),Period())>2*InpMATrendPeriod) { //--- 在调用 Processing() 方法之后 依据 ExtTimeOut 增加 limit_time 的数值 if(ExtExpert.Processing()) limit_time=TimeCurrent()+ExtTimeOut; } } }
在 OnTick() 时间处理器中包括一个定期调用 ExtExpert.Processing() 方法的机制, 它用来进行市场分析以及当交易条件满足时进行交易。
每次调用的时间间隔在 ExtTimeOut 输入参数中设定。
2.3. OnDeInit() 卸载函数
OnDeInit() 当 EA 从图表中删除时会被调用。如果一个程序在操作期间放置了图形对象, 它们可以从图表中删除。
在一些例子中未使用卸载函数, 没有任何动作会被执行。
3. CSampleExpert 类
3.1. CSampleExpert 类
//+------------------------------------------------------------------+ //| MACD 样本 EA 类例子 | //+------------------------------------------------------------------+ class CSampleExpert { protected: //--- 保护变量 - 类成员再类方法内部可见 double m_adjusted_point; // 乘数,用于 3/5-位报价系统 CTrade m_trade; // CTrade 类实例 CSymbolInfo m_symbol; // CSymbolInfo 类实例 CPositionInfo m_position; // CPositionInfo 类实例 CAccountInfo m_account; // CAccountInfo 类实例 //--- 指标句柄 int m_handle_macd; // 这是 MACD 指标句柄 int m_handle_ema; // 这是移动均线句柄 //--- 指标缓存区 double m_buff_MACD_main[]; // MACD 指标的主线缓存区 double m_buff_MACD_signal[]; // MACD 指标的信号线缓存区 double m_buff_EMA[]; // EMA 指标缓存区 //--- 当前指标数值 double m_macd_current; double m_macd_previous; double m_signal_current; double m_signal_previous; double m_ema_current; double m_ema_previous; //--- 级别 (单位为标准点) double m_macd_open_level; double m_macd_close_level; double m_traling_stop; double m_take_profit; public: //--- 构造器 CSampleExpert(void); //--- 析构器 ~CSampleExpert(void); //--- 公有方法可以从类外部调用 //--- 初始化方法 bool Init(void); //--- 卸载方法 void Deinit(void); //--- 处理方法 bool Processing(void); protected: //--- 保护方法可以在类方法内部存取 bool InitCheckParameters(const int digits_adjust); bool InitIndicators(void); bool LongClosed(void); bool ShortClosed(void); bool LongModified(void); bool ShortModified(void); bool LongOpened(void); bool ShortOpened(void); };
这个 EA 类包含变量声明 (类成员) 以及函数 (类方法)。
为了更便利的使用变量所有类成员变量包含前缀 "m_" (成员), 其指明是类成员变量。在声明变量或方法之前, 要指定它的类型 (或函数返回值)。
类成员变量和方法的可见性由 存取修饰符 定义。在类 CSampleExpert 中使用了修饰符 protected 和 public。所有在 public 区间定义的变量和方法, 是公有的并可从外部存取。这个 CSampleExpert 类有这样的五个方法:
- CSampleExpert(void) - 构造器 (当创建类实例时自动调用);
- ~CSampleExpert(void) - 析构器 (当类实例被删除时自动调用);
- bool Init(void) - 初始化方法, 准备操作所需的所有数据;
- void Deinit(void) - 卸载方法;
- bool Processing(void) - 处理方法。
CSampleExpert 类成员变量声明带有 protected 存取修饰符,仅在 CSampleExpert 类的方法内部可见 (以及子类)。
- double m_adjusted_point - 乘数变量,用于校正 3/5-位报价;
- CTrade m_trade - СTrade 类实例;
- CSymbolInfo m_symbol - CSymbolInfo 类实例;
- CPositionInfo m_position - СPositionInfo 类实例;
- CAccountInfo m_account - CAccountInfo 类实例;
- int m_handle_macd - 保存 MACD 指标 句柄的变量。
- int m_handle_ema - 保存 EMA 指标 句柄的变量;
- double m_buff_MACD_main[] - 动态浮点类型数组, 用于请求 MACD 主线数值;
- double m_buff_MACD_signal[] - 动态浮点类型数组, 用于请求 MACD 信号线数值;
- double m_buff_EMA[] - 动态浮点类型数组, 用于请求 EMA 指标数值;
- double m_macd_current - 用于保存当前 MACD 主线数值;
- double m_macd_previous - 用于保存之前 MACD 主线数值;
- double m_signal_current - 用于保存当前 MACD 信号线数值;
- double m_signal_previous - 用于保存之前 MACD 信号线数值;
- double m_ema_current - 用于保存当前 EMA 指标数值;
- double m_ema_previous - 用于保存之前 EMA 指标数值
- double m_macd_open_level,
- double m_macd_close_level,
- double m_traling_stop,
- double m_take_profit - 用于保存价格级别 (输入参数中设置) 将与账户的 m_adjusted_point 相乘。
CSampleExpert 类方法声明带有 protected 存取修饰符:
- bool InitCheckParameters(const int digits_adjust) - 输入参数和 EA 参数初始化的正确性检查;
- bool InitIndicators(void) - 初始化 (创建 ) MACD 和 移动均线 指标;
- bool LongClosed(void) - 如果多头平仓条件满足,返回 true (并关闭一个已开多头);
- bool ShortClosed(void) - 如果空头平仓条件满足,返回 true (并关闭一个已开空头);
- bool LongModified(void) - 如果已开多头止损位变更条件满足,返回 true (并修改止损价格);
- bool ShortModified(void) - 如果已开空头止损位变更条件满足,返回 true (并修改止损价格);
- bool LongOpened(void) - 如果多头开仓条件满足,返回 true (并开多头仓位);
- bool ShortOpened(void) - 如果空头开仓条件满足,返回 true (并开空头仓位)。
3.2. CSampleExpert 类构造器
//+------------------------------------------------------------------+ //| CSampleExpert 类构造器 | //+------------------------------------------------------------------+ CSampleExpert::CSampleExpert(void) : m_adjusted_point(0), m_handle_macd(INVALID_HANDLE), m_handle_ema(INVALID_HANDLE), m_macd_current(0), m_macd_previous(0), m_signal_current(0), m_signal_previous(0), m_ema_current(0), m_ema_previous(0), m_macd_open_level(0), m_macd_close_level(0), m_traling_stop(0), m_take_profit(0) { ArraySetAsSeries(m_buff_MACD_main,true); ArraySetAsSeries(m_buff_MACD_signal,true); ArraySetAsSeries(m_buff_EMA,true); }
类构造器 在类实例对象创建时被自动调用。当它被调用时, 类成员变量的省缺值 (在括号中) 被设置,并且时间序列 m_buff_MACD_main[], m_buff_MACD_signal[], m_buff_EMA[] 的 检索方向 被设置。
3.3. CSampleExpert 类析构器
//+------------------------------------------------------------------+ //| CSampleExpert 类析构器 | //+------------------------------------------------------------------+ CSampleExpert::~CSampleExpert(void) { }
这个 CSampleExpert 类析构器不包含任何代码。
3.4. CSampleExpert 类的 Init 方法
//+------------------------------------------------------------------+ //| 初始化并验证输入参数 | //+------------------------------------------------------------------+ bool CSampleExpert::Init(void) { //--- 设置通用属性 m_symbol.Name(Symbol()); // 品种symbol m_trade.SetExpertMagicNumber(12345); // 魔幻数字 //--- 校正账户 3/5-位报价 int digits_adjust=1; if(m_symbol.Digits()==3 || m_symbol.Digits()==5) digits_adjust=10; m_adjusted_point=m_symbol.Point()*digits_adjust; //--- 设置账户 m_adjusted_point 修饰符数值 m_macd_open_level =InpMACDOpenLevel*m_adjusted_point; m_macd_close_level=InpMACDCloseLevel*m_adjusted_point; m_traling_stop =InpTrailingStop*m_adjusted_point; m_take_profit =InpTakeProfit*m_adjusted_point; //--- 设置滑点 3 点 m_trade.SetDeviationInPoints(3*digits_adjust); //--- if(!InitCheckParameters(digits_adjust)) return(false); if(!InitIndicators()) return(false); //--- 全部成功 return(true); }
在 Init() 方法中, 类成员变量被初始化,并且输入参数被验证。
调用 m_symbol 对象的 Name() 方法 (CSymbolInfo 类实例) 设置 EA 运行图表的品种名称, 之后 SetExpertMagicNumber() 方法被调用; 它设置 EA 的 m_trade 对象魔幻数字值 (将会用于交易操作)。之后, 这个 Digits() 方法用来请求品种的报价小数点之后位数, 并且在必要时校正该数值。
下一步,m_trade 的 SetDeviationInPoints() 方法被调用, 它设置交易操作允许的滑点数值。
3.5. CSampleExpert 类的 InitCheckParameters
//+------------------------------------------------------------------+ //| 检查输入参数 | //+------------------------------------------------------------------+ bool CSampleExpert::InitCheckParameters(const int digits_adjust) { //--- 检查止盈级别正确性 if(InpTakeProfit*digits_adjust<m_symbol.StopsLevel()) { printf("止盈必须大于 %d",m_symbol.StopsLevel()); return(false); } //--- 检查尾随止损级别正确性 if(InpTrailingStop*digits_adjust<m_symbol.StopsLevel()) { printf("尾随止损必须大于 %d",m_symbol.StopsLevel()); return(false); } //--- 检查交易量正确性 if(InpLots<m_symbol.LotsMin() || InpLots>m_symbol.LotsMax()) { printf("手数范围必须从 %f 到 %f",m_symbol.LotsMin(),m_symbol.LotsMax()); return(false); } if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10) { printf("手数不符合递增值 %f",m_symbol.LotsStep()); return(false); } //--- 如果 Take Profit<=Trailing Stop,显示警告 if(InpTakeProfit<=InpTrailingStop) printf("警告: 尾随止损必须小于止盈"); //--- 全部成功 return(true); }
在 InitCheckParameters() 方法中,检查 EA 输入参数的正确性。如果任何参数无效,出现相应的消息,并且该函数返回 false。
3.6. CSampleExpert 类的 InitIndicators() 方法
//+------------------------------------------------------------------+ //| 指标初始化方法 | //+------------------------------------------------------------------+ bool CSampleExpert::InitIndicators(void) { //--- 创建 MACD 指标 if(m_handle_macd==INVALID_HANDLE) if((m_handle_macd=iMACD(NULL,0,12,26,9,PRICE_CLOSE))==INVALID_HANDLE) { printf("创建 MACD 指标错误"); return(false); } //--- 创建 EMA 指标 if(m_handle_ema==INVALID_HANDLE) if((m_handle_ema=iMA(NULL,0,InpMATrendPeriod,0,MODE_EMA,PRICE_CLOSE))==INVALID_HANDLE) { printf("创建 EMA 指标错误"); return(false); } //--- 全部成功 return(true); }
在 InitIndicators() 方法中, 检查 m_handle_macd 和 m_handle_ema 变量初始值的正确性 (它们必须等于 INVALID_HANDLE, 即使它们已经在构造器中被初始化), 并且技术指标 MACD 和 移动均线 被创建 (使用 iMACD 和 iMA 函数)。如果成功, 函数返回 true, 并且指标句柄被保存在 m_handle_macd 和 m_handle_ema 类成员中。
创建的指标句柄将被用于检查计算数据的数量 (BarsCalculated) 以及在 Processing() 方法中获取的指标数值数量 (CopyBuffer)。
3.7. CSampleExpert 类的 LongClosed() 方法
//+------------------------------------------------------------------+ //| 检查多头的平仓条件 | //+------------------------------------------------------------------+ bool CSampleExpert::LongClosed(void) { bool res=false; //--- 持仓将被平仓? if(m_macd_current>0) if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous) if(m_macd_current>m_macd_close_level) { //--- 平仓 if(m_trade.PositionClose(Symbol())) printf("多头仓位 %s 将被平仓",Symbol()); else printf("平仓错误 %s : '%s'",Symbol(),m_trade.ResultComment()); res=true; } //--- 返回结果 return(res); }
如果平仓条件满足,这个 LongClosed() 方法返回 true (并且平掉多头持仓):
- m_macd_current>0 - MACD 指标主线的当前数值为正 (MACD 直方图高于零轴);
- m_macd_current<m_signal_current && m_macd_previous>m_signal_previous - MACD 指标主线下穿信号线。
- m_macd_current>m_macd_close_level - MACD 指标主线的当前数值大于 m_macd_close_level。
3.8. CSampleExpert 类 ShortClosed() 方法
//+------------------------------------------------------------------+ //| 检查空头平仓条件 | //+------------------------------------------------------------------+ bool CSampleExpert::ShortClosed(void) { bool res=false; //--- 持仓将被平仓? if(m_macd_current<0) if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous) if(MathAbs(m_macd_current)>m_macd_close_level) { //--- 平仓 if(m_trade.PositionClose(Symbol())) printf("空头持仓 %s 将被平仓",Symbol()); else printf("平仓错误 %s : '%s'",Symbol(),m_trade.ResultComment()); res=true; } //--- 返回结果 return(res); }
如果空头平仓条件满足,这个 ShortClosed() 方法返回 true (并且平掉空头持仓):
- m_macd_current<0 - MACD 指标主线的当前数值为负 (MACD 直方图低于零轴).
- m_macd_current>m_signal_current && m_macd_previous<m_signal_previous - MACD 指标主线上穿信号线。
- MathAbs(m_macd_current)>m_macd_close_level - MACD 指标主线的当前数值大于 m_macd_close_level。
3.9. CSampleExpert 类 LongModified() 方法
//+------------------------------------------------------------------+ //| 检查多头修改条件 | //+------------------------------------------------------------------+ bool CSampleExpert::LongModified(void) { bool res=false; //--- 检查是否需要尾随止损 if(InpTrailingStop>0) { if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop) { double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits()); double tp=m_position.TakeProfit(); if(m_position.StopLoss()<sl || m_position.StopLoss()==0.0) { //--- 修改持仓的止损和止盈 if(m_trade.PositionModify(Symbol(),sl,tp)) printf("多头持仓 %s 将被修改",Symbol()); else { printf("修改持仓错误 %s : '%s'",Symbol(),m_trade.ResultComment()); printf("修改参数 : SL=%f,TP=%f",sl,tp); } res=true; } } } //--- 返回结果 return(res); }
如果多头修改条件满足,这个 LongModified() 方法返回 true (并且修改持仓的止损数值): 如果输入 InpTrailingStop>0, 则检查价位是否超越持仓方向的开盘价的 InpTrailingStop 点数。之后, 计算新的止损位以及持仓的止损参数被修改。
3.10. CSampleExpert 类 ShortModified 方法
//+------------------------------------------------------------------+ //| 检查空头持仓修改条件 | //+------------------------------------------------------------------+ bool CSampleExpert::ShortModified(void) { bool res=false; //--- 检查是否需要尾随止损 if(InpTrailingStop>0) { if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop)) { double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits()); double tp=m_position.TakeProfit(); if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0) { //--- 修改持仓的止损和止盈 if(m_trade.PositionModify(Symbol(),sl,tp)) printf("空头持仓 %s 将被修改",Symbol()); else { printf("修改持仓错误 %s : '%s'",Symbol(),m_trade.ResultComment()); printf("修改参数 : SL=%f,TP=%f",sl,tp); } res=true; } } } //--- 返回结果 return(res); }
如果空头修改条件满足,这个 ShortModified() 方法返回 true (并且修改持仓的止损数值): 如果输入 InpTrailingStop>0, 则检查价位是否超越持仓方向的开盘价的 InpTrailingStop 点数。之后, 计算新的止损位以及持仓的止损参数被修改。
3.11. CSampleExpert 类 LongOpened() 方法
//+------------------------------------------------------------------+ //| 检查多头开仓条件 | //+------------------------------------------------------------------+ bool CSampleExpert::LongOpened(void) { bool res=false; //--- 检查多头开仓条件 if(m_macd_current<0) if(m_macd_current>m_signal_current && m_macd_previous<m_signal_previous) if(MathAbs(m_macd_current)>(m_macd_open_level) && m_ema_current>m_ema_previous) { double price=m_symbol.Ask(); double tp =m_symbol.Bid()+m_take_profit; //--- 检查剩余保证金 if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_BUY,InpLots,price)<0.0) printf("资金不足。剩余保证金 = %f",m_account.FreeMargin()); else { //--- 开多头仓位 if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_BUY,InpLots,price,0.0,tp)) printf("仓位 %s 将被开仓",Symbol()); else { printf("开多头仓位错误 %s : '%s'",Symbol(),m_trade.ResultComment()); printf("开仓参数 : price=%f,TP=%f",price,tp); } } res=true; } //--- 返回结果 return(res); }
如果多头开仓条件满足,LongOpened() 方法返回 true (并开多头仓位):
- m_macd_current<0 - MACD 指标主线的当前数值为负 (MACD 直方图低于零轴);
- m_macd_current>m_signal_current && m_macd_previous<m_signal_previous - MACD 指标主线上穿信号线;
- MathAbs(m_macd_current)>m_macd_open_level - MACD 指标主线的当前数值大于 m_macd_open_level;
- m_ema_current>m_ema_previous - ema grows.
当所有条件满足, 检查剩余保证金 (CAccountInfo 标准类库的 FreeMarginCheck() 方法),并且使用 CTrade 类的 PositionOpen() 方法开多头仓位。
3.12. CSampleExpert 类 ShortOpened 方法
//+------------------------------------------------------------------+ //| 检查空头开仓条件 | //+------------------------------------------------------------------+ bool CSampleExpert::ShortOpened(void) { bool res=false; //--- 检查空头开仓条件 if(m_macd_current>0) if(m_macd_current<m_signal_current && m_macd_previous>m_signal_previous) if(m_macd_current>(m_macd_open_level) && m_ema_current<m_ema_previous) { double price=m_symbol.Bid(); double tp =m_symbol.Ask()-m_take_profit; //--- 检查剩余保证金 if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL,InpLots,price)<0.0) printf("资金不足。剩余保证金 = %f",m_account.FreeMargin()); else { //--- 开空头仓位 if(m_trade.PositionOpen(Symbol(),ORDER_TYPE_SELL,InpLots,price,0.0,tp)) printf("仓位 %s 将被开仓",Symbol()); else { printf("开空头仓位错误 %s : '%s'",Symbol(),m_trade.ResultComment()); printf("开仓参数 : price=%f,TP=%f",price,tp); } } res=true; } //--- 返回结果 return(res); }
如果空头开仓条件满足,ShortOpened() 方法返回 true (并开空头仓位:
- m_macd_current>0 - MACD 指标主线的当前数值为正 (MACD 直方图高于零轴);
- m_macd_current<m_signal_current && m_macd_previous>m_signal_previous - MACD 指标主线下穿信号线。
- m_macd_current>m_macd_open_level - MACD 指标主线的当前数值大于 m_macd_open_level;
- m_ema_current<m_ema_previous - ema falls.
当所有条件满足, 检查剩余保证金 (CAccountInfo 标准类库的 FreeMarginCheck() 方法),并且使用 CTrade 类的 PositionOpen() 方法开空头仓位。
3.13CSampleExpert 类 Processing() 方法
//+------------------------------------------------------------------+ //| 如果处理过任何持仓,主函数返回 true | //+------------------------------------------------------------------+ bool CSampleExpert::Processing(void) { //--- 更新报价 if(!m_symbol.RefreshRates()) return(false); //--- 更新指标数值 if(BarsCalculated(m_handle_macd)<2 || BarsCalculated(m_handle_ema)<2) return(false); if(CopyBuffer(m_handle_macd,0,0,2,m_buff_MACD_main) !=2 || CopyBuffer(m_handle_macd,1,0,2,m_buff_MACD_signal)!=2 || CopyBuffer(m_handle_ema,0,0,2,m_buff_EMA) !=2) return(false); //--- 简化指标工作并加快存取 //--- 当前指标数值保存于内部变量 (类成员) m_macd_current =m_buff_MACD_main[0]; m_macd_previous =m_buff_MACD_main[1]; m_signal_current =m_buff_MACD_signal[0]; m_signal_previous=m_buff_MACD_signal[1]; m_ema_current =m_buff_EMA[0]; m_ema_previous =m_buff_EMA[1]; //--- 正确入场是重要的, 但正确退出更重要 //--- 首先检查是否有已开持仓 if(m_position.Select(Symbol())) { if(m_position.PositionType()==POSITION_TYPE_BUY) { //--- 如果必要, 我们尝试平掉或修改多头仓 if(LongClosed()) return(true); if(LongModified()) return(true); } else { //--- 如果必要, 我们尝试平掉或修改空头仓 if(ShortClosed()) return(true); if(ShortModified()) return(true); } } //--- 无开仓 else { //--- 若必要,检查开多头仓位条件并开仓 if(LongOpened()) return(true); //--- 若必要,检查开空头仓位条件并开仓 if(ShortOpened()) return(true); } //--- 不处理仓位退出 return(false); }
CSampleExpert 类 Processing() 方法是 EA 的方法。该 Processing() 方法在 OnTick() 时间处理器中调用, 并且监控方法调用的时间间隔 (不小于 ExtTimeOut 秒) (第 2.2 部分)。
通过调用 CSymbolInfo 类的 RefreshRates() 方法,报价被更新。这个 BarsCalculated() 函数用于获取指标 MACD 和 移动均线 已计算的柱线数量 (第 3.6 部分); 如果柱线数量小于 2,函数退出并返回 false
下一步,这个 CopyBuffer 函数请求最后两个技术指标的数值 (MACD 的主线和信号线,以及均线值); 并且如果复制数据的数量小于 2, 则函数退出。之后,来自数组 m_buff_MACD_main[], m_buff_MACD_signal[] 和 m_buff_EMA[] 的指标数据被复制到变量 m_macd_current, m_macd_previous, m_signal_current, m_signal_previous, m_ema_current 和 m_ema_previous。
下一步工作是利用 CPositionInfo 标准类库对仓位进行操作。如果 Select() 方法调用返回 true, 意味着当前有已开仓位, 它的类型使用 PositionType() 方法确定。进一步的工作是根据持仓的类型操作。
4. 回测
最佳输入参数集合可借助 MetaTrader 5 客户端的 策略测试员 发现。
图例 3 显示 EA 测试结果 2013 省缺设置。
图例 3. MACD 样本 EA 的回测结果
结论
此 MACD 样本 EA 包括在 MetaTrader 5 客户终端的标准派发包装里,是一个利用面向对象方式开发 EA 的例子。
由MetaQuotes Ltd译自俄语
原代码: https://www.mql5.com/ru/code/2154
![MultiT3_TRIXx7Signal](https://c.mql5.com/i/code/indicator.png)
此 MultiT3_TRIXx7 信号指标显示七个不同时间帧的 T3_TRIX 指标的活动趋势信息。
![BackgroundCandle_T3_TRIX_HTF](https://c.mql5.com/i/code/indicator.png)
此指标用填充颜色的长方形绘制大周期的蜡烛条。长方形的填充颜色是根据 T3_TRIX 直方图方向改变。