基于自定义指标的交易信号生成器

Vladimir Karputov | 25 三月, 2014

简介

本文中,我将为您讲解如何根据自定义指标创建交易信号生成器。您会明白如何针对某个自定义指标编写自己的交易模型。我还会解释模型 0 的用途,以及为什么要在交易信号模块中采用 IS_PATTERN_USAGE(0) 型结构。

本文将用到两种代码:我们将要修改的代码和已经修改过的代码。而修改过的代码会如下高亮显示

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2012, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+

修改过的代码,是指要复制和粘贴到交易信号生成器的代码。我希望通过使用高亮能够方便您更好地理解代码。

 

1. 自定义指标

我很确定,肯定有那么一个指标,您一直以来都想要,但偏偏标配包里就是没有。而那个指标,就是您想要建立一个交易信号模块的基础。我将采用标准包中 MACD 指标作为这样一个指标。指标位置如下:...MQL5\Indicators\Examples\MACD.mq5

每个指标可描述一个或多个市场模型。而市场模型是指标值与价格值的一种特定组合。MACD 指标的可用模型分别为主线和信号线的转向、穿越,零位的穿越,背离及双背离。

1.1 新指标模型

我们假设对给定的指标适用市场模型不满意,而且想要引入我们自己的指标模型。新指标模型描述:如果 MACD 指标低于零线,且其值在递增,那么我们可以预计未来增长并建买入持仓:

图 1:预期指标增长的模型 

图 1:预期指标增长的模型 

如果 MACD 指标高于零线,且其值在递减,那么我们可以预计未来下跌并建卖出持仓:

 图 2:预期指标下跌的模型 

图 2:预期指标下跌的模型 

所以,我们决定用自定义指标,并提出了该指标的新交易模型及其描述。我们继续编写代码。

 

2. 根据我们的自定义指标编写交易信号生成器

我们的生成器是 CExpertSignal 基类的后代。CExpertSignal 基类是一种创建交易信号生成器的类。CExpertSignal 类中包含一系列的公共(即,可外部访问)方法,这些方法允许 EA 交易查看有关进入市场方向的交易信号生成器的指示。

由于我们是处理自己的交易信号生成器,所以它应继承自 CExpertSignal 类、且已重新定义了相关的虚拟方法(填入对应的代码)。

 

3. 创建交易信号生成器的类

默认情况下,交易信号生成器应位于 ...MQL5\Include\Expert\Signal 文件夹。不要在标准库的 ...\Signal 文件夹内放入太多的信息,我们在 ...\Expert 文件夹下创建一个新文件夹,并将其命名为 \MySignals

图 3. 创建新的 MySignals 文件夹  

图 3. 创建新的 MySignals 文件夹

接下来,我们利用 MQL5 向导来创建一个包含文件。在 MetaEditor 中选择 File (文件)菜单下的 "New" (新建),再选择 "Include File (*.mqh)" (包含文件)。

图 4. MQL5 向导创建包含文件

图 4. MQL5 向导创建包含文件

信号生成器的类名称将是 MySignal。它将位于 Include\Expert\MySignals\MySignal 下。我们来指定它:

图 5. MQL5 向导包含文件的位置

图 5. MQL5 向导包含文件的位置

单击 "Finish" (完成)后,MQL5 向导就会生成一个空模板。从这时开始,我们一切都是手动完成并复制/粘贴数据。我想让您注意的是,内部来讲,来自标准库的所有信号都几乎完全相同。唯一的区别在于确定交易模型所用的算法。

因此,您可以取 \Include\Expert\Signal 文件夹中的任何文件,复制其内容并粘贴到您的模板里。之后,您可以开始编辑交易信号生成器的结果文件了。

 

4. 交易信号生成器的类的描述

作为一个模板,我复制了 \Include\Expert\Signal\SignalEnvelopes.mqh 文件除标题之外的所有内容:
//+------------------------------------------------------------------+
//|                                              SignalEnvelopes.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+

并将其粘贴到我们几乎空着的 MySignal.mqh 模板。结果如下:

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2012, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| It is derived from the CExpertSignal class.                      |
//+------------------------------------------------------------------+
class CSignalEnvelopes : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

public:
                     CSignalEnvelopes(void);
                    ~CSignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and time series
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalEnvelopes::~CSignalEnvelopes(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and time series of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| "Voting" that the price will grow.                               |
//+------------------------------------------------------------------+
int CSignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+
//| "Voting" that the price will fall.                               |
//+------------------------------------------------------------------+
int CSignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+

注意第 6 行:

#include <Expert\ExpertSignal.mqh>

我们在这里为预处理器下一个命令,令其包含 CExpertSignal 基类,以供我们模板中交易信号生成器的创建。

我们会继续编辑此模板。为确保稍后在 MQL5 向导上可以看到我们的模板,我们需要更改类的描述:

//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+

那么,我们来看看。此行

//| Title=Signals of indicator 'Envelopes'                           |

 会显示我们信号类的名称,MQL5 向导中就是按此显示。我们会将此名称改为类似这种样式:

//| Title=Signal of the 'Custom Indicator' indicator             |

下一行:

//| Name=Envelopes                                                   |

会指明描述我们交易信号类变量的名称。此描述将被 MQL5 向导采用。我们对此行进行如下修改:

//| Name=MyCustomIndicator                                           |

下一行:

//| ShortName=Envelopes                                              |

我们为此参数赋予相同的名称:

//| ShortName=MyCustomIndicator                                      |

下一行设定类名称:

//| Class=CSignalEnvelopes                                           |

重命名此参数:

//| Class=CSignalMyCustInd                                           |

下一个参数保持不变。

//| Page=signal_envelopes                                            |

下一个参数组负责交易信号生成器所本的指标参数描述。前面提到过,我会将 ...MQL5\Indicators\Examples\MACD.mq5 作为自定义指标使用。它拥有下述参数:

//--- input parameters
input int                InpFastEMA=12;               // Fast EMA period
input int                InpSlowEMA=26;               // Slow EMA period
input int                InpSignalSMA=9;              // Signal SMA period
input ENUM_APPLIED_PRICE  InpAppliedPrice=PRICE_CLOSE; // Applied price

4.1 参数描述块

请注意,上面给出的参数仅适用于 MACD.mq5。您的自定义指标拥有的参数可能完全不同。此处的重点在于,将指标参数与交易信号类中的各自描述匹配起来。研究中的自定义指 标MACD.mq5,其交易信号类中的参数描述块将如下所示:

//| Parameter=PeriodFast,int,12,Period of fast EMA                   |
//| Parameter=PeriodSlow,int,24,Period of slow EMA                   |
//| Parameter=PeriodSignal,int,9,Period of averaging of difference   |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |

看一看,指标中的参数现在与类描述块中的描述匹配度如何。完成所有修改后,我们的类描述块将如下所示:

//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal of the 'Custom Indicator' indicator                 |
//| Type=SignalAdvanced                                              |
//| Name=MyCustomIndicator                                           |
//| ShortName=MyCustomIndicator                                      |
//| Class=CSignalMyCustInd                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodFast,int,12,Period of fast EMA                   |
//| Parameter=PeriodSlow,int,24,Period of slow EMA                   |
//| Parameter=PeriodSignal,int,9,Period of averaging of difference   |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//+------------------------------------------------------------------+

编程过程中,向某人的代码中添加注释被视为一种不错的做法,这样一来,如果过一段时间再看代码,也会更方便理解。所以,我们将修改下述代码块:

//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| It is derived from the CExpertSignal class.                      |
//+------------------------------------------------------------------+

以匹配我们类的描述:

//+------------------------------------------------------------------+
//| Class CSignalMyCustInd.                                          |
//| Purpose: Class of the trading signal generator based on          |
//|          the custom indicator.                                   |
//| It is derived from the CExpertSignal class.                      |
//+------------------------------------------------------------------+

为避免混淆,我们需要将所有的 "CSignalEnvelopes" 值替换为 "CSignalMyCustInd"

图 6. 将 CSignalEnvelopes 替换为 CSignalMyCustInd

图 6. 将 CSignalEnvelopes 替换为 CSignalMyCustInd

现在,我们来研究一些几个理论方面的内容。

 

5. CiCustom 类

我们需要 CiCustom 类来继续处理自定义指标中交易指标类的代码。CiCustom 类专为处理自定义指标而创建。CiCustom 类可实现自定义指标数据的创建、设置和访问。

 

6. CIndicators 类

CIndicators 是一个收集时间序列与技术指标类实例的类。CIndicators 类可实现技术指标类实例的创建、存储和管理(数据同步、处理及内存管理)。

我们对 CIndicators 类尤其感兴趣,而原因就在于 Create 方法。此方法会利用指定参数创建某特定类型的指标。

 

7. 继续编写我们的交易信号类

我们接下来要修改的代码块(28-42 行)如下:
class CSignalMyCustInd : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

 

8. 在交易信号生成器中创建自定义指标

看一看上面提供的代码块。此行

   CiEnvelopes       m_env;            // object-indicator

会声明一个对象 - CiEnvelopes 类指标。CiEnvelopes 是处理“标准库”技术指标的类。CiEnvelopes 类基于“标准库”技术指标创建。但是,我们却基于自己的自定义指标编写生成器代码。因此,“标准库”中没有针对我们或您的自定义指标的即用型类。我们能做的,就是使用 CiCustom 类。

我们将自己的指标声明为 CiCustom 类:

   CiCustom          m_mci;            // indicator object "MyCustomIndicator"

8.1 四个变量

您还记得此类中的参数描述块吗?该描述中有三个参数。在我们生成器类的受保护区域中,我们现在将声明 4 个变量,将值传递给我们的 4 个参数:

   //--- adjustable parameters
   int               m_period_fast;    // "fast EMA period"
   int               m_period_slow;    // "slow EMA period"
   int               m_period_signal;  // "difference averaging period"
   ENUM_APPLIED_PRICE m_applied;       // "price type"

下面的代码块:

   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

此代码会声明可加大我们交易信号生成器交易模型“分量”的变量。我们将“分量”块替换为下述代码:

   //--- "weights" of the market models (0-100)
   int               m_pattern_0;      // model 0 "the oscillator has required direction"
   int               m_pattern_1;      // model 1 "the indicator is gaining momentum - buy; the indicator is falling - sell"

 

9. 模型 0

您还记得,本文开头只是决定讲解一种新模型,而该模型要通过我们的交易信号生成器生成。但是,在上述代码中,我指定了两个市场模型(模型 0 和模型 1)。这里的模型 0 是一种重要的辅助模型。挂单交易时,它更是必不可少。应用时,模型 0 会确保挂单随价格一起变化。来看一看我们的交易信号生成器和下述条件:

这些条件是我们交易模型的完美体现。变化如下:我们的交易模型条件会在 1 号柱出现时接受检查。结果如下:MACD 低于零线,但正蓄势待发。这与购买信号对应。因此,我们下达一个“买入止损”挂单:

图 7. 下达一个“买入止损”挂单
 图 7. 下达一个“买入止损”挂单

待第 2 个柱出现后,条件检查发现 MACD 低于零线且正下跌。根据我们的交易模型,当前没有任何买入或卖出条件。但要注意:根据 CExpertSignal 类逻辑,由于买入和卖出条件都不具备,所以应删除所有的挂单。这种情况下,如果价格突然上扬,我们就会错失进入市场发挥优势的良机,因为那时不会有挂单。

这个时候,辅助模型 0 似乎就有用武之地了。适用辅助模型 0 的前提是:

因此,我们可以下达一个“买入止损”挂单:由于我们下达了距柱开盘价 50 点的订单,所以我们只需按照价格变动移动“买入止损”挂单:

图 8. 下移“买入止损”订单
  图 8. 下移“买入止损”订单 

因此,通过使用辅助模型 0,我们得到了根据价格波动移动挂单的机会。

 

10. 模板代码的进一步修改

下一个待修改代码块如下所示:
public:
                     CSignalMyCustInd(void);
                    ~CSignalMyCustInd(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and time series
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

 

在此代码块中,我们可声明设置可调参数的方法、调整交易模型权重的方法、设置验证的方法、指标初始化方法以及检查市场模型是否已生成的方法。

鉴于我们已经在可调参数中声明了 4 个变量,设置参数的方法的代码块如下所示:

   //--- methods of setting adjustable parameters
   void              PeriodFast(int value)               { m_period_fast=value;           }
   void              PeriodSlow(int value)               { m_period_slow=value;           }
   void              PeriodSignal(int value)             { m_period_signal=value;         }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_applied=value;               }

下一个代码块保持不变:

   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and time series
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are generated
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

下一个待修改代码块如下所示:

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };

此代码块将被大量修改。请注意,我使用的是 CIndicator 类的 GetData 方法。调用方法的名称,将直接于代码中提供:

protected:
   //--- indicator initialization method
   bool              InitMyCustomIndicator(CIndicators *indicators);
   //--- methods for getting data
   //- getting the indicator value
   double            Main(int ind) { return(m_mci.GetData(0,ind));      }
   //- getting the signal line value
   double            Signal(int ind) { return(m_mci.GetData(1,ind));    }
   //- difference between two successive indicator values
   double            DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
   int               StateMain(int ind);
   double            State(int ind) { return(Main(ind)-Signal(ind)); }
   //- preparing data for the search
   bool              ExtState(int ind);
   //- searching the market model with the specified parameters
   bool              CompareMaps(int map,int count,bool minimax=false,int start=0);
  };

下一个代码块是构造函数。

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalMyCustInd::CSignalMyCustInd(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }

在构造函数中,我们会更改变量的名称。而且,我们只会用到两个序列:USE_SERIES_HIGH+USE_SERIES_LOW

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalMyCustInd::CSignalMyCustInd(void) : m_period_fast(12),
                                           m_period_slow(24),
                                           m_period_signal(9),
                                           m_applied(PRICE_CLOSE),
                                           m_pattern_0(10),
                                           m_pattern_1(50)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
  }

来修改我们类中的 ValidationSettings 方法。

//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }

在检验块中,我们会检查给定自定义指标的主要条件:m_period_fast>=m_period_slow

//+------------------------------------------------------------------+
//| Checking parameters of protected data                            |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_period_fast>=m_period_slow)
     {
      printf(__FUNCTION__+": slow period must be greater than fast period");
      return(false);
     }
//--- ok
   return(true);
  }

下一个代码块会处理指标的创建:

//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and time series of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }

就像应用于我们的自定义指标一样:

//+------------------------------------------------------------------+
//| Creation of indicators.                                          |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitIndicators(CIndicators *indicators)
  {
//--- check of pointer is performed in the method of the parent class
//---
//--- initialization of indicators and time series of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- creation and initialization of the custom indicator
   if(!InitMyCustomIndicator(indicators))
      return(false);
//--- ok
   return(true);
  }

下述代码块是指标初始化块:

//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }

首先,我们向此块添加一个对象。之后,设置我们指标的参数,并利用 CIndicators 类的 Create 方法创建自定义指标:

//+------------------------------------------------------------------+
//| Initialization of indicators.                                    |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitMyCustomIndicator(CIndicators *indicators)
  {
//--- add an object to the collection
   if(!indicators.Add(GetPointer(m_mci)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- set parameters of the indicator
   MqlParam parameters[4];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="Examples\\MACD.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_period_fast;
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_period_slow;
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_period_signal;
//--- object initialization
   if(!m_mci.Create(m_symbol.Name(),0,IND_CUSTOM,4,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- number of buffers
   if(!m_mci.NumBuffers(4)) return(false);
//--- ok
   return(true);
  }

下一个代码块会检查买入条件:

//+------------------------------------------------------------------+
//| "Voting" that the price will grow.                               |
//+------------------------------------------------------------------+
int CSignalMyCustInd::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

根据我们的模型 0 实施来检查两个模型: 

//+------------------------------------------------------------------+
//| "Voting" that the price will grow.                               |
//+------------------------------------------------------------------+
int CSignalMyCustInd::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
//--- check direction of the main line
   if(DiffMain(idx)>0.0)
     {
      //--- the main line goes upwards, which confirms the possibility of the price growth
      if(IS_PATTERN_USAGE(0))
         result=m_pattern_0;      // "confirming" signal number 0
      //--- if the model 1 is used, look for a reverse of the main line
      if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
         result=m_pattern_1;      // signal number 1
     }
//--- return the result
   return(result);
  }

下一个代码块会检查卖出条件:

//+------------------------------------------------------------------+
//| "Voting" that the price will fall.                               |
//+------------------------------------------------------------------+
int CSignalMyCustInd::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

根据我们的模型 0 实施来检查两个模型:

//+------------------------------------------------------------------+
//| "Voting" that the price will fall.                               |
//+------------------------------------------------------------------+
int CSignalMyCustInd::ShortCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
//--- check direction of the main line
   if(DiffMain(idx)<0.0)
     {
            //--- the main line gown downwards, which confirms the possibility of the price fall
      if(IS_PATTERN_USAGE(0))
         result=m_pattern_0;      // "confirming" signal number 0
      //--- if the model 1 is used, look for a reverse of the main line
      if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0)
         result=m_pattern_1;      // signal number 1
     }
//--- return the result
   return(result);
  }

 

总结

我希望本文能够帮助您理解如何基于自己的自定义指标创建交易信号生成器。