外汇EA编写教程:使用信号指标的简单交易系统

简介

信号指标是指明入市出市时机的简单探测器。如果当前柱有一个入市信号,则交易品种图表上会出现相应的标签。而此标签之后可用作执行某交易的一个条件。

此类的指标纷繁复杂,但基于此类指标的原创交易系统的本质精髓却根本没有变化。因此,以最简单且通用的形式来实现,是个很好的想法。如此一来,在使用任何无重大变动的类似指标时,就能够更进一步地使用已获得的结果。

图 1. ASCtrend 信号指标

图 1. ASCtrend 信号指标

图 2. ASCtrend 指标。执行某交易的交易信号

图 2. 利用 ASCtrend 信号指标执行某交易的交易信号

典型信号指标示例

代码基中当前存在大量的此类指标。本文中,我只提供几个到相应网页的链接:

除信号指标外,还存在一组信号趋势指标:

图 3. 采用 Heiken_Ashi_Smoothed 指标的交易信号

图 3. 信号趋势指标

 

图 4. 利用 Heiken Ashi Smoothed 信号趋势指标执行某交易的交易信号

图 4. 利用 Heiken Ashi Smoothed 信号趋势指标执行某交易的交易信号

采用此类指标的交易系统获取交易信号的代码略有不同,而“EA 交易”代码则几乎未变。

典型信号趋势指标示例

代码基中包含大量此类指标。本文中,我只提供几个到相应网页的链接:

 

创建一个交易系统的基础数据:

  1. 带有将于“EA 交易”中出现的输入参数的信号指标;
  2. 附加输入“EA 交易”交易参数列表:
    • 交易中使用的存款金融资源份额;
    • 止损和获利额度(零值情况下不得使用挂单);
    • 最大允许滑点数(定价与实际成交价间允许的最大差异);
    • 柱指数,由此接收交易信号;
    • 买入持仓与卖出持仓许可权限;
    • 根据指标信号强行进行买入持仓和卖出持仓平仓的许可权限。

当然,利用通用交易函数下令执行交易会方便得多。此类函数非常复杂,应将其打包成为一个独立的库文件,从而让应用代码尽可能地简单。

“EA 交易”实现信号交易系统的代码:

//+------------------------------------------------------------------+
//|                                                 Exp_ASCtrend.mq5 |
//|                             Copyright © 2011,   Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2011, Nikolay Kositsin"
#property link      "farria@mail.redcom.ru"
#property version   "1.00"
//+----------------------------------------------+
//|  EA交易系统指标输入参数                         |
//+----------------------------------------------+
input double MM=-0.1;             // 一笔交易使用的入金,负值 - 交易量大小
input int    StopLoss_=1000;      // 止损点数
input int    TakeProfit_=2000;    // 获利点数
input int    Deviation_=10;       // 最大价格滑点数 
input bool   BuyPosOpen=true;     // 允许买入
input bool   SellPosOpen=true;    // 允许卖出
input bool   BuyPosClose=true;    // 允许退出买入持仓
input bool   SellPosClose=true;   // 允许退出卖出持仓
//+----------------------------------------------+
//| ASCtrend 指标输入参数                          |
//+----------------------------------------------+
input ENUM_TIMEFRAMES InpInd_Timeframe=PERIOD_H1; // ASCtrend 指标的时间框架
input int  RISK=4;                               // 风险水平
input uint SignalBar=1;                          // 获取入场信号的柱形索引
//+----------------------------------------------+

int TimeShiftSec;
//---- 为指标句柄声明整型变量
int InpInd_Handle;
//---- 声明开始计算数据的整型变量
int min_rates_total;
//+------------------------------------------------------------------+
//| 交易算法                                                          | 
//+------------------------------------------------------------------+
#include <TradeAlgorithms.mqh>
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- 获取 ASCtrend 指标句柄
   InpInd_Handle=iCustom(Symbol(),InpInd_Timeframe,"ASCtrend",RISK);
   if(InpInd_Handle==INVALID_HANDLE) Print(" Failed to get handle of ASCtrend indicator");

//---- 初始化以秒的形式存储图表周期的变量  
   TimeShiftSec=PeriodSeconds(InpInd_Timeframe);

//---- 初始化开始计算数据的变量
   min_rates_total=int(3+RISK*2+SignalBar);
//----
   return(0);
  
}
//+------------------------------------------------------------------+
//| EA交易去初始化函数                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//----
   GlobalVariableDel_(Symbol());
//----
  
}
//+------------------------------------------------------------------+
//| EA的订单函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
//---- 检查用于计算的柱形数量是否足够
   if(BarsCalculated(InpInd_Handle)<min_rates_total) return;
   
//---- 为IsNewBar()和SeriesInfoInteger()函数的正常运行,加载历史数据  
   LoadHistory(TimeCurrent()-PeriodSeconds(InpInd_Timeframe)-1,Symbol(),InpInd_Timeframe);

//---- 本地变量声明
   double DnVelue[1],UpVelue[1];
//----静态变量声明
   static bool Recount=true;
   static bool BUY_Open=false,BUY_Close=false;
   static bool SELL_Open=false,SELL_Close=false;
   static datetime UpSignalTime,DnSignalTime;
   static CIsNewBar NB;

//+----------------------------------------------+
//| 搜索交易执行信号                               |
//+----------------------------------------------+
   if(!SignalBar || NB.IsNewBar(Symbol(),InpInd_Timeframe) || Recount) // 检查新的柱形
     {
      //---- 交易信号清零
      BUY_Open=false;
      SELL_Open=false;
      BUY_Close=false;
      SELL_Close=false;
      Recount=false;

      //---- 将新数据复制到数组中
      if(CopyBuffer(InpInd_Handle,1,SignalBar,1,UpVelue)<=0) {Recount=true; return;}
      if(CopyBuffer(InpInd_Handle,0,SignalBar,1,DnVelue)<=0) {Recount=true; return;}

      //---- 获取买入信号
      if(UpVelue[0] && UpVelue[0]!=EMPTY_VALUE)
        {
         if(BuyPosOpen) BUY_Open=true;
         if(SellPosClose) SELL_Close=true;
         UpSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        
}

      //---- 获取卖出信号
      if(DnVelue[0] && DnVelue[0]!=EMPTY_VALUE)
        {
         if(SellPosOpen) SELL_Open=true;
         if(BuyPosClose) BUY_Close=true;
         DnSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        
}

      //---- 为获取持仓平仓信号,查找最近一笔交易的方向
      //if(!MQL5InfoInteger(MQL5_TESTING) && !MQL5InfoInteger(MQL5_OPTIMIZATION)) //如果执行方式在策略测试器中被设置为“随机延迟” 
      if((BuyPosOpen && BuyPosClose || SellPosOpen && SellPosClose) && (!BUY_Close && !SELL_Close))
        {
         int Bars_=Bars(Symbol(),InpInd_Timeframe);

         for(int bar=int(SignalBar+1); bar<Bars_; bar++)
           {
            if(SellPosClose)
              {
               if(CopyBuffer(InpInd_Handle,1,bar,1,UpVelue)<=0) {Recount=true; return;}
               if(UpVelue[0]!=0 && UpVelue[0]!=EMPTY_VALUE)
                 {
                  SELL_Close=true;
                  break;
                 
}
              
}

            if(BuyPosClose)
              {
               if(CopyBuffer(InpInd_Handle,0,bar,1,DnVelue)<=0) {Recount=true; return;}
               if(DnVelue[0]!=0 && DnVelue[0]!=EMPTY_VALUE)
                 {
                  BUY_Close=true;
                  break;
                
}
              
}
           
}
        
}
     
}

//+----------------------------------------------+
//| 执行交易                                      |
//+----------------------------------------------+
//---- 平买入持仓
   BuyPositionClose(BUY_Close,Symbol(),Deviation_);

//---- 平卖出持仓   
   SellPositionClose(SELL_Close,Symbol(),Deviation_);

//---- 买入
   BuyPositionOpen(BUY_Open,Symbol(),UpSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);

//---- 卖出
   SellPositionOpen(SELL_Open,Symbol(),DnSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);
//----
  
}
//+------------------------------------------------------------------+

尽管还有一些细节应予澄清,但实现这样一种理念的代码确实非常简单且清晰。

信号指标与“EA 交易”使用的图表时段,于“EA 交易”的 InpInd_Timeframe 输入变量中被修复。因此,图表的变动、“EA 交易”所处的位置,都不会改变“EA 交易”的这个参数。

确定新柱抵达时机所需的 IsNewBar() 函数,被实现为置于 TradeAlgorithms.mqh 文件中的一个类。如此则能轻松使用代码中任意数量的此类函数 – 为其中的每一个设置一个个体静态 CIsNewBar 变量。

UpSignalTime与DnSignalTime 变量用于存储并将时间(在此时间之后,方可继前一个交易之后执行下一个交易)传递给交易函数。在本例中,此功能用于避免于同柱同方向中执行多次交易(执行交易时,交易函数会存储当前柱的结束时间,且于同方向该时机到来之前不会执行新交易)。

OnTick() 函数中的“搜索上一个交易方向以获取平仓信号”块,是那些不含交易信号的柱接收平仓信号之所必需。在某“EA 交易”正常运行的情况下,则不需要它们。但如果是互联网连接故障,则极有可能错失某个新的交易信号。要进入事后市场,几乎没有什么好主意,但关闭持仓却不失为一个明智之举。

使用带有其它信号指标的交易系统

现在,如果有必要使用带有另一种信号指标的此代码,则应执行下述动作:

  1. 利用“EA 交易”输入参数中新数据的必需参数,替换之前的指标数据;
  2. 更改于 OnInit() 块中获取指标名柄的代码;
  3. 确定指标缓冲区指数 – 用于存储源自指标代码的买卖交易信号 – 并妥善地输入 OnTick() 块的 CopyBuffer() 函数调用集。本例中采用的是零和第一指标缓冲区;
  4. 根据指标代码,更改“EA 交易”中数据计算初始化起点变量 (min_rates_total);
  5. 根据指标代码更改OnTick()函数中的“搜索上一个交易方向以获取平仓信号”块。

使用带有其它信号趋势指标的交易系统

使用这个带有信号趋势指标的交易系统时,已于确定OnTick()函数交易信号的块中对“EA 交易”代码做出了些微更改。比如说,基于 FiboCandles 指标的“EA 交易”代码可能如下:

//+------------------------------------------------------------------+
//| EA的订单函数                                                      |
//+------------------------------------------------------------------+
void OnTick()
  {
//---- 检查用于计算的柱形数量是否足够
   if(BarsCalculated(InpInd_Handle)<min_rates_total) return;
   
//---- 为IsNewBar()和SeriesInfoInteger()函数的正常运行加载历史数据
   LoadHistory(TimeCurrent()-PeriodSeconds(InpInd_Timeframe)-1,Symbol(),InpInd_Timeframe);

//---- 本地变量声明
   double TrendVelue[2];
//----静态变量声明
   static bool Recount=true;
   static bool BUY_Open=false,BUY_Close=false;
   static bool SELL_Open=false,SELL_Close=false;
   static datetime UpSignalTime,DnSignalTime;
   static CIsNewBar NB;

//+----------------------------------------------+
//| 搜索交易执行信号                               |
//+----------------------------------------------+
   if(!SignalBar || NB.IsNewBar(Symbol(),InpInd_Timeframe) || Recount) // 检查新的柱形
     {
      //---- 交易信号清零
      BUY_Open=false;
      SELL_Open=false;
      BUY_Close=false;
      SELL_Close=false;
      Recount=false;

      //---- 将新获取到的数据复制到数组中
      if(CopyBuffer(InpInd_Handle,4,SignalBar,2,TrendVelue)<=0) {Recount=true; return;}

      //---- 获取买入信号
      if(TrendVelue[0]==1 && TrendVelue[1]==0)
        {
         if(BuyPosOpen) BUY_Open=true;
         if(SellPosClose)SELL_Close=true;
         UpSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        
}

      //---- 获取卖出信号
      if(TrendVelue[0]==0 && TrendVelue[1]==1)
        {
         if(SellPosOpen) SELL_Open=true;
         if(BuyPosClose) BUY_Close=true;
         DnSignalTime=datetime(SeriesInfoInteger(Symbol(),InpInd_Timeframe,SERIES_LASTBAR_DATE))+TimeShiftSec;
        
}

      //---- 为获取持仓平仓信号,查找最近一笔交易的方向
      //if(!MQL5InfoInteger(MQL5_TESTING) && !MQL5InfoInteger(MQL5_OPTIMIZATION)) //<s1如果执行方式在策略测试器中被设置为“随机延迟” 
        {
         if(SellPosOpen && SellPosClose  &&  TrendVelue[1]==0) SELL_Close=true;
         if(BuyPosOpen  &&  BuyPosClose  &&  TrendVelue[1]==1) BUY_Close=true;
        
}
     
}

//+----------------------------------------------+
//| 执行交易                                      |
//+----------------------------------------------+
//---- 平买入持仓
   BuyPositionClose(BUY_Close,Symbol(),Deviation_);

//---- 平卖出持仓   
   SellPositionClose(SELL_Close,Symbol(),Deviation_);

//---- 买入
   BuyPositionOpen(BUY_Open,Symbol(),UpSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);

//---- 卖出
   SellPositionOpen(SELL_Open,Symbol(),DnSignalTime,MM,0,Deviation_,StopLoss_,TakeProfit_);
//----
  
}

本例中,交易信号只由一个颜色指标缓冲区(包含颜色指数)接收。此缓冲区内的数据只有两个值:0 – 针对上升市场,以及 1 – 针对下滑市场。“搜索上一个交易方向以获取平仓信号”块代码已最大程度的简单化,因为任何柱的趋势方向都可以从指标缓冲区的相应单元直接接收。

在“执行交易”块,平仓函数先行,然后是开仓函数。如是相反的顺序,则可能只是关闭了一个柱上的交易,您将不能在 “Open prices only” (仅开盘价)模式下同时打开它们!因此,交易结果会遭到严重破坏。

交易系统测试

在前往交易系统测试之前,有一个重要细节应予澄清。如果SignalBar输入变量值等于零,则“EA 交易”会从当前柱获取交易执行信号。但是,在指示趋势(与前柱此信号反向)的变动方面,当前柱信号并不可靠。当前柱上的信号会出现和消失,同时趋势又会向着此类信号的相反方向移动很长一段时间。如根据所有订单号测试“EA 交易”,启用可视化且 SignalBar 变量等于零,则很容易看到这一点。ASCtrend 指标运行可视化为此类情况下的这一事实提供了一个非常明确的证据。

再说一次,只有 “Every tick” (每一订单号)模式适用于利用某种从当前柱接收到的信号进行优化的“EA 交易”。如果要从已经关闭的任何其它柱接收,则 “Open prices only” (仅开仓价)模式足以胜任。如此则极大地加快了交易系统行为分析的速度,而且质量无任何重大损失。

因此,最好不要使用源自当前柱的信号实施此类交易系统的测试和优化!

那么,我们利用 EUR/USD 上的默认参数,执行“EA 交易”从年初到 12 月初的测试:

图 5. 利用 EUR/USD H1 上的默认参数测试 Exp_ASCtrend “EA 交易”的结果

图 5. 利用 EUR/USD H1 上的默认参数测试 Exp_ASCtrend “EA 交易”的结果

在对策略测试仪中的“EA 交易”参数完成些微更改之后,我们就能非常轻松地找到“EA 交易”参数针对现有历史数据最适当的组合:

 图 6. 利用 EUR/USD H1 上的更好参数优化 Exp_ASCtrend “EA 交易”之后的测试结果

图 6. 利用 EUR/USD H1 上的更好参数优化 Exp_ASCtrend “EA 交易”之后的测试结果

交易系统优化的过程并无任何独特之处,正因如此,我只提供一个通往详细讲述此过程的文章的链接:”MQL5:利用 MQL5 测试与优化‘EA 交易’指南”。

当然,想通过这么一种简单的交易系统就能获得多大的利润是不现实的。但是,如果能够熟练运用这个半自动的系统,并定期根据市场的当前状态进行调整,则还是很有可能达成良好结果的。

比如说,从 2011 年 1 月到 5 月,EUR/USD H12 图表上呈上升趋势。而且于早期阶段即可轻松检测得到:

图 7. EUR/USD H12 图表(2011 年 1-5 月)

图 7. EUR/USD H12 图表(2011 年 1-5 月)

利用默认设置、以这种时间间隔来测试“EA 交易”也会很有趣,只买入及使用 5% 入金的可能性 (MM=0.05)。 此为利用此类参数于 H1 图表上测试“EA 交易”的结果:

图 8. 利用默认参数于 EUR/USD H1 上测试 2011 年 1-5 月 Exp_ASCtrend “EA 交易”的结果(仅买入持仓,MM=0.05)

图 8. 利用默认参数于 EUR/USD H1 上测试 2011 年 1-5 月 Exp_ASCtrend “EA 交易”的结果(仅买入持仓,MM=0.05)

当然,本例中是由交易商全权负责选择交易方向。但是,只要我们牢记应使用大型时间表图表来完成,即会所向披靡。

搭配另一指标使用的交易模块的修改

本文本应到此结束,但是 MetaEditor 又增加了基于即用型交易模块生成“EA 交易”的可能性创建此类模块的过程要考虑到此处所述的所有材料,非常复杂,需要单独研究。因此,我会将重点放在已经创建的、与我曾建议的交易系统完全类似的交易模块上。之后,我还会根据具体的信号指标(且避免不必要的细节程度),继续讲解上述模块修改的详情。

我们假定现在已经拥有信号系统交易模块的集合(MySignals.zip),而且想要创建针对任何特定货票的类似模块。令其成为 BykovTrendSignal.mq5 指标 – 一种典型的信号指标。首先,我们应从此集中找到该指标最准确的类似模块 (Indicators.zip)。我们通过观察确定本文中的第一个指标 (ASCtrend) 与其最为相似。 因此,我们会使用此指标的交易模块进行修改。

鉴于其在目标程序代码中的使用,此指标本身 (BykovTrend) 亦有一组输入参数:

//+----------------------------------------------+
//| 指标输入参数                                   |
//+----------------------------------------------+
input int RISK=3;
input int SSP=9;
//+----------------------------------------------+

而且,我们需要利用指标缓冲区指数存储执行交易的信号。本例中为:0 – 卖出信号,及 1 – 买入信号。

现在,我们知道了应该用哪类模块进行修改,我们从 /MQL5/Include/Expert/Signal/MySignals/ 文件夹中复制出名为 BykovTrendSignal.mqh 的文件,然后再用 MetaEditor 打开。用过的代码中有一个经常碰到的表达式”ASCtrend”(之前的指标名称)。应替换为新指标的名称 – “BykovTrend”。想完成此操作,则同时按下 “Ctrl” 与 “H” 键,并做出必要的改动:

 替换交易模块代码中的指标名称

图 9. 替换交易模块代码中的指标名称

我们下一阶段的工作最为严谨。我们必须替换交易模块代码中与指标输入参数相关的一切内容。此过程与“MQL5 向导:如何创建一个交易信号模块”一文中所述非常相似。

首先,我们应在 MQL5 向导交易信号类描述被注释掉的块中做出一些改动:

//+----------------------------------------------------------------------+
//| 声明类                                                                |
//| 标题=基于BykovTrend指标的信号                                           |
//| 类型=SignalAdvanced                                                   |
//| 名称=BykovTrend                                                       |
//| 类=CBykovTrendSignal                                                  |
//| 页面=                                                                 |
//| 参数=BuyPosOpen,bool,true,允许买入                                     |
//| 参数=SellPosOpen,bool,true,允许卖出                                    |
//| 参数=BuyPosClose,bool,true,允许退出买入持仓                             |
//| 参数=SellPosClose,bool,true,允许退出卖出持仓                            |
//| 参数=Ind_Timeframe,ENUM_TIMEFRAMES,PERIOD_H1,时间框架                  |
//| 参数=RISK,int,4,风险水平                                               |
//| 参数=SSP,int,9,SSP                                                    |
//| 参数=SignalBar,uint,1,入场信号的柱形索引                                |
//+----------------------------------------------------------------------+
//--- 向导描述结束
//+----------------------------------------------------------------------+
//| CBykovTrendSignal 类                                                 |
//| 目的: 基于BykovTrend指标生成交易信号的类                                 |
//| BykovTrend 指标 https://www.mql5.com/zh/code/497/                      |
//|             从CExpertSignal类衍生出来                                  |
//+----------------------------------------------------------------------+

两个指标包含的RISK输入变量相同,因此可将其保留。但两个指标中的默认值却不同。实际上,这种差异并不重要,可以不予改动。有关 SSP 变量的注释行已经添加:

//| 参数=SSP,int,9,SSP                                    |

而且至“代码基”指标的链接亦已替换:

//| 目的:基于BykovTrend指标生成交易信号的类                   |
//| BykovTrend值 https://www.mql5.com/zh/code/497/.        |

现在,与输入参数变更相关的所有内容,均应体现于CBykovTrendSignal交易信号类的描述当中。我们已在设置参数中声明了新全局 global m_SSP类变量行:

   uint              m_SSP;              // SSP

 以及新SSP()设置参数安装方法行声明:

   void               SSP(uint value)                         { m_SSP=value;              } 

与我们创建的交易信号模块中RISK输入变量相关的一切内容,均等同于该输入模块,因此,当前及任何其它交易模块区块中均无变动。

现在,我们着手讨论 CBykovTrendSignal::CBykovTrendSignal()类构造函数。新变量的初始化应添加到此区段中:

   m_SSP=4;

检查新变量是否正确,应于 CBykovTrendSignal::ValidationSettings()设置参数验证块中执行:

   if(m_SSP<=0)
     {
      printf(__FUNCTION__+": SSP must be above zero");
      return(false);
     
}

此后,我们可继续研究 BykovTrend 指标初始化块 – BykovTrendSignal::InitBykovTrend()。此新指标拥有的输入变量数目有所不同,因此,声明的输入参数数组的尺寸亦会有所区别:

//--- 设置指标参数
   MqlParam parameters[3];

本例中,我们需要一个指标字符串名称尺寸,还有其输入参数的两个尺寸。

现在,我们必须初始化输入参数数组的一个新单元,指明将存储其中的变量类型:

   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_SSP;

 然后,将此区块中调用指标初始化的输入变量数目改为 3:

//--- 对象初始化   
   if(!m_indicator.Create(m_symbol.Name(),m_Ind_Timeframe,IND_CUSTOM,3,parameters))

指标中指标缓冲区的数目仍保持不变或等同于2,因此,本例中不需要更改指标缓冲区数目初始化行中的任何内容。

//--- 缓存数量
   if(!m_indicator.NumBuffers(2))  return(false);

ASCtrend与BykovTrend两个指标中的每一个,都拥有两个指标缓冲区。而缓冲区的函数则完全一致。零缓冲区用于存储卖出信号,而指数为1的缓冲区则用于存储买入信号。所以,传递CBykovTrendSignal::LongCondition()和 CBykovTrendSignal::ShortCondition() 交易信号的函数模块中无需任何改动,而交易信号模块修改方面的工作亦可视为已完成。

但总体而言,所有信号指标都有差异,因此,不同信号指标的此类区块之间可能存在着相当大的差别。MySignals.zip 交易模块存档与相应的 Indicators.zip 存档中都包含着创建各种指标的足量示例。检查几次之后,即有可能找到替换过程的细节,以及可能的相应代码版本。

现在,我想将重点放在交易信号模块的 Ind_Timeframe 输入变量上。此变量允许将某个适用的时间表下载到指标。但是,生成的“EA交易”却会根据其被指定的时间表运行。也就是说,Ind_Timeframe 输入变量时间表永远不得超过“EA 交易”运行所赖之图表时段,才能让模块正常运行。

最后,我想告诉大家创建交易信号模块的另一个独特性。自定义枚举有时是在基本指标代码中作为模块输入变量类型实现的。比如说,Smooth_Method自定义枚举就被用作 Candles_Smoothed 指标的 MA_SMethod 变量类型:

//+-----------------------------------+
//|  声明枚举类型                       |
//+-----------------------------------+
enum Smooth_Method
  {
   MODE_SMA_,  // SMA
   MODE_EMA_,  // EMA
   MODE_SMMA_, // SMMA
   MODE_LWMA_, // LWMA
   MODE_JJMA,  // JJMA
   MODE_JurX,  // JurX
   MODE_ParMA, // ParMA
   MODE_T3,    // T3
   MODE_VIDYA, // VIDYA
   MODE_AMA,   // AMA
  }; */
//+----------------------------------------------+
//| 指标输入参数                                   |
//+----------------------------------------------+
input Smooth_Method MA_SMethod=MODE_LWMA; // 平滑方式
input int MA_Length=30;                   // 平滑深度                    
input int MA_Phase=100;                   // 平滑参数
                                          // 对于JJMA它在 -100 ... +100之间变化,
                                          //对于VIDIA而言,它是CMO周期,对于AMA而言,它是慢速平均周期
//+----------------------------------------------+

此类情况下,该类别的输入变量和交易信号模块中的所有相关元素(Candles_SmoothedSignal.mqh),均应在 int 和 uint 类型变量中进行修改。而且,亦应执行直至“EA 交易”输入函数及必要输入变量类型(ExpM_Candles_Smoothed Expert Advisor) 的反向自定义枚举流程,以方便此输入变量在成品“EA 交易”已经生成的代码中的使用。

//+------------------------------------------------------------------+
//|  声明枚举类型                                                      |
//+------------------------------------------------------------------+
enum Smooth_Method
  {
   MODE_SMA_,  // SMA
   MODE_EMA_,  // EMA
   MODE_SMMA_, // SMMA
   MODE_LWMA_, // LWMA
   MODE_JJMA,  // JJMA
   MODE_JurX,  // JurX
   MODE_ParMA, // ParMA
   MODE_T3,    // T3
   MODE_VIDYA, // VIDYA
   MODE_AMA,   // AMA
  };
//+------------------------------------------------------------------+
//| 输入参数                                                          |
//+------------------------------------------------------------------+
//--- EA的输入参数
input string          Expert_Title         ="Candles_Smoothed"; // 文件名
ulong                 Expert_MagicNumber   =29976;              // 
bool                  Expert_EveryTick     =false;              // 
//--- 主要型号的输入参数
input int             Signal_ThresholdOpen =40;                 // 开仓信号阈值 [0...100]
input int             Signal_ThresholdClose=20;                 // 平仓信号的阈值 [0...100]
input double          Signal_PriceLevel    =0.0;                // 执行交易的价格水平
input double          Signal_StopLevel     =50.0;               // 止损水平(点数)
input double          Signal_TakeLevel     =50.0;               // 获利水平(点数)
input int             Signal_Expiration    =1;                  // 挂单到期时间(以柱形计)
input bool            Signal__BuyPosOpen   =true;               // Candles_Smoothed() 允许买入
input bool            Signal__SellPosOpen  =true;               // Candles_Smoothed() 允许卖出
input bool            Signal__BuyPosClose  =true;               // Candles_Smoothed()允许退出买入持仓
input bool            Signal__SellPosClose =true;               // Candles_Smoothed() 允许退出卖出持仓
input ENUM_TIMEFRAMES Signal__Ind_Timeframe=PERIOD_H1;            // Candles_Smoothed() 时间框架
input Smooth_Method   Signal__MA_SMethod   =4;                  // Candles_Smoothed() 平滑方式 (1 - 10)
input uint            Signal__MA_Length    =30;                 // Candles_Smoothed() 平滑深度
input uint            Signal__MA_Phase     =100;                // Candles_Smoothed() 平滑参数
input uint            Signal__SignalBar    =1;                  // Candles_Smoothed() 入场信号的柱形索引
input double          Signal__Weight       =1.0;                // Candles_Smoothed() 权重 [0...1.0]
//--- 用于资金管理的输入参数
input double          Money_FixLot_Percent =10.0;               // 百分比
input double          Money_FixLot_Lots    =0.1;                // 固定持仓

本例中是利用 Signal__MA_SMethod 输入变量来完成。

如果您在编辑器中将两个代码版本(ASCtrendSignal.mqh 与 BykovTrendSignal.mqh)都同时打开(一个放在左侧,另一个在右侧),并仔细对比两个代码版本,即可大幅提高代码修改的速度。

总结

我已于本文随附的 Experts.zip 存档中放入了基于信号交易系统的足量“EA 交易”示例,从而让“EA 交易”的新手创建人员能够轻松掌握编写此类代码的所有功能,或者至少也能使用那些采用非常流行的指标的即用型“EA 交易”。

所有随附的“EA 交易”示例,还都会作为交易模块呈现,提供给那些想利用交易策略生成器作为其自用交易系统基础的人们。上述模块均位于 MySignals.zip 中,而基于它们的交易系统则位于 Expertsez.zip 中。“EA 交易”中使用的指标放在 Indicators.zip 中。文件的解压路径如下:

  • Experts.zip:”/MQL5/Experts/”;
  • Expertsez.zip:”/MQL5/Experts/”; 
  • MySignals.zip:”/MQL5/Include/Expert/Signal/MySignals/”; 
  • Indicators.zip:”/MQL5/Indicators/”;
  • SmoothAlgorithms.mqh:”/Include/”;
  • TradeAlgorithms.mqh:”/Include/”.

重启MetaEditor,打开Navigator窗口,右键点击MQL5标签,并在弹出菜单中选择 “Compile”。

SmoothAlgorithms.mqh是Indicators.zip中某些指标编译的必需文件,而 TradeAlgorithms.mqh 则是 Experts.zip 中所有“EA 交易”编译的必需文件。

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

附加的文件 |

expertsez.zip
(31.51 KB)
mysignals.zip
(44.08 KB)
indicators.zip
(39.15 KB)
experts__1.zip
(42.23 KB)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

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

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

風險提示

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

邁投公眾號

聯繫我們

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

MyFxtops 邁投