下载MetaTrader 5

请观看如何免费下载自动交易

有趣的脚本?
因此发布一个链接 -
让其他人评价

喜欢这个脚本? 在MetaTrader 5客户端尝试它

2014.06.13 13:57
EA

MACD 样本 - MetaTrader 5EA

| Chinese English Русский Español Deutsch 日本語 Português

发布者:
MetaQuotes Software Corp.
显示:
1879
等级:
投票: 28

此 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. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2009-2013, MetaQuotes Software Corp."
#property link        "http://www.mql5.com"
#property version     "5.20"
#property description "重要的是确认 EA 可以工作在正常的"
#property description "图表中,并且用户没有造成任何输入"
#property description "变量 (手数, 止盈, 尾随止损) 的错误,"
#property description "我们检查图表上的止盈大于 2*trend_period 柱线"

前 5 行包括一个注释, 之下七行使用预编译指令 #property 设置 MQL5 程序的属性 (版权, 链接, 版本, 描述)。

当您运行这个 EA 时,它们将显示在"通用"选项中:

该 MACD 样本 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 的输入参数

图例 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 类有这样的五个方法:

  1. CSampleExpert(void) - 构造器  (当创建类实例时自动调用);
  2. ~CSampleExpert(void) - 析构器 (当类实例被删除时自动调用);
  3. bool Init(void) - 初始化方法, 准备操作所需的所有数据;
  4. void Deinit(void) - 卸载方法;
  5. bool Processing(void) - 处理方法。

CSampleExpert 类成员变量声明带有 protected 存取修饰符,仅在 CSampleExpert 类的方法内部可见 (以及子类)。

  1. double           m_adjusted_point - 乘数变量,用于校正 3/5-位报价;
  2. CTrade          m_trade - СTrade 类实例;
  3. CSymbolInfo  m_symbol - CSymbolInfo 类实例;
  4. CPositionInfo  m_position - СPositionInfo 类实例;
  5. CAccountInfo  m_account - CAccountInfo 类实例;
  6. int                 m_handle_macd - 保存 MACD 指标 句柄的变量。
  7. int                 m_handle_ema - 保存 EMA 指标 句柄的变量;
  8. double           m_buff_MACD_main[] - 动态浮点类型数组, 用于请求 MACD 主线数值;
  9. double           m_buff_MACD_signal[] - 动态浮点类型数组, 用于请求 MACD 信号线数值;
  10. double           m_buff_EMA[] - 动态浮点类型数组, 用于请求 EMA 指标数值;
  11. double           m_macd_current - 用于保存当前 MACD 主线数值;
  12. double           m_macd_previous - 用于保存之前 MACD 主线数值;
  13. double           m_signal_current - 用于保存当前 MACD 信号线数值;
  14. double           m_signal_previous - 用于保存之前 MACD 信号线数值;
  15. double           m_ema_current - 用于保存当前 EMA 指标数值;
  16. double           m_ema_previous - 用于保存之前 EMA 指标数值
  17. double           m_macd_open_level,
  18. double           m_macd_close_level,
  19. double           m_traling_stop,
  20. double           m_take_profit - 用于保存价格级别 (输入参数中设置) 将与账户的 m_adjusted_point 相乘。

CSampleExpert 类方法声明带有 protected 存取修饰符:

  1. bool  InitCheckParameters(const int digits_adjust) - 输入参数和 EA 参数初始化的正确性检查;
  2. bool  InitIndicators(void) - 初始化 (创建 ) MACD移动均线 指标;
  3. bool  LongClosed(void) - 如果多头平仓条件满足,返回 true (并关闭一个已开多头);
  4. bool  ShortClosed(void) - 如果空头平仓条件满足,返回 true (并关闭一个已开空头);
  5. bool  LongModified(void) - 如果已开多头止损位变更条件满足,返回 true (并修改止损价格);
  6. bool  ShortModified(void) - 如果已开空头止损位变更条件满足,返回 true (并修改止损价格);
  7. bool  LongOpened(void) - 如果多头开仓条件满足,返回 true (并开多头仓位);
  8. 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移动均线 被创建 (使用 iMACDiMA 函数)。如果成功, 函数返回 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 (并且平掉多头持仓):

  1. m_macd_current>0 - MACD 指标主线的当前数值为正 (MACD 直方图高于零轴);
  2. m_macd_current<m_signal_current && m_macd_previous>m_signal_previous - MACD 指标主线下穿信号线。
  3. 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 (并且平掉空头持仓):

  1. m_macd_current<0 - MACD 指标主线的当前数值为负 (MACD 直方图低于零轴).
  2. m_macd_current>m_signal_current && m_macd_previous<m_signal_previous - MACD 指标主线上穿信号线。
  3. 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 (并开多头仓位):

  1. m_macd_current<0 - MACD 指标主线的当前数值为负 (MACD 直方图低于零轴);
  2. m_macd_current>m_signal_current && m_macd_previous<m_signal_previous - MACD 指标主线上穿信号线;
  3. MathAbs(m_macd_current)>m_macd_open_level - MACD 指标主线的当前数值大于 m_macd_open_level;
  4. 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 (并开空头仓位:

  1. m_macd_current>0 - MACD 指标主线的当前数值为正 (MACD 直方图高于零轴);
  2. m_macd_current<m_signal_current && m_macd_previous>m_signal_previous - MACD 指标主线下穿信号线。
  3. m_macd_current>m_macd_open_level - MACD 指标主线的当前数值大于 m_macd_open_level;
  4. 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 的回测结果

图例 3. MACD 样本 EA 的回测结果

结论

此 MACD 样本 EA 包括在 MetaTrader 5 客户终端的标准派发包装里,是一个利用面向对象方式开发 EA 的例子。


本文译自 MetaQuotes Software Corp. 撰写的俄文原文
官方代码: https://www.mql5.com/ru/code/2154

MultiT3_TRIXx7Signal MultiT3_TRIXx7Signal

此 MultiT3_TRIXx7 信号指标显示七个不同时间帧的 T3_TRIX 指标的活动趋势信息。

BackgroundCandle_T3_TRIX_HTF BackgroundCandle_T3_TRIX_HTF

此指标用填充颜色的长方形绘制大周期的蜡烛条。长方形的填充颜色是根据 T3_TRIX 直方图方向改变。

Exp_T3_TRIX Exp_T3_TRIX

一款使用 T3_TRIX 指标的交易系统。

Exp_RSIOMA_V2 Exp_RSIOMA_V2

交易系统采用 RSIOMA_V2 指标。