外汇EA编写教程:小型趋势指标、中型趋势指标和主要趋势指标

简介

James Hyerczyk 在其著作《形态-价格-时间:甘氏理论在交易系统里的运用》的序言中写道:

“我在期货交易上的经验显示,交易人员在他们的分析中太频繁地依赖于形态、价格或时间。他们趋向于在分析中偏重于一种方法,而不是齐头并进、均衡考量。最常见的错误是,系统围绕进入市场时间/退出市场价格或进入市场价格/退出市场时间而建。此外,使用形态的交易人员经常以欠佳的价格或在欠佳的时机进入/退出市场。这些观察结果提供了进一步的证据,证明所有三种方法的组合是在市场上取得成功所必需的。正是在这一前提下拙作得以成书。”

读者可以不同意这种说法。让我们试着去理解如何在实践中运用这些方法。本文以书中介绍的一些理念为基础,探讨以指标和“EA 交易”形式进行自动化交易和分析的可能性。因此,为更好地理解本文,建议先行阅读上文提到的相关著作(或至少阅读书的第一部分 – 模型)。

1.1 小型趋势

小型趋势的图形如图 1 所示。我们简单地介绍一下构建小型趋势的规则:

  • 在向上走势中(下一个柱的最大值大于上一个柱的最大值,且下一个柱的最小值大于上一个柱的最小值),我们将下一个柱的最大值和上一个柱连接,得到一条上升趋势线段;
  • 在向下走势中(下一个柱的最小值小于上一个柱的最小值,且下一个柱的最大值小于上一个柱的最大值),我们将下一个柱的最小值和上一个连接,得到一条下降趋势线段;
  • 如果在向上走势期间,其他柱的最大值不大于上一个柱的最大值,且因此下一个柱的最小值小于上一个柱的最小值,则走势方向变为向下;
  • 如果在向下走势期间,下一个柱的最小值不小于上一个柱的最小值,且与此同时下一个柱的最大值大于上一个柱的最大值,则方向变为向上;
  • 对于任何走势,如果下一个柱的最小值大于上一个柱的最小值,且与此同时下一个柱的最大值小于上一个柱的最大值,则该柱为内侧柱(参见图 1)且不参与图形的构建;
  • 如果在任何走势期间,下一个柱的最大值大于上一个柱的最大值,且与此同时下一个柱的最小值小于上一个柱的最小值,则该柱为外侧柱(参见图 1)。基于柱的方向(上升或下降),我们构建图形对应的区段。

图 1. 小型趋势

图 1. 小型趋势

当图形的走势方向改变时,就会形成所谓的小型顶部和底部。在图 1 中,小型底部以左侧红色价格标签标示,小型顶部以右侧绿色价格标签标示。

如果在向上走势期间方向变为向下,但没有达到上一个底部,则我们有了一个纠正移动。否则,方向会发生变化。这对于向下走势同样适用。

因此,价格在底部和顶部之间移动。这种移动称之为摆动。与此同时,可以生成纠正移动。

这些就是构建小型趋势的指标线的简要规则。更详细的描述可在上文提到的书中第一部分找到。该指标的图形与著名的峰谷指标的图形类似。但不同的是,它不是在其他柱收盘后重新绘制,并且没有影响趋势线的构建的外部可调节参数。

1.2. GannMicroTrend 指标

我们来开发一个显示小型趋势的图形的指标。它的外观应与图 1 所示的相同。我们同样将输出添加至顶部和底部的最新位置的显示,对应于时间。该指标位于本文所附文件 GannMicroTrend.mq5 中。

要显示该信息,使用在《利用标准库类创建您自己的“市场报价”》一文中介绍的库。为此,在指标文本的开头添加 #include 指令:

#include  <TextDisplay.mqh>

假设上述文件位于 /MQL5/Include 文件夹中。

指标应在全局变量中存储当前趋势的参数和最新顶部和底部的参数。同时,应该能够针对历史数据中指定的柱数指定计算深度。

为此,添加外部指定参数:

input int     MaxBars = 1000;
input bool    IsSaveTrendParams = true;
//---------------------------------------------------------------------
input bool    ShowInfo = true;
input int     UpDownInfoShift = 1;
input int     LeftRightInfoShift = 1;
input color   TitlesColor = LightCyan;
input color   TopFieldsColor = Green;
input color   LowFieldsColor = Brown;
//---------------------------------------------------------------------
input color   UpTrendColor = LightGreen;
input color   DnTrendColor = LightPink;
input int     LineWidth = 4;
//---------------------------------------------------------------------
input color   UpStopLossColor = Green;
input color   DnStopLossColor = Brown;
input int     StopLossWidth = 1;

这些参数的目的如下表中所示:

参数名称  参数目的

MaxBars

 历数据中指标要绘制的最大柱数。如果为 0,则历史数据中的所有可用柱已计算和绘制。

IsSaveTrendParams

 如果为真,则当前趋势的参数和最新顶部和底部的参数存储在全局变量中。

ShowInfo

 如果为真,则图形窗口显示最新顶部和底部的坐标。

UpDownInfoShift

 信息输出位置的从上到下的垂直偏移。

LeftRightInfoShift

 信息输出位置的从左到右的水平偏移。

TitlesColor

 信息输出时的标题的颜色。

TopFieldsColor

 输出最新顶部的参数时的文本颜色。

LowFieldsColor

 输出最新底部的参数时的文本颜色。

UpTrendColor

 绘制向上走势的线的颜色。

DnTrendColor

 绘制向下走势的线的颜色。

LineWidth

 趋势线的宽度。

UpStopLossColor


 标示顶部的右侧价格标签的颜色。

DnStopLossColor

 标示底部的左侧价格标签的颜色。

StopLossWidth

 指示顶部和底部的价格标签的大小。

我们将使用来自标准类组的 CChartObjectTrend 类型的图形对象构建趋势线。次级顶部将通过 CChartObjectArrowLeftPrice 类型的对象使用左侧价格标签标示,而次级底部通过 CChartObjectArrowRightPrice 类型的对象标示。所有这些对象都包含在随 MetaTrader 5 终端一起提供的标准库类中。

由于未来可能需要操作趋势线以及顶部/底部,我们将它们存储于同样来自标准类组的 CList 类型的对象列表中。为此,我们在指标的开头添加包含头文件的指令:

#include  <Arrays/List.mqh>
#include  <ChartObjects/ChartObjectsLines.mqh>
#include  <ChartObjects/ChartObjectsArrows.mqh>

接下来,添加对象列表:

CList*  trend_list_Ptr = NULL;  // list of the trend lines
CList*  up_list_Ptr = NULL;     // list of the peaks
CList*  dn_list_Ptr = NULL;     // list of the bottoms

现在,我们具备了构建指标的所有元素。

指标的 OnInit 函数如下所示:

int OnInit()
{
  trend_list_Ptr = new CList();
  if(CheckPointer(trend_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Error of creating the object CList #1");
    return(-1);
  }

  up_list_Ptr = new CList();
  if(CheckPointer(up_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Error of creating the obkect CList #2");
    return(-1);
  }

  dn_list_Ptr = new CList();
  if(CheckPointer(dn_list_Ptr) != POINTER_DYNAMIC)
  {
    Print("Error of creating the object CList #3");
    return(-1);
  }

  if(InitGraphObjects() != 0)
  {
    Print("Error of creating the object TableDisplay");
    return(-1);
  }

  return(0);
}

此为创建指向对象列表的指针,然后检查创建是否成功。如果指针无效,则会接收到一条错误消息,此时指标的工作完成。错误发生的位置可通过带 # 字符的编号识别。接下来,显示最新顶部和底部参数的表格完成初始化。这在功能码 InitGraphObjects 中完成。

指标的主要部分是执行计算所需的事件处理程序。它就是 OnCalculate 函数。让我们来一点一点地进行分析。第一部分 – 检查重新计算指标整个显示部分的需要。当指标在图形上第一次启动、在图形上下载更新的历史数据、时间表发生变化时,就产生了这种需要。在所有这些情形中,自变量 prev_calculated 的值等于零。

这通过以下方式验证:

int index, start = prev_calculated - 1;

if(prev_calculated == 0)
{
  if(CheckPointer(trend_list_Ptr) != POINTER_INVALID)
  {
    trend_list_Ptr.Clear();
  }
  if(CheckPointer(up_list_Ptr) != POINTER_INVALID)
  {
    up_list_Ptr.Clear();
  }
  if(CheckPointer(dn_list_Ptr) != POINTER_INVALID)
  {
    dn_list_Ptr.Clear();
  }

//  Determine the bar number of the beginning of calculations:
  if(MaxBars > 0 && rates_total > MaxBars)
  {
    start = rates_total - MaxBars;
  }
  else
  {
    start = 0;
  }
  time_prev = 0;
  trend_prev = 0;
}

如果需要重新计算整个指标,则我们清除趋势线列表以及顶部/底部列表。此外,这些图形对象也将从图形上删除。然后我们确定需要从其开始计算指标的柱的编号 – start 变量。如果 MaxBars 外部变量的值大于零且小于 rates_total 图形上的柱的数量,则计算开始的起始柱将等于:

    start = rates_total - MaxBars;

回想一下,按时间序列的柱的索引编排从零(最近的柱)开始。

如果 MaxBars 外部变量的值等于零(表示我们需要在图形的所有柱上计算指标)或大于图形上柱的数量,则我们需要针对图形上所有的柱重新计算指标所有的值,即 start 等于零。

接下来,是一个趋势线和次级顶部/底部位置的计算循环。按照上述规则分析柱的最大和最小价格值相当简单,无需进一步解释(请参见 GannMicroTrend.mq5 文件中的源文本)。

要绘制趋势线的区段,我们使用下面的简单函数:

//---------------------------------------------------------------------
//  Drawing of a section
//---------------------------------------------------------------------
void  CreateCut(datetime _dt1, double _prc1, datetime _dt2, double _prc2, color _clr, int _wd)
{
  string  name = GetUniqName(prefix + " ");
  CChartObjectTrend*  trend_obj = new CChartObjectTrend();
  if(CheckPointer(trend_obj) != POINTER_INVALID)
  {
    trend_obj.Create(0, name, 0, _dt1, _prc1, _dt2, _prc2);
    trend_obj.Color(_clr);
    trend_obj.Width(_wd);
    trend_list_Ptr.Add(trend_obj);
  }
}

在此我们使用该函数以获得图形中唯一的名称 GetUniqName,这在《利用标准库类创建您自己的“市场报价”》一文中进行了详细介绍。在成功构建趋势线图形对象的情形下,它的参数是指定的(颜色和线宽),且该对象通过调用 CList::Add 方法添加至线列表。

要绘制次级顶部/底部的位置,我们分别使用 CreateUpStopLoss/CreateDnStopLoss 函数。这两个函数与 CreateCut 函数类似,将创建的对象添加到它们的列表。

完成计算后,显示出最新顶部和底部的参数。在此我们使用在上一步中创建的列表。我们获得这些已按照时间递增进行排序的列表,并通过调用 CList::GetLastNode 方法获得顶部或底部的最新对象。

所述指标的工作效果在下图中显示:

图 2. 小型趋势指标

图 2. 小型趋势指标

2.1. 中型趋势

中期趋势的图形反映由两个柱描绘的市场的走势(双柱走势)。中期趋势的图形如图 2 中所示。我们简单地介绍一下构建中型趋势的图形的规则:

  • 在向上走势中(下一个柱的最大值大于上两个柱走势的最大值,且下一个柱的最小值同样大于上两个柱走势的最小值),我们连接下一个柱的最大值和上两个柱走势的最大值,得到一条上升中型趋势线;
  • 在向下走势中(下一个柱的最小值小于上两个柱走势的最小值,且下一个柱的最大值同样小于上两个柱走势的最小值),我们连接下一个柱的最小值和上两个柱走势的最小值,得到一条下降中型趋势线;
  • 如果在向上走势期间,下一个柱的最大值不大于上两个柱走势的最大值,且与此同时下一个柱的最小值小于上两个柱走势的最小值,则走势方向变为向下;
  • 如果在向上走势期间,下一个柱的最大值不大于上两个柱走势的最大值,且与此同时下一个柱的最小值小于上两个柱走势的最小值,则走势方向变为向下;
  • 在任何走势期间,如果下一个柱的最小值大于上两个柱走势的最小值,且与此同时下一个柱的最大值小于上两个柱走势的最大值,则该柱为内侧柱(参见图 2)且不参与图形的构建;
  • 如果在任何走势期间,下一个柱的最大值大于之前柱的最大值,且与此同时下一个柱的最小值小于之前柱的最小值,则该柱为外侧柱(参见图 2)。基于柱的方向(上升或下降),我们构建图形对应的区段。

图 3. 中型趋势

图 3. 中型趋势

中型趋势上升反向的唯一指标是中型顶部价位交叉。同样地,中型趋势下降反向的唯一指标是中型底部价位交叉。

如果中型趋势为上升,且市场形成一个向下中型摆动但未冲掉中型摆动的上一个底部,则它是一个纠正。如果中型趋势为下降,且市场形成一个向上中型摆动但未冲掉中型摆动的上一个顶部,则它也是一个纠正。

2.2. GannMiddleTrend 指标

我们来开发一个显示中型趋势的图形的指标。它的外观应与图 2 所示的相同。此外,最新顶部和底部的位置应在屏幕上显示。该指标可在本文随附的 GannMiddleTrend.mq5 文件中找到。

在该指标中,针对图形元素的渲染,我们将使用指标缓冲区和绘制类型 DRAW_COLOR_SECTION。这些在我们稍后开发 EA 时会用到。要从 EA 访问该指标的数据,我们使用指标缓冲区。

屏幕上指标的显示参数通过下列指令指定:

#property indicator_buffers    2
#property indicator_plots      1
#property indicator_type1      DRAW_COLOR_SECTION
#property indicator_color1     LightGreen, LightPink
#property indicator_width1     4

在此我们按顺序指定:

  • 指标缓冲区的数量(仅有两个 – 数据缓冲区和颜色索引缓冲区);
  • 屏幕上显示的图形的数量;
  • 指标图形的渲染类型(我们将使用彩色区段渲染);
  • 可以在颜色索引缓冲区中指定的颜色;
  • 指标图形的线宽;

OnInit 初始化函数中,我们将分派项与指标缓冲区结合,并指定其他一些指标参数。

这通过下述代码段实现:

SetIndexBuffer(0, DataBuffer, INDICATOR_DATA);
SetIndexBuffer(1, ColorBuffer, INDICATOR_COLOR_INDEX);

IndicatorSetInteger(INDICATOR_DIGITS, Digits( ));
IndicatorSetString(INDICATOR_SHORTNAME, "GannMiddleTrend");
PlotIndexSetString(0, PLOT_LABEL, "GannMiddleTrend");
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);

在此我们按顺序指定:

  • 在指标中用作数据缓冲区(用于在屏幕上渲染)的缓冲区;
  • 用于指定指标图形区段的颜色的缓冲区;
  • 指标值在屏幕上显示时的小数位数;
  • 指标在屏幕上显示时的简称;
  • 图形序列(数据缓冲区)在屏幕上显示时的名称;
  • 屏幕上对应于空值的值(无渲染);

该指标与小型趋势指标 GannMicroTrend 在结构和外部参数上相似。区别在于,前者在指标缓冲区和颜色缓冲区中直接而不是使用图形对象分派值。因此,我们将跳过实施的细节。

指标工作的结果如下图所示:

图 4. 中型趋势指标

图 4. 中型趋势指标

我们可以看到,该图形与图 3 中手工绘制的图形一样。

3.1. 主要趋势

主要趋势的图形反映由三个柱描绘的市场的走势(三柱走势)。它的外观应与图 5 所示的相同。我们简单地介绍一下构建主要趋势的规则:

  • 在向上走势中(下一个柱的最大值大于上三个柱走势的最大值,且下一个柱的最小值同样大于上三个柱走势的最小值),我们连接下一个柱的最大值和上三个柱走势的最大值,得到一条上升主要趋势线;
  • 在向下走势中(下一个柱的最小值小于上三个柱走势的最小值,且下一个柱的最大值同样小于上三个柱走势的最小值),我们连接下一个柱的最小值和上三个柱走势的最小值,得到一条下降主要趋势线;
  • 如果在向上走势期间,下一个柱的最大值不大于上三个柱走势的最大值,且与此同时下一个柱的最小值小于上三个柱走势的最小值,则走势方向变为向下;
  • 如果在向上走势期间,下一个柱的最大值不大于上三个柱走势的最大值,且与此同时下一个柱的最小值小于上三个柱走势的最小值,则走势方向变为向下;
  • 对于任何走势,如果下一个柱的最小值大于上三个柱走势的最小值,且与此同时下一个柱的最大值小于上三个柱走势的最大值,则该柱为内侧柱(参见图 5)且不参与图形的构建;
  • 如果在任何走势期间,下一个柱的最大值大于之前柱的最大值,且与此同时下一个柱的最小值小于之前柱的最小值,则该柱为外侧柱(参见图 5)。基于柱的方向(上升或下降),我们构建图形对应的区段。

图 5. 主要趋势

图 5. 主要趋势

主要趋势上升反向的唯一指标是主要顶部价位交叉。同样地,主要趋势下降反向的唯一指标是主要底部价位交叉。

如果主要趋势为上升,且市场形成一个向下摆动但未冲掉上一个底部摆动,则它是一个纠正。如果主要趋势为下降,且市场形成一个向上摆动但未冲掉上一个顶部摆动,则它是一个纠正。

3.2. GannMainTrend 指标

我们来开发一个显示主要趋势的图形的指标。它的外观应与图 5 所示的相同。此外,最新顶部和底部的位置应在屏幕上显示。该指标位于本文随附的 GannMainTrend.mq5 文件中。

该指标在结构和外部参数上与 GannMiddleTrend 中型趋势指标并无二致,因此我们将不再对其实施细节进行赘述。指标工作的结果如下图所示:

图 6. 主要趋势指标

图 6. 主要趋势指标

4. 在交易中运用摆动图表

至此,我们具备了以模型 – 小型趋势指标、中型趋势指标和主要趋势指标 – 分析市场的工具。现在,让我们试着基于价格摆动开发一个简单的交易系统。

James Hyerczyk 在其著作中提出以下策略:

  • 识别具有长期下降(上升)走势的区段;
  • 在形成停滞后,沿水平方向移动,市场在最新摆动的顶部上方下达买入订单(在最新摆动的底部下方下达卖出订单);
  • 将保护性止损设置在最新摆动底部的正下方(最新摆动顶部的正上方);
  • 建仓后,止损随价格移动,位于生成的新摆动的底部(顶部)的下方;

让我们通过图形进行说明:

图 7. 摆动交易

图 7. 摆动交易

在极高的价格水平,建议考虑转向卖出持仓的可能性;在极低价位,建议考虑转向买入持仓的可能性。图 7 显示了中型趋势的图形。通过主要趋势图形,我们将识别具有长期走势的区段。通过中期趋势图形,我们将识别“停滞”市场区段。仓位将通过中型趋势图形来监控。

下面是同一区段的主要趋势的图形:

图 8. 主要趋势图表上的区段

图 8. 主要趋势图表上的区段

长期下降走势(摆动)位于主要顶部 1.36913 和主要底部 1.18758 之间。该走势跨越 1815.5 四位数点。接下来是“停滞”市场区段,具有从 1.24664 到 1.21495 的几近水平的趋势(请参见图 7)。该走势跨越 316.9 点。之后,价格突破中型趋势图形上最新摆动的中型顶部的水平,然后向上。

我们设置初始止损位于中型底部和最新摆动 1.21495 的正下方,监控中型趋势图形上的仓位。作为此次交易的结果,我们将得到约 1.31186 – 1.23966 = 722.0 点的盈利。

5. 用于 MQL5 向导中的交易信号类

在设计实施我们的交易系统的代码前,让我们概要地想象一下交易的整个过程。让我们来看看下面的图解:

图 9. 买入持仓交易

图 9. 买入持仓交易

买入仓位的调整包括以下操作:

  • 根据主要趋势图形定义一个长期下降走势(图 9 中区段 A-B)。走势的持续时间和量级分别由参数 dTdP 指定。这些参数的值应在研究该工具历史数据的基础上确定。
  • 在主要趋势图形上形成主要底部后(图 9 中的 B 点),等待中型趋势图形上 C 点和 D 点的形成。这些点,连同 B 点,一起构成中型 B-C 和 C-D 摆动。如果这些摆动的持续时间和量级未超出指定值,则我们假设它们形成了一个水平趋势(或“停滞”市场)。
  • 等待中型 C 顶部水平(或在 C 后形成的最近的中型顶部)的到达。突破后,在 D 点设置一个位于中型底部正下方的止损(或在 C 后形成的最近的中型底部)。
  • 通过在形成的中型底部的下方(位于 F 点和 L 点正下方)移动止损,随着上升走势的继续监控仓位。
  • 取决于资金管理的模式,我们可以在突破点、形成的中型顶部(G 点和 M 点)添加仓位交易量。

卖出仓位的调整所需的操作呈“镜像”对称。

因此,要构建“EA 交易”,我们需要以下组件:生成买入/卖出信号的模块;敞口仓位追踪止损的模块;以及可能的一个模块,负责“金字塔式交易”仓位(资金管理)。

在撰写此部分时,我参考了下述文章的内容:《MQL5 向导:如何创建交易信号模块》《MQL5 向导:如何创建敞口仓位的追踪模块》以及《MQL5 向导:如何创建风险和资金管理模块》

负责生成交易信号的模块的开发包括以下操作:

  • 添加一条预处理程序指令以包含标准 mqh 文件,该文件包含所有用于生成“EA 交易”的基类。这通过以下方式实现:
#include <Expert/ExpertSignal.mqh>

在我们生成交易信号的模块的开头插入该指令。

  • 以注释的形式添加的特殊字符串指示 MetaEditor 编辑器此文件应在生成 EA 时使用:
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal based on swings on charts                           |
//| of the middle and main trends according to Gann (iCustom)        |
//| Type=Signal                                                      |
//| Name=TGannBreakSignal                                            |
//| Class=TGannBreakSignal                                           |
//| Page=                                                            |
//| Parameter=MinMainSwingContinuance,int,5                          |
//| Parameter=MinMainSwingSize,double,300.0                          |
//| Parameter=MinMiddleSwingContinuance,int,3                        |
//| Parameter=MaxMiddleSwingSize,double,200.0                        |
//| Parameter=OpenPriceSpace,double,5.0                              |
//| Parameter=StopLossSpace,double,5.0                               |
//+------------------------------------------------------------------+
// wizard description end

在此我们可以看到参数 Title,它用于指定在 EA 生成期间出现在列表 MetaEditor 中的模块的名称(请参见下述描述)。一个重要的参数 – Type,它用于确定指定模块为信号生成模块。同时,外部参数和它们的默认值出现。

所有这些代码行紧跟包含标准文件 ExpertSignal.mqh 的指令之后。

  • 对基类的后代类的描述在文件 ExpertSignal.mqh 中进行。该类应实现一些在 CExpertSignal 基类中缺失的功能性。类的描述如下所示(部分不太重要的类未在下方列示):
class TGannBreakSignal : public CExpertSignal
  {
private:
   int               min_main_swing_continuance;    // minimum swing duration time of the main tren
   double            min_main_swing_size_points;    // minimum swing amplitude on the chart of the main trend
   int               min_middle_swing_continuance;  // minimum swing duration time on the chart of the middle trend
   double            max_middle_swing_size_points;  // maximum swing amplitude of the chart of the middle trend
   double            open_price_space;              // distance between the open price and peak/bottom
   double            stop_loss_space;               // distance between the stop loss price and peak/bottom

   datetime          main_swing_lf_datetime;        // time of left point of a swing on the chart of the main trend
   double            main_swing_lf_price;           // price of left point of a swing on the chart of the main trend
   datetime          main_swing_rt_datetime;        // time of right point of a swing on the chart of the main trend
   double            main_swing_rt_price;           // price of right point of a swing on the chart of the main trend
   int               main_swing_continuance;        // swing duration time on the chart of the main trend
   double            main_swing_size_points;        // swing amplitude (in points) on the chart of the main trend

   datetime          middle_swing_lf_datetime;      // time of left point of a swing on the chart of the middle trend
   double            middle_swing_lf_price;         // price of left point of a swing on the chart of the middle trend
   datetime          middle_swing_rt_datetime;      // time of right point of a swing on the chart of the middle trend
   double            middle_swing_rt_price;         // price of right point of a swing on the chart of the middle trend
   int               middle_swing_continuance;      // swing duration time on the chart of the middle trend
   double            middle_swing_size_points;      // swing amplitude (in points) on the chart of the middle trend

   int               handle_main_swing;
   int               handle_middle_swing;
   double            main_swing_buff[];
   double            middle_swing_buff[];
   datetime          time_buff[];
   double            price_buff[];
public:
                     TGannBreakSignal();   // constuctor
                    ~TGannBreakSignal();   // destructor
   //   Settings:
   void              MinMainSwingContinuance(int _cont);
   void              MinMainSwingSize(double _size);
   void              MinMiddleSwingContinuance(int _cont);
   void              MaxMiddleSwingSize(double _size);
   void              OpenPriceSpace(double _space);
   void              StopLossSpace(double _space);

   int               GetMainSwingContinuance();    // gets swing duration time on the chart of the main trend
   double            GetMainSwingSizePoints();     // gets swing amplitude (in 4-digit points) on the chart of the main trend
   int               GetMiddleSwingContinuance();  // gets swing duration time on the chart of the middle trend
   double            GetMiddleSwingSizePoints();   // gets swing amplitude (in 4-digit points) on the chart of the middle trend
   
   // overloaded methods of the CExpertSignal class:
   virtual bool      ValidationSettings();
   virtual bool      CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      InitIndicators(CIndicators *indicators);

   //   Additional methods:
protected:
   //   Sets swing parameters of the main trend
   void              SetMainSwingParameters(datetime _lf_dt,double _lf_price,datetime _rt_dt,double _rt_price);
   //   Sets swing parameters of the middle trend
   void              SetMiddleSwingParameters(datetime _lf_dt,double _lf_price,datetime _rt_dt,double _rt_price);
   // Gets swing parameters of the main trend
   int               GetMainSwing();                  
   // Gets swing parameters of the middle trend
   int               GetMiddleSwing( );                
  };

通过注释,数据成员的作用一目了然。下面我们介绍类的一些方法。

首先,我们需要重新定义基类的方法。第一个方法用于检查 EA 指定外部参数的正确性:

//---------------------------------------------------------------------
// Validation of settings
//---------------------------------------------------------------------
bool TGannBreakSignal::ValidationSettings()
  {
   if(this.min_main_swing_continuance<=0)
     {
      Print("Wrong Parameter: min_main_swing_continuance = ",
           this.min_main_swing_continuance);
      return(false);
     }
   if(this.min_main_swing_size_points<=0.0)
     {
      Print("Wrong Parameter: min_main_swing_size_points = ",
            DoubleToString(this.min_main_swing_size_points,1));
      return(false);
     }
   if(this.min_middle_swing_continuance<=0)
     {
      Print("Wrong Parameter: min_middle_swing_continuance = ",
             this.min_middle_swing_continuance);
      return(false);
     }
   if(this.max_middle_swing_size_points<=0.0)
     {
      Print("Wrong Parameter: max_middle_swing_size_points = ",
             DoubleToString(this.max_middle_swing_size_points,1));
      return(false);
     }

   return(true);
  }

在此,我们对外部参数的正确性作一简单检查。显然,摆动的量级(点数)和持续时间(柱数)不能小于或等于零。对于不正确的指定外部参数的情况下,方法返回 false

接下来,我们探讨针对建仓生成信号的方法。

买入持仓建仓必要性的检查通过下面继承自基类的方法完成:

//---------------------------------------------------------------------
// Checks conditions to open long position
//---------------------------------------------------------------------
bool TGannBreakSignal::CheckOpenLong(double &_price,double &_sl,
                                         double &_tp,datetime &_expiration)
  {
   if(this.GetMainSwing()==-1)
     {
      return(false);
     }

   if(this.GetMiddleSwing()==-1)
     {
      return(false);
     }

// If the main swing upward, exit
   if(this.main_swing_rt_price>=this.main_swing_lf_price)
     {
      return(false);
     }

// If the middle weak swing isn't formed, exit:
   if(this.middle_swing_rt_price>=this.middle_swing_lf_price)
     {
      return(false);
     }

// Check swing parameters on the main trend chart
   if(this.main_swing_continuance<this.min_main_swing_continuance ||
     this.main_swing_size_points<this.min_main_swing_size_points)
     {
      return(false);
     }

// Check swing parameters on the middle trend chart
   if(this.middle_swing_continuance<this.min_middle_swing_continuance ||
      this.middle_swing_size_points>this.max_middle_swing_size_points)
     {
      return(false);
     }

   double unit=this.PriceLevelUnit();

// If the price has crossed the peak of the weak middle swing, set signal to open long position:
   double delta=this.m_symbol.Bid()
             -(this.middle_swing_lf_price+this.open_price_space*unit);
   if((delta>=0.0) && (delta<(10.0*unit)))
     {
      _price=0.0;
      _sl = this.m_symbol.NormalizePrice(this.middle_swing_rt_price - stop_loss_space*unit);
      _tp = 0.0;

      return(true);
     }

   return(false);
  }

首先,用于获得主要和中型趋势图形的最新摆动的参数的两个方法被调用 – TGannBreakSignal::GetMainSwingTGannBreakSignal::GetMiddleSwing。如果这些方法成功,则我们可以分析摆动的参数。

由于我们是检查买入持仓建仓信号的存在性,摆动应向下。我们比较点 A 和点 B 的位置(参见图 9)- 如果点 B 具有低于点 A 的价格,则价格摆动向下。

接下来,我们检查点 C 和点 D 是否存在(参见图 9)。此外,点 D 必须具有低于点 C 的价格。如果该条件满足,则我们检查主要和中型趋势的摆动的参数。走势的持续时间和量级已检查。

如果所有前述检查成功,则执行最后一道检查 – 价格是否穿越中型摆动的顶部。如果是,则填入止损值并返回结果 true

卖出持仓建仓必要性的检查通过调用方法 TGannBreakSignal::CheckOpenShort 完成,该方法执行与方法 TGannBreakSignal::CheckOpenLong 类似的检查,但在价格轴上呈镜像对称。

至此,我们已回顾了生成交易信号的模块的结构和基本方法。所述的模块位于本文所附文件 GannTrendSignal.mqh 中。

我们需要的第二个模块 – 敞口仓位追踪止损的模块。该模块同样基于标准类开发,包括以下操作:

  • 添加一条预处理程序指令以包含标准 mqh 文件,该文件包含用于生成仓位追踪的代码的基类。

这通过以下方式实现:

#include <Expert/ExpertTrailing.mqh>

在仓位追踪模块的开头插入该指令。

  • 以注释的形式添加的特殊字符串指示编辑器 MetaEditor 此文件应用于在 EA 中生成仓位追踪:
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing on peaks/bottoms on the chart of the middle trend |
//| Type=Trailing                                                    |
//| Name=MiddleTrend                                                 |
//| Class=MiddleTrendTrailing                                        |
//| Page=                                                            |
//| Parameter=StopLossSpace,double,5.0                               |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+

在此,参数 Type 设置为等于 “Trailing” 值 – 这表示该模块应用于支持仓位(追踪)。同时,外部参数和它们的默认值出现。

所有这些代码行紧跟包含标准文件 ExpertTrailing.mqh 的指令之后。

  • 对基类的后代类的描述在文件 ExpertTrailing.mqh 中进行。该类应实现一些在 CExpertTrailing 基类中缺失的功能性。类的描述如下所示(部分不太重要的类未在下方列示):
class MiddleTrendTrailing : public CExpertTrailing
  {
private:
   datetime          middle_swing_lf_datetime;  // time of left point of a swing on the chart of the main trend
   double            middle_swing_lf_price;     // price of left point of a swing on the chart of the main trend
   datetime          middle_swing_rt_datetime;  // time of right point of a swing on the chart of the main trend
   double            middle_swing_rt_price;     // price of right point of a swing on the chart of the main trend
   double            stop_loss_space;           // the distance between peak/bottom and stop loss price

   int               handle_middle_swing;
   double            middle_swing_buff[];
   datetime          time_buff[];
   double            price_buff[];
public:
                     MiddleTrendTrailing();     // constructor
                    ~MiddleTrendTrailing();     // destructor
private:
   int               GetMiddleSwing();          // get parameters of the middle swing

public:
   //   Settings:
   void              StopLossSpace(double _space);
   //   Overloaded methods of CExpertTrailing class:
   virtual bool      ValidationSettings();
   virtual bool      InitIndicators(CIndicators *indicators);
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
  };

在我们的类中重新定义的基类方法 – MiddleTrendTrailing::CheckTrailingStopLongMiddleTrendTrailing::CheckTrailingStopShort。这两个方法分别检查买入持仓和卖出持仓的止损修改条件。

我们从更细节的层面讨论方法 MiddleTrendTrailing::CheckTrailingStopLong

//---------------------------------------------------------------------
// Checks conditions of trailing stop for long position
//---------------------------------------------------------------------
bool MiddleTrendTrailing::CheckTrailingStopLong(CPositionInfo *_position,double &_sl,double &_tp)
  {
   if(_position==NULL)
     {
      return(false);
     }

   if(this.GetMiddleSwing()==-1)
     {
      return(false);
     }

   double sl_req_price = this.m_symbol.NormalizePrice(MathMin(middle_swing_lf_price,middle_swing_rt_price)
                      - this.stop_loss_space * this.m_adjusted_point );
   if(_position.StopLoss() >= sl_req_price )
     {
      return(false);
     }

   _tp = EMPTY_VALUE;
   _sl = sl_req_price;

   return(true);
  }

首先,我们调用获取中型趋势图形最新摆动的参数的方法 – TGannBreakSignal::GetMiddleSwing。如果该方法成功(返回一个零值),则分析摆动的参数是可能的。

接下来,我们基于获得的摆动参数计算设置止损的价格水平。如果计算得出的止损水平低于当前水平(对于买入持仓),则我们将方法 _sl 的新值 sl_req_price 填入参数并返回 true。否则,返回 false – 这表示不需要修改止损水平。

检查卖出持仓止损水平修改必要性的方法可类似构建。

至此,我们已回顾了追踪敞口仓位(追踪)的模块的结构和基本方法。所述的模块位于本文所附文件 GannTrailing.mqh 中。

基于交易信号生成 EA

使用 “Masters MQL5” 通过模板生成 EA 十分简单。它包含几个步骤:

  • 步骤 1

使用主菜单 MetaEditor 的 File / New(文件/新建)命令,调用 EA 生成大师。一个对话框窗口在屏幕上显示,如下所示:

图 10. 在 MQL5 向导中创建就绪“EA 交易”对话框

图 10. 在 MQL5 向导中创建就绪“EA 交易”对话框

选择其后文本为 “EA (generate)”(EA (生成))的单选按钮,并单击 “Next “(下一步)按钮 – 前往生成 EA 的下一步。

  • 步骤 2

在本步骤中,我们指定 EA 的一般参数 – 名称、幻数等。如下所示的对话框窗口显示:

图 11.“EA 交易”的一般属性

图 11.“EA 交易”的一般属性

true 中指定参数 EveryTick 的值 – 我们需要 EA 处理每个价格变动,幻数可保持不变。单击 “Next “(下一步)按钮,进入 EA 生成的下一步。

  • 步骤 3

在本步骤中,我们为 EA 指定信号的参数。首先,我们从列表选择信号的具体类型:

图 12. 选择交易信号模块

图 12. 选择交易信号模块

选择我们先前编写的信号的名称,如下所示的对话框将出现在屏幕上:

图 13. 交易信号模块的输入参数

图 13. 交易信号模块的输入参数

在此,我们可以修改我们所需参数的默认值。再次单击 “Next “(下一步)按钮并进入下一步骤。

  • 步骤 4

在本步骤中,选择支持敞口仓位的追踪类型。我们可以从列表中任意选择一个,但我们将选择先前所构建的追踪止损方法:

图 14. 选择仓位追踪类型

图 14. 选择仓位追踪类型

我们得到如下所示的对话框窗口:

图 15. 指定追踪参数

图 15. 指定追踪参数

在此,我们可调整指定外部参数的默认值。单击 “Next “(下一步)按钮并进入下一步骤。

  • 步骤 5

图 16. 指定资金管理参数

图 16. 指定资金管理参数

在此,我们可以选择资金管理参数(计算有效手数的方法)。保持不变 – 以固定交易量交易。单击 “Done”(完成)按钮,生成具有指定名称、建仓算法、追踪和资金管理规则的就绪 EA。

测试生成的 EA,确保它能够工作:

图 17. 测试创建的“EA 交易”

图 17. 测试创建的“EA 交易”

我们可以看到,趋势经正确识别,并且是完全的(在该方法允许的范围内)。此外,我们使用按一般考虑指定的默认参数。

总结

实际上,我们仅讨论了甘氏理论及其在交易系统和市场分析中的应用的第一部分 – 模型。似乎其应用的最好结果可在该等时间周期获取,其中图形被划分为柱,这与交易的自然架构相一致。

对于股票市场 – 使用每日、每周和每月间隔交易。对于货币市场 – 使用会话间隔交易。对于商品市场 – 不仅使用每日、每周和每月间隔交易,也使用市场的季节性波动交易。

补遗

我决定进行一些与本文主题不是直接相关的额外研究,但研究还是关于甘氏理念的。更具体地说,是关于我下面提出的问题:价格在其走势期间是否会标示所谓的“圆形”水平?即,对欧元货币和股票而言,价格水平结束于 50 和 100(对日元来说,“圆形”价格水平是指结束于 40)。

为此,我们在小数点后的最后几位数字上构建一个顶部/底部的分布图。对于五位数字报价,小数点后有三位数字(最后一位数 – 小数点后一位)。我们针对日柱使用中型趋势图形。

在一个圆轴上,我们绘制价格的最后几位数,从零到五十(四舍五入到小数点后一位);而在纵轴上 – 是在这些水平上形成的顶部/底部的数量。分别构建顶部图、底部图和总图。

下面是一些主要货币对在 2000 年到 2011 年以及日时间表上的顶部图、底部图和总图。

我们如何理解这些结果?首先,图表中存在失真,即不是所有价格值具有形成顶部/底部的同等可能性。其次,这些值没有与“圆”值完全重合 – 而这是我们的基本预期。它是否可以用于交易还很难说。这需要更严谨的研究。也许从实用的角度看,可以从股票市场获得更有趣的结果。

至少,这是历史数据分析的又一工具,并且在同类工具中也还差强人意。

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

附加的文件 |


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

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

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

風險提示

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

邁投公眾號

聯繫我們

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

MyFxtops 邁投