外汇EA编写教程:通用智能交易系统:组合交易及管理策略组合(第四章)

内容简介表

 

简介

经常我们需要创建一个能同另一个算法共存的算法,例如,某算法的执行不能影响另一个同时再运行的算法。这种情况出现在当你需要将多个算法集成到一个可执行ex5模块中的时候。尽管它很简单,但是也有明显的“缺陷” —在创建交易策略的引擎时必须考虑算法的特征。

CStrategy交易引擎包含一组算法,能使两个或多个交易策略联合运行。我们将在本文中详细讨论它们。同时我们也将创建一个交易组合 — 一组同时交易的EA,为了分散交易风险。CStrategyList类 — CStrategy类型策略的容器 — 属于提供同时操作策略的算法。此类允许上传基于XML描述的策略,同时使用相应的方法— 一个策略仓库,动态地创建它们。

附件视频展示了在MetaTrader 5 策略测试器中测试多个策略的过程。基于所描述的交易引擎的所有策略都有一个默认的自定义面板,它可以帮助您轻松的直接从图表上控制每个策略。

 

CStrategyList 策略管理器

在“通用智能交易系统”系列的第二篇文章中描述了 CStrategy 类和它的主要模块。通过使用这个类以及模块中的功能函数,每一个衍生策略都有一个统一的交易逻辑。然而,使用程序组织一个交易过程不仅仅是执行交易请求。确保策略之间的协作性是非常重要的,其中包括在一个可执行ex5模块中运行多种算法。

CStrategyList类就是用于这个特殊目的的。你可以从它的名字猜到,此类提供一个CStrategy型策略的列表,但是它的运作要比一般的数据容器更为复杂些。该模块解决如下问题:

  • 确保多个交易策略同时运行;
  • 向每个策略实例发送交易事件;
  • 从统一的策略XML列表中创建策略对象;
  • 同自定义EA配置面板交互。

这里是 CStrategyList 类的头文件:

//+------------------------------------------------------------------+
//| 管理CStrategy类型策略的容器类
//+------------------------------------------------------------------+
class CStrategyList
  {
private:
   CLog*       Log;                 // 日志
   CArrayObj   m_strategies;        // CStrategy类型策略
   CLimits*    m_limits;
   void        ParseStrategies(CXmlElement* xmlStrategies, bool load_curr_symbol);
   void        ParseLimits(CXmlElement* xmlLimits);
   CStrBtn     StrButton;   
public:
   CStrategyList(void);
   ~CStrategyList(void);
   void LoadStrategiesFromXML(string xml_name, bool load_curr_symbol);
   bool AddStrategy(CStrategy* strategy);
   int  Total();
   CStrategy* At(int index);
   void OnTick();
   void OnTimer();
   void OnBookEvent(string symbol);
   void OnDeinit(const int reason);
   void OnChartEvent(const int id,
                     const long &lparam,
                     const double &dparam,
                     const string &sparam);
                     

  };

如你所见,大多数方法都是交易事件处理函数。他们有同样类型的内容。让我们分析其中一个,OnBookEvent:

//+------------------------------------------------------------------+
//| 发送 OnBookEvent 事件到所有列表策略
//+------------------------------------------------------------------+
void CStrategyList::OnBookEvent(string symbol)
  {
   for(int i=0; i<m_strategies.Total(); i++)
     {
      CStrategy *strategy=m_strategies.At(i);
      strategy.OnBookEvent(symbol);
     }
  }

从类的内容来看,它在列表中搜索CStrategy策略并在每个策略中调用一个对应的事件。其他事件的处理方法类似。

除了传递事件外,CStrategyList执行特殊的程序从XML文件中加载策略。关于它运作方式的更多详细信息请读下面的部分。

 

从一个XML列表中加载策略。一个策略的组合

如果一个ex5执行模块包含多个交易算法,我们需要能够生成策略组合的工具。假设两个具有不同参数的算法在一个执行模块中做交易。如何配置这些参数?最简单的办法就是在EA属性窗口输出每个策略的参数。但是,当使用许多策略,且每个策略都有很多参数时怎么办?这种情况下,不同的调整值,标识,字符串和备注参数列表将会非常庞大。下图就是执行三个交易策略的EA参数窗口:

图 1. 用三种策略交易的EA参数列表

一个EA甚至可以使用更多的策略。这种情况下,参数列表的规模可能难以想象。组合策略交易的第二个重要特征是:流水线化创建策略。假设我们想要运行不同参数的同一个策略。我们该怎么办?显然,除了参数设置不同,这两个策略几乎一样。我们可以把此任务交给一个独立的类,而无需手动创建每个策略。这个类可以自动创建策略对象并正确配置它。

在创建一个策略前,有必要给出它的完整描述。对其的描述需要包含如下几个方面:

  • 策略名称;
  • 唯一的ID或者编号;
  • 策略加载的货币对;
  • 时间框架;
  • 策略的参数列表(每个策略一个)。

策略描述还可能包含畜类上述之外的属性。最好的方法是使用XML来描述。XML语言是一种特殊的描述工具。他是得描述复杂对象变得容易,因此一个交易策略可以被转化为一个XML文档,一个XML文档能被转化成一个策略。例如,基于一个XML文档,交易引擎能够创建一个策略并正确配置其参数。要直接使用MQL5语言处理这种类型的文档,我们可以使用Code Base中的一个特殊的XML-Parser库来实现。

这里是一个策略组合的XML描述样例,它加载三个不同参数的移动平均策略。

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyOnly</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>12</FastMA>
                                <SlowMA>45</SlowMA>
                                <Shift>1</Shift>
                                <Method>MODE_EMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

每个策略形成<Strategy>单元。下面这些属性在其中指定:Symbol, Timeframe, Magic 和 StrategyName。从上面的例子我们看到三个策略中的每一个都有其自身的货币对,编号和时间框架。除了这些必须的参数,其他策略属性在XML列表中指定。<TradeStateStart>部分用于策略加载时指定交易模式。<Params>部分包含策略的参数。

在开始时,交易引擎尝试从上面的XML文件中加载交易策略。一个策略在LoadStrategiesFromXML方法中基于CStrategyList类的XML文件中,被加载和创建。下面是其方法体以及相关方法:

//+------------------------------------------------------------------+
//| 从XML文件 "xml_name" 中加载策略
//| 如果load_curr_symbol被设置为true,它将仅加载
//| 当前货币对CurrentSymbol()所对应的
//| 策略               
//+------------------------------------------------------------------+
void CStrategyList::LoadStrategiesFromXML(string xml_name,bool load_curr_symbol)
  {
   CXmlDocument doc;
   string err;
   bool res=doc.CreateFromFile(xml_name,err);
   if(!res)
      printf(err);
   CXmlElement *global=GetPointer(doc.FDocumentElement);
   for(int i=0; i<global.GetChildCount(); i++)
     {
      CXmlElement* child = global.GetChild(i);
      if(child.GetName() == "Strategies")
         ParseStrategies(child,load_curr_symbol);
     }
  }
//+------------------------------------------------------------------+
//| 解析 XML 策略
//+------------------------------------------------------------------+
void CStrategyList::ParseStrategies(CXmlElement *xmlStrategies,bool load_curr_symbol)
  {
   CParamsBase *params=NULL;
   for(int i=0; i<xmlStrategies.GetChildCount(); i++)
     {
      CXmlElement *xStrategy=xmlStrategies.GetChild(i);
      if(CheckPointer(params)!=POINTER_INVALID)
         delete params;
      params=new CParamsBase(xStrategy);
      if(!params.IsValid() || (params.Symbol()!=Symbol() && load_curr_symbol))
         continue;
      CStrategy *str=CStrategy::GetStrategy(params.Name());
      if(str==NULL)
         continue;
      str.ExpertMagic(params.Magic());
      str.ExpertSymbol(params.Symbol());
      str.Timeframe(params.Timeframe());
      str.ExpertName(params.Name());
      string name=str.ExpertName();
      CXmlElement *xml_params=xStrategy.GetChild("Params");
      if(xml_params!=NULL)
         str.ParseXmlParams(xml_params);
      CXmlElement *xml_mm=xStrategy.GetChild("MoneyManagment");
      if(xml_mm!=NULL)
        {
         if(!str.MM.ParseByXml(xml_mm))
           {
            string text="Strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+") load MM from XML failed";
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      CXmlElement *xml_regim=xStrategy.GetChild("TradeStateStart");
      if(xml_regim!=NULL)
        {
         string regim=xml_regim.GetText();
         if(regim=="BuyAndSell")
            str.TradeState(TRADE_BUY_AND_SELL);
         else if(regim=="BuyOnly")
            str.TradeState(TRADE_BUY_ONLY);
         else if(regim=="SellOnly")
            str.TradeState(TRADE_SELL_ONLY);
         else if(regim=="Stop")
            str.TradeState(TRADE_STOP);
         else if(regim=="Wait")
            str.TradeState(TRADE_WAIT);
         else if(regim=="NoNewEntry")
            str.TradeState(TRADE_NO_NEW_ENTRY);
         else
           {
            string text="For strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+
                        ") set not correctly trade state: "+regim;
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      AddStrategy(str);
     }
   if(CheckPointer(params)!=POINTER_INVALID)
      delete params;
  }

此方法最有意思的是,使用特殊的静态方法CStrategy::GetStrategy来创建一个策略。策略的名称应当作为参数传入。方法返回与此名称相对应的一个类的实例。方法被设计为静态的,以便在策略对象创建之前就能够使用。GetStrategy在一个独立的头文件中,因为不同交易引擎的其他部分,你将需要不时的编辑它,向其中添加新的策略。如果你希望从XML中加载策略,它的创建过程必须被直接添加到此方法中。该头文件的源码如下:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "https://www.mql5.com"
/*
   GetStrategy是一个策略制造器。它根据特定的名称创建策略对象。
   为了自动化,该方法在于一个独立的文件中。
*/
#include <Strategy/Strategy.mqh>
#include <Strategy/Samples/MovingAverage.mqh>
#include <Strategy/Samples/ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

一旦策略被创建,应该改用<Params>中的参数对其进行初始化。因为每个策略的参数都是不同的,就不可能在交易引擎层面对这些参数进行初始化。相反,策略的基类嫩巩固调用虚拟方法ParseXmlParams。如果策略重写此方法并且正确的解析XML节点的参数列表,就将能够确定其自身需要的参数值。作为一个例子,来看看基于两根移动平均线的CMovingAverage策略(算法已在第一章中描述过了)的ParseXmlParams方法。

//+------------------------------------------------------------------+
//| 基于两个移动平均线的经典策略样例。
//| 如果快线从下往上穿越慢线
//| — 买入,从上往下穿越 — 卖出。          
//+------------------------------------------------------------------+
class CMovingAverage : public CStrategy
  {
   ...
public:
   virtual bool      ParseXmlParams(CXmlElement *params);
  };
//+------------------------------------------------------------------+
//| 策略参数在重写CStrategy中    
//| 方法的方法内部解析
//+------------------------------------------------------------------+
bool CMovingAverage::ParseXmlParams(CXmlElement *params)
  {
   bool res=true;
   for(int i=0; i<params.GetChildCount(); i++)
     {
      CXmlElement *param=params.GetChild(i);
      string name=param.GetName();
      if(name=="FastMA")
        {
         int fastMA=(int)param.GetText();
         if(fastMA == 0)
           {
            string text="Parameter 'FastMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            FastMA.MaPeriod(fastMA);
        }
      else if(name=="SlowMA")
        {
         int slowMA=(int)param.GetText();
         if(slowMA == 0)
           {
            string text="Parameter 'SlowMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            SlowMA.MaPeriod(slowMA);
        }
      else if(name=="Shift")
        {
         FastMA.MaShift((int)param.GetText());
         SlowMA.MaShift((int)param.GetText());
        }
      else if(name=="Method")
        {
         string smethod=param.GetText();
         ENUM_MA_METHOD method=MODE_SMA;
         if(smethod== "MODE_SMA")
            method = MODE_SMA;
         else if(smethod=="MODE_EMA")
            method=MODE_EMA;
         else if(smethod=="MODE_SMMA")
            method=MODE_SMMA;
         else if(smethod=="MODE_LWMA")
            method=MODE_LWMA;
         else
           {
            string text="Parameter 'Method' must be type of ENUM_MA_METHOD";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.MaMethod(method);
         SlowMA.MaMethod(method);
        }
      else if(name=="AppliedPrice")
        {
         string price=param.GetText();
         ENUM_APPLIED_PRICE a_price=PRICE_CLOSE;
         if(price=="PRICE_CLOSE")
            a_price=PRICE_CLOSE;
         else if(price=="PRICE_OPEN")
            a_price=PRICE_OPEN;
         else if(price=="PRICE_HIGH")
            a_price=PRICE_HIGH;
         else if(price=="PRICE_LOW")
            a_price=PRICE_LOW;
         else if(price=="PRICE_MEDIAN")
            a_price=PRICE_MEDIAN;
         else if(price=="PRICE_TYPICAL")
            a_price=PRICE_TYPICAL;
         else if(price=="PRICE_WEIGHTED")
            a_price=PRICE_WEIGHTED;
         else
           {
            string text="Parameter 'AppliedPrice' must be type of ENUM_APPLIED_PRICE";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.AppliedPrice(a_price);
         SlowMA.AppliedPrice(a_price);
        }
     }
   return res;
  }

该策略的细节在本系列的第三篇文章中消息描述过了,其中还包括自定义策略的开发。

使用从文件中创建策略的机制,可以一次性配置一组策略,然后每次从一个文件中加载它。你甚至可以更进一步,写一个能自行优化的算法,将其最优的参数集保存到一个XML文件中。交易引擎在开始运行时读取该文件,并基于此形成一些列策略。

 

使用自定义面板管理策略

从用户角度来看,应能方便的通过一个特别的自定义面板来控制策略。此面板在EA加载后显示在一个图表上,并将允许对每个交易算法执行简单的操作:

  • 改变策略的交易模式;
  • 买入或卖出期望的头寸大小,而不是由策略决定。

如果EA由于某些原因没有正确执行恰当的操作,后面一个选项就非常有用了,并且你得将其状态和当前市场情况进行同步。

创建自定义面板和对话框类的描述超出了本文讨论的范围,需要另起一篇文章来描述。我们将仅仅描述和面板连接相关的基本概念。

EA控制面板在一个独立的类CPanel中实现,类中包括各种控件,诸如列表,按钮和文本标签。用于创建GUI的所有类都在<数据文件夹>/MQL5/Include/Panel中。为了确保面板的操作,有必要在EA的mq5文件中直接处理OnChartEvent事件。图表事件处理函数在CStrategyList类中,因此可以在OnChartEvent中调用此函数:

CStrategyList Manager;
...

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

CStrategyList中的这些事件处理函数将它们直接发送到面板中。

点击面板中的任何一个按钮,定义了执行何种操作并执行之。例如,如果我们从列表中选择了一个策略,当前策略的索引值将等于选中的这个,然后你可以进行后续交易操作了。比如,你可以通过从下拉列表中选择恰当的策略模式选项,来改变选中策略的交易模式。

图 2. 选定策略的模式列表

图 2. 选定策略的模式列表

代表选定策略的买入和卖出执行起来是一样的。策略的指针调用CStrategy基类的Buy和Sell方法。交易量由传入的参数确定。在这种情况下,执行中的magic数字对应于策略的编号,因此无法区分手动交易还是EA交易。

需要注意的是EA的交易逻辑,所有用户的开仓以一般模式被EA所保持。它管理这类头寸如同管理其自动开仓的头寸一样。

 

以组交易的EA

我们可以创建一个策略组合。策略必须包含解析XML参数的方法,例如,我们要重写 ParseXmlParams 方法。还需要向CStrategy::GetStrategy方法中添加创建正确策略类型的功能。最终我们需要创建一个XML文件,含有策略列表和对应的参数。之后CStrategyList类将创建策略实例并将它们添加到策略列表中。此后自定义面板将显示这些策略。

让我们创建一个包含上述EA的策略组合。解析CMovingAverage和CChannel策略XML设置的例子在3.5和4.3节中提供。

用于创建两个策略的CStrategy::GetStrategy方法的方法体如下:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "https://www.mql5.com"
/*
   GetStrategy是一个策略制造器。它根据特定的名称创建策略对象。
   为了自动化,该方法在于一个独立的文件中。
*/
#include <Strategy/Strategy.mqh>
#include <Strategy/Samples/MovingAverage.mqh>
#include <Strategy/Samples/ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

最后是重写用于EA全名的函数。为 CMovingAverage 策略进行重写:

//+------------------------------------------------------------------+
//|  EA的全称
//+------------------------------------------------------------------+
string CMovingAverage::ExpertNameFull(void)
  {
   string name=ExpertName();
   name += "[" + ExpertSymbol();
   name += "-" + StringSubstr(EnumToString(Timeframe()), 7);
   name += "-" + (string)FastMA.MaPeriod();
   name += "-" + (string)SlowMA.MaPeriod();
   name += "-" + StringSubstr(EnumToString(SlowMA.MaMethod()), 5);
   name += "]";
   return name;
  }

现在一切就绪,可以创建策略组合了。我们的组合将包含四个交易系统。每一个都在其自身加载的货币对上进行交易。两个处理基于移动平均,另外两个基于布林带。这些策略更为详细的描述在先前的文章:“通用智能交易系统:自定义策略和辅助交易类(第三章)”中介绍过了。

我们的XML组合如下:

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>30</Period>
                                <StdDev>1.5</StdDev>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="103" Timeframe="PERIOD_M30" Symbol="ED">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>20</Period>
                                <StdDev>2.0</StdDev>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

此文件Strategies.xml应该保存在MetaTrader平台的公用数据文件夹中。

这里是创建一个EA的mq5模块源代码:

//+------------------------------------------------------------------+
//|                                                       Expert.mq5 |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Strategy/StrategiesList.mqh>

CStrategyList Manager;
//+------------------------------------------------------------------+
//| EA初始化函数             
//+------------------------------------------------------------------+
int OnInit()
  {
   Manager.LoadStrategiesFromXML(StrategiesXMLFile,LoadOnlyCurrentSymbol);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| EA反初始化函数                                       
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//|  EA的tick函数            
//+------------------------------------------------------------------+
void OnTick()
  {
   Manager.OnTick();
  }
//+------------------------------------------------------------------+
//| BookEvent 函数                
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   Manager.OnBookEvent(symbol);
  }

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

自定义变量StrategiesXMLFileLoadOnlyCurrentSymbol在CStrategyList类中定义。它们在这个类中使用,用于指定加载的策略列表以及模式(是否仅允许加载同EA所运行图表名称一致的策略)。还要注意一些事件,诸如 OnBookEvent 和 OnTimer,没有被使用。这意味着它们不会被用于自定义策略。

编译应该能够成功。之后,EA(项目中的名称为 Agent.ex5)就可以使用了。让我们在图标上运行它。在此之前,我们必须确保所有被用到的货币对在 MetaTrader Market Watch 中可用。成功启动之后,EA的图标会出现在图表右上角。另一个按钮被添加到图表的左上角:它用于最大化自定义面板。如果我们在面板上选择EA(Agent)列表,将打开四个EA列表:

图 3. 已加载EA的列表

图 3. 已加载EA的列表

截图显示了由我们的 Strategies.xml文件创建的EA列表。过一会儿之后,策略开始交易 — 每一个策略独立运行于自己的货币对上。

 

在策略测试器中分析EA的效果

在生成一个策略组合之后,我们可以在策略测试器中对其运行效果进行测试。无需额外的操作,因为XML策略列表位于全局数据文件夹下,策略测试器能够访问。当在其中加载Agent.ex5 EA 模块后,所需的货币对会被自动加载。每个EA会根据其自身的交易逻辑运行,并且将独立绘制其含有的指标集。下面的视频展示了在四个不同的标的上测试策略组合的例子:

在策略测试器中,基于CStrategy的策略仿真同使用这些策略进行实际交易类似。可视化测试选项使你能够方便的检查策略进场和出场的准确性。

 

总结

我们已经考虑了可以创建任意交易策略集的算法。有了这些策略集或策略组合,当在同一个执行模块中管理多个交易策略时,你可以灵活有效的控制交易过程。这种算法对于使用多货币对作为交易对象的策略特别有用。使用所提出的方法,创建类似的交易算法就像开发传统交易策略一样简单。

本文译自 MetaQuotes Software Corp. 撰写的俄文原文
原文地址: https://www.mql5.com/ru/articles/2179

附加的文件 |

strategyarticle.zip
(85.76 KB)

 

 


MyFxtop迈投-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投