期货量化交易软件:同时双向工作的通用 RSI 指标

简介

当开发交易算法时,我们几乎总是会遇到一个难题:如何确定趋势/盘整在哪里开始和结束? 很难找到一个完美的解决方案。这个目标看起来可以通过把基于趋势和基于盘整的策略组合为一个算法来实现。在本文中,赫兹量化交易软件将会创建一个通用的指标,它将组合来自不同类型策略的信号。赫兹量化软件将会尝试在 EA 中尽可能简化交易信号的生成,并将给出一个把几个指标组合为一的实例。这可以通过使用面向对象编程来做到,每个指标或者它的一部分以类的形式包含在主程序文件中。 

所以,这里的任务是写一个 EA 交易来组合两个交易策略:一个用于趋势交易,另一个用于盘整时期。我们假定,同时双向交易更加高效,并且这样的策略将更加稳定,那么在一个EA交易中只包含一个指标将更加方便,而这个指标将生成两种策略类型的信号。在其中,您可以实现一个复杂的系统,用于判断买入和卖出信号。可能需要在其中组合几个使用不同设置的相同指标成为一体,或者在指标中包含两个不同的:主指标和过滤指标(辅助)。使用OOP(面向对象编程)来实现这样的架构非常方便。

下面的框架显示了在主指标文件(Indicator.mq5)中包含两个指标类 (CIndicator1 和 CIndicator2),CIndicator2 是一个辅助指标,它的计算结果是 CIndicator1 所需要的。在此,赫兹量化交易软件使用了之前在关于创建多交易品种指标的文章关于创建多交易品种指标的文章 中确定真实柱形的方法,为这篇文章赫兹量化交易软件写了一个独立的 CFirstTrueBar 类。它将包含于所有的指标中,以避免在不属于当前时段的柱上进行计算。

图 1. 一个可行的使用 OOP 创建指标的框架

选择指标

任何来自于标准终端分发包的指标都可以选择用来生成信号,它们中的大部分都有一个类似的思路,作为规则,它们中的任何一个都不优先于其它的指标。一些指标与过滤器的组合在某些时间段有效,而其他的可能在不同的时间段有效,

但是为了研究方便,最好是选择振荡器类型的指标,它们在有趋势和盘整的时候都可以用于确定信号。振荡器的数据也可以用于绘制价格通道,这样,赫兹量化交易软件就可以创建一个通用指标,在开发任何复杂度的交易策略时都很方便。

在本系列文章中,我们将使用 RSI (相对强弱指数,Relative Strength Index) 指标作为实例。下面是这个指标在周期数为8的 AUDUSD H1 图表上计算的结果。 

图 2. 相对强弱指数指标

最初看来,很容易根据这个指标的信号来获取利润,但这是一种错觉。在你达到下一步的大致理解之前,需要做大量的工作。同时,还无法保证能够达到你的目标。 

考虑最简单和明显的例子: 我们相信指标线在与默认水平交叉的时候会有利润: 70/30. 如果向下与 70 水平线交叉,它是个卖出信号。如果向上与 30 水平线交叉,它是个买入信号。但是,我们看到很多错误信号,价格走向了持仓相反的方向。 

这里是另一个使用这个指标分析信号的例子 (参见图3). 我们看到,价格下跌了很长时间,红色线标记了指标向上与30水平交叉所构成的信号,如果您的算法包含了根据这些信号来买入,您将会得到浮动的回撤,如果您每次都设置了止损,就会产生好几次亏损。同时,从最后一次买入信号到出现卖出信号(绿色线)价格都没有达到正的结果,您的结果就是亏损。另外,这段图表会建议跟随趋势进行交易,也就表示我们没有看到任何不确定的因素。

当使用任何指标时都会遇到类似的问题,所以,将来赫兹量化交易软件选择什么指标并没有关系。

图 3. RSI 指标的信号

修改 RSI 指标

应该在选定的指标中加入功能,使它能更加方便地在 EA 交易中使用,我们创建了5个版本的 RSI,按顺序从简单到复杂(以便容易理解)。

第一版. 加上信号缓冲区

标准版本的 RSI 位于终端的 \MQL5\Indicators\Examples 目录下,让我们把它复制一份,再开始修改它。我们在固定的参数列表上加上了另外两个指标缓冲区,它们的总数将也等于 5, 和 3,将显示在图表上。两个缓冲区将为辅助计算保留,买入信号的标签将使用绿色 (clrMediumSeaGreen), 而卖出信号使用红色 (clrRed)。 

//--- 属性
#property indicator_separate_window
#property indicator_minimum 0
#property indicator_maximum 100
#property indicator_buffers 5
#property indicator_plots   3
#property indicator_color1  clrSteelBlue
#property indicator_color2  clrMediumSeaGreen
#property indicator_color3  clrRed

定义用于信号标签的代码。如果需要以点显示,代码为 159,如果信号使用箭头来显示,使用的代码分别是 233 和 234

//--- 信号箭头: 159 - 点; 233/234 - 箭头
#define ARROW_BUY  159
#define ARROW_SELL 159

指标线与边界的交叉也可以既作为买入也作为卖出信号,所以,外部参数将需要一个枚举,它可以用来指定如何解释指标信号。

  • Break in — 突破进入边界的范围。向上突破底部边界是一个买入信号,而向下突破顶部边界是一个卖出信号。
  • Break in reverse — 突破进入边界的范围 (与波动方向相反). 与 'Break in' 模式相同的信号,只是买入和卖出的条件相反。
  • Break out — 突破出边界的范围。向上突破顶部边界是买入信号,而向下突破底部边界是卖出信号。 
  • Break out reverse — 突破出边界的范围 (与波动方向相反). 与 'Break out' 模式相同的信号, 只是买入和卖出的条件相反.

所有这些模式将显示在下面的图表中。

//--- 用于突破通道边界模式的枚举
enum ENUM_BREAK_INOUT
  {
   BREAK_IN          =0, // Break in(向内突破模式)
   BREAK_IN_REVERSE  =1, // Break in reverse(向内突破反转信号模式)
   BREAK_OUT         =2, // Break out(向外突破模式)
   BREAK_OUT_REVERSE =3  // Break out reverse(向外突破反转信号模式)
  };

指标将一共有三个外部参数:

  • RSI Period — 指标周期数;
  • Signal Level — 指标水平线;
  • Break Mode — 水平突破模式.

//--- 输入参数
input  int              PeriodRSI   =8;         // RSI 周期数
input  double           SignalLevel =30;        // 信号水平
input  ENUM_BREAK_INOUT BreakMode   =BREAK_OUT; // 突破模式

指标的属性是在 SetPropertiesIndicator() 函数中设置的,最后会设置辅助数组,所有的指标数组在 ZeroIndicatorBuffers() 函数中使用0来做初始化,然后, 我们指定0值不应当显示在图表上, 意思是这样的数值是空的。

//+------------------------------------------------------------------+
//| 设置指标属性                                                       |
//+------------------------------------------------------------------+
void SetPropertiesIndicator(void)
  {
//--- 短名称
   ::IndicatorSetString(INDICATOR_SHORTNAME,"RSI_PLUS1");
//--- 小数点位置
   ::IndicatorSetInteger(INDICATOR_DIGITS,2);
//--- 指标数组
   ::SetIndexBuffer(0,rsi_buffer,INDICATOR_DATA);
   ::SetIndexBuffer(1,buy_buffer,INDICATOR_DATA);
   ::SetIndexBuffer(2,sell_buffer,INDICATOR_DATA);
   ::SetIndexBuffer(3,pos_buffer,INDICATOR_CALCULATIONS);
   ::SetIndexBuffer(4,neg_buffer,INDICATOR_CALCULATIONS);
//--- 初始化数组
   ZeroIndicatorBuffers();
//--- 设置文字标签
   string plot_label[]={"RSI","buy","sell"};
   for(int i=0; i<indicator_plots; i++)
      ::PlotIndexSetString(i,PLOT_LABEL,plot_label[i]);
//--- 设置指标数组的宽度
   for(int i=0; i<indicator_plots; i++)
      ::PlotIndexSetInteger(i,PLOT_LINE_WIDTH,1);
//--- 设置指标数组的类型
   ENUM_DRAW_TYPE draw_type[]={DRAW_LINE,DRAW_ARROW,DRAW_ARROW};
   for(int i=0; i<indicator_plots; i++)
      ::PlotIndexSetInteger(i,PLOT_DRAW_TYPE,draw_type[i]);
//--- 标签代码
   ::PlotIndexSetInteger(1,PLOT_ARROW,ARROW_BUY);
   ::PlotIndexSetInteger(2,PLOT_ARROW,ARROW_SELL);
//--- 开始计算的起始元件的索引
   for(int i=0; i<indicator_plots; i++)
      ::PlotIndexSetInteger(i,PLOT_DRAW_BEGIN,period_rsi);
//--- 指标水平线的数量
   ::IndicatorSetInteger(INDICATOR_LEVELS,2);
//--- 指标水平线的值
   up_level   =100-SignalLevel;
   down_level =SignalLevel;
   ::IndicatorSetDouble(INDICATOR_LEVELVALUE,0,down_level);
   ::IndicatorSetDouble(INDICATOR_LEVELVALUE,1,up_level);
//--- 线型
   ::IndicatorSetInteger(INDICATOR_LEVELSTYLE,0,STYLE_DOT);
   ::IndicatorSetInteger(INDICATOR_LEVELSTYLE,1,STYLE_DOT);
//--- 表示不画任何内容的空值
   for(int i=0; i<indicator_buffers; i++)
      ::PlotIndexSetDouble(i,PLOT_EMPTY_VALUE,0);
//--- 在 Y 轴上的偏移
   if(BreakMode==BREAK_IN_REVERSE || BreakMode==BREAK_OUT_REVERSE)
     {
      ::PlotIndexSetInteger(0,PLOT_ARROW_SHIFT,arrow_shift);
      ::PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,-arrow_shift);
     }
   else
     {
      ::PlotIndexSetInteger(0,PLOT_ARROW_SHIFT,-arrow_shift);
      ::PlotIndexSetInteger(1,PLOT_ARROW_SHIFT,arrow_shift);
     }
  }

为方便起见,RSI 指标值的预先计算和主体计算部分移动到了独立的函数 PreliminaryCalculations() 和 CalculateRSI() 中,它们的内容和标准分发包中的 RSI 指标是一样的让我们只探讨用于确定指标信号的函数 — CalculateSignals(),在这里,首先会根据外部参数中设置的模式来检查条件,然后,如果条件满足,就把 RSI 指标值保存到对应的指标数组中。如果条件不满足,就保存0值,它们将不会显示在图表中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赫兹量化软件

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值