English Русский Español Deutsch 日本語 Português
preview
如何利用 MQL5 创建自定义指标(Heiken Ashi)

如何利用 MQL5 创建自定义指标(Heiken Ashi)

MetaTrader 5交易 | 27 十月 2023, 14:11
1 233 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

概述

我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。

在本文中,我将与您分享一种克服这一挑战的方法,方法是从 iCustom 函数中受益,并根据您的条款和偏好创建自定义指标。 我们还将看到一个示例,因为我们将创建一个自定义的 Heiken Ashi 技术指标,我们将在交易系统示例中使用此自定义指标。 我们将通过以下主题来介绍这一点:

在明晰了我在前面主题中分享的内容后,您应该能够创建自定义指标,该指标将有助于读取图表,并可在您的交易系统中运用。 我们将利用内置于 MetaTrader 5 交易平台中的 MQL5(MetaQuotes 语言),编写将要创建的指标和 EA 的代码。 如果您尚不清楚如何下载和使用它们,您可以阅读上一篇文章中的主题在 MetaEditor 中编写 MQL5 代码,它对此很有帮助。

免责声明:所有信息仅按原样提供,仅用于教学目的,并非准备用于交易目的或建议。 该信息不保证任何类型的结果。 如果您选择在您的任何交易账户上使用这些素材,您将自行承担风险,并且您将是唯一负责的人。

自定义指标和 Heiken Ashi 定义

在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。

我们来研究开始创建自定义指标所需的步骤:

打开 MetaEditor IDE,然后在导航器中选择 “Indicators” 文件夹

指标文件夹

单击“新建”按钮创建一个新程序,如下图所示

新按钮

之后,将打开以下窗口,您应该在其中选择要所需创建的程序类型。 在此我们选择“自定义指标”

程序选择

单击“下一步”后,将打开以下包含指标详细信息的窗口。 在此处指定自定义指标的名称,然后单击“下一步”

指标详情

在接下来的窗口中,我们继续确定更多指标细节

指标详情2

指标详情3

一旦完成首选项设置,并单击“下一步”,然后单击“完成”后,编辑器窗口将打开,我们就可在其中编写指标代码。

我们将以 Heiken Ashi 为例,了解如何开发自定义指标。 那么,我们就需要了解有关 Heiken Ashi 技术指标的更多信息。 它是一种烛台类型的图表方法,可用于呈现和分析市场走势,并且可以与其它工具结合使用,以便获得有效和更好的见解,在此基础上,我们可以在发现良好潜在交易理念和机会后做出明智的交易决策。

Heiken Ashi 图表类似于普通的烛台技术图表,但绘制这些蜡烛的计算方式是不同的。 也就是说,有两种不同的方法。 众所周知,普通烛台图表根据特定时期内的真实开盘价、最高价、最低价和收盘价计算价格,但 Heiken Ashi 在计算蜡烛时会考虑之前类似价格(开盘价、最高价、最低价和收盘价)的价格。

以下是 Heiken Ashi 的相关值如何计算的:

  • 开盘价 =(前一根蜡烛的开盘价 + 前一根蜡烛的收盘价)/ 2
  • 收盘价 =(开盘价 + 收盘价 + 当前蜡烛的最高价 + 最低价)/ 4
  • 最高价 = 来自当期最高值、开盘价或收盘价的最高值
  • 最低价 = 来自当期最低值、开盘价或收盘价的最低值

根据计算,指标构建阳线和阴线烛台,这些烛台的颜色指示市场的相关方向:是看涨还是看跌。 下面是一个显示传统日本烛条和 Heiken Ashi 的示例,如此可从视觉角度观察差异。

 ha 指标

在上一个图表的屏幕截图中,上半部分显示了传统的烛条;而在下半部分,Heiken Ashi 指标显示为蓝色和红色烛条,定义了市场方向。 根据其计算,该指标的意图是通过平滑数据来过滤和消除市场走势中的一些噪音,从而避免错误信号。


简单的 Heiken Ashi 指标

在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。

我们来查看创建此自定义指标需要完成的所有步骤。

通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:

  • (indicator_separate_window) 在单独的窗口中显示指标。
  • (indicator_buffers) 确定指标计算的缓冲区数量。
  • (indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
  • (indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
  • (indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
  • (indicator_widthN) 还要确定 N 或图形序列的宽度。
  • (indicator_labelN) 确定图形序列 N 的标签设置。
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"

为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。

double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];

在 OnInit() 中,此函数初始化正在运行的指标。

int OnInit()

调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。 其参数为:

  • index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
  • buffer[]: 在我们的自定义指标中声明的数组。
  • data_type: 我们需要在指标数组中存储的数据类型。
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);

通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:

  • prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
  • prop_value: 属性的值,我们将指定(_Digits)。
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:

  • prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
  • prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");

调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:

  • plot_index: 图形绘图的索引,我们将指定 0。
  • prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
  • prop_value: 属性值。
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);

然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。

   return(INIT_SUCCEEDED);

在指标中调用的 OnCalculate 函数内部,基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])

创建一个整数型 “start” 变量,我们稍后将为其赋值:

int start;

使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:

   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;

在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。

这三个表达式将是:

  • i=start: 对应起始位置。
  • i<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
  • i++: 加 1 作为新的 i。

我们每次在循环过程中需要执行的操作:

计算四个双精度变量

  • haOpenVal: 对应 Heiken Ashi 开盘价。
  • haCloseVal: 对应 Heiken Ashi 收盘价。
  • haHighVal: 对应 Heiken Ashi 最高价。
  • haLowVal: 对应 Heiken Ashi 最低价。

在上一步中分配的计算值与以下内容相同

  • haLow[i]=haLowVal
  • haHigh[i]=haHighVal
  • haOpen[i]=haOpenVal
  • haClose[i]=haCloseVal

检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。

   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;

      //--- set candle color
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }

终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。

return(rates_total);

然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:

//+------------------------------------------------------------------+
//|                                             simpleHeikenAshi.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];
int OnInit()
  {
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   return(INIT_SUCCEEDED);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int start;
   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }
   return(rates_total);
  }

编译无误后,指标应在导航器窗口的 “Indicators” 文件夹中可供使用,如下图所示。

simpleHA 导航

然后在所需的图表上双击执行它,此刻将出现指标信息的通用窗口:

 simpleHA 窗口

“颜色”选项卡显示默认设置:蓝色表示上行走势,红色表示下行走势。 若有需要,您可以编辑这些值,以便设置首选颜色。 此选项卡如下所示:

 simpleHA 窗口2

按下确定后,指标将附加到图表上,如下图所示:

simpleHA 加载

正如您在上一张图表中所见,我们将简单 Heiken Ashi 指标插入到图表的单独子窗口之中。 根据这些烛条的方向(看涨和看跌),它分别为蓝色和红色烛条。 现在,我们有一个在 MetaTrader 5 中创建的自定义指标,我们可以在任何交易系统中使用此自定义指标。 我们将在接下来的主题中看到如何轻松做到这一点。


基于自定义 Heiken Ashi 指标的 EA

在这一部分中,我们将学习如何在我们的交易系统 EA 中使用任意自定义指标。 我们将创建一个简单的 Heiken Ashi 系统,该系统可以向我们显示指标的价格(开盘价、最高价、最低价和收盘价),因为我们已经知道指标计算出的数值与实际价格不同。

做到这一点的方式是选择创建一个新的智能系统。 而以下就是完整代码:

//+------------------------------------------------------------------+
//|                                             heikenAshiSystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int heikenAshi;
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,1,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,1,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,1,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,1,heikenAshiClose);
   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
  }

此代码中的区别:

程序的类型是智能系统。 故此,该程序的构造将有所不同,因为它由三个部分组成,它们如下:

  • int OnInit():它初始化 EA 的运行,返回整数值的推荐类型。
  • void OnDeinit: 它是所运行 EA 的逆初始化,不返回任何值。
  • void OnTick(): 它在每次跳价时处理新报价,它不返回任何值。

在前面函数的作用域之外,在它们之前,我们创建了一个整数型变量(heikenAshi)

int heikenAshi;

在 OnInit() 的作用域内,我们将 iCustom 函数的值分配给 'heikenAshi' 变量。 iCustom 函数返回自定义指标的句柄,此处则是简单 Heiken Ashi,但您可以使用指标文件夹中的任意自定义指标。 其参数为:

  • symbol: 品种名称,我们采用(_Symbol)对应当前品种。
  • period: 时间帧,我们采用(_Period)对应当前时间帧。
  • name: 自定义指标的名称,及其在 MetaTrader 5 的指标文件夹中的路径,这里我们采用 “My Files\\Heiken Ashi\\simpleHeikenAshi”。

然后我们终止函数,并返回(INIT_SUCCEEDED)来表示初始化成功。

int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }

在 OnDeinit() 函数的作用域内,我们使用打印函数来通知 EA 被删除

void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }

在 OnTick() 函数的作用域内,我们按以下内容来完成我们的代码:

为 Heiken Ashi 价格创建四个双精度类型变量(开盘价、最高价、最低价和收盘价)

   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];

调用 CopyBuffer 函数获取自定义指标缓冲区的数据。 其参数为:

  • indicator_handle: 指标句柄,我们采用(heikenAshi)。
  • buffer_num: 我们采用指标缓冲区编号(0 对应开盘价,1 对应最高价,2 对应最低价,3 对应收盘价)。
  • start_pos: 第一个要复制的元素位置,我们采用 0 对应当前元素。
  • count: 要复制的数据量,我们采用 1,这里不需要更多。
  • buffer[]: 我们要复制的数组,我们采用(heikenAshiOpen 对应开盘价,heikenAshiHigh 对应最高价,heikenAshiLow 对应最低价,heikenAshiClose 对应收盘价)。

调用 Comment 函数,取当前 Heiken Ashi 价格(开盘价、最高价、最低价和收盘价)在图表上作为注释:

   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));

在编译此代码,若无任何错误,执行它后,我们可以发现附加到图表的 EA。 我们可以在下面的测试示例中接收相同的信号:

 haSystem

正如我们在上一张图表中所见,我们在图表的左上角显示指标价格作为注释。


Heiken Ashi - EMA 系统

在本主题中,我们将结合另一种技术工具,看看结果是否会更好。 我们需要应用的思路是通过使用价格的指数移动平均线来过滤自定义指标的信号。 有很多方法可以做到这一点,如果我们想要添加更多功能,我们可以针对 EMA 创建另一个自定义指标,那么我们可以在 EA 中将其用作 iCustom,就像我们获取所需信号一样。 我们还可以通过平滑指标的数值来创建平滑指标,然后获取我们的信号。 我们可以在 EA 中调用内置的 iMA 函数,并从中获取信号,为了简单起见,我们在此采用这种方法。

我们需要做的是让 EA 持续检查当前 2 个 EMA(快速和慢速)和之前的快速 EMA 和 Heiken Ash 收盘价的数值,从而判定每个值的位置。 如果前一个 heikenAshiCloses 大于前一个 fastEMAarray,且当前 fastEMA 大于当前 slowEMA 值,则 EA 应返回买入信号,以及这些值作为图表上的注释。 如果前一个 heikenAshiCloses 低于前一个 fastEMAarray,且当前 fastEMA 低于当前 slowEMA 值,则 EA 应返回卖出信号,以及这些值作为图表上的注释。

以下是创建此 EA 的完整代码:

//+------------------------------------------------------------------+
//|                                          heikenAsh-EMASystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period
int heikenAshi;
double fastEMAarray[], slowEMAarray[];
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi-EMA System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);
   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
  }

此代码内的区别是:

创建用户输入,并根据用户偏好设置快速 EMA 周期和慢速 EMA 周期。

input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period

为 fastEMA 和 slowEMA 创建两个数组。

double fastEMAarray[], slowEMAarray[];

在 CopyBuffer 中将要复制的数据量设置为 3,从而获取 Heiken Ashi 指标前几个收盘价数值

   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);

调用内置的 iMA 函数,定义快速和慢速 EMA,该函数返回移动平均线指标的句柄。 其参数为:

  • symbol: 品种名称,我们采用(_Symbol)对应当前那个。
  • period: 我们采用(_Period)对应当前那个。
  • ma_period: 需要平滑平均值的周期,我们采用(fastEMASmoothing 和 slowEMASmoothing)输入值。
  • ma_shift: 指标的偏移,我们取 0。
  • ma_method: 移动平均线的类型,我们采用 MODE_SMA 对应简单移动平均线。
  • applied_price: 计算中所需的价格类型,我们采用 PRICE_CLOSE。
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);

调用 ArraySetAsSeries 函数设置 AS_SERIES 标志。 其参数为:

  • array[]: 我们所用的数组(fastEMAarray 和 slowEMA)。
  • flag: 数组索引方向,我们采用 true。
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);

调用 CopyBuffer 函数获取 EMA 指标缓冲区的数据。

   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);

使用 'if' 语句返回条件信号:

在买入信号的情况下

如果前一个 heikenAshiClose > 前一个 fastEMAarray,且当前 fastEMAarray > 当前 slowEMAarray,则 EA 必须返回买入信号和以下值:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }

若出现卖出信号的情况下

如果前一个 heikenAshiClose < 前一个 fastEMAarray,且当前 fastEMAarray < 当前 slowEMAarray,则 EA 必须返回卖出信号和价格值:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }

编译此代码,且无错误,执行后,我们可以获得信号,如以下测试示例所示。

在买入信号的情况下:

HA 结合 2EMA - 买入信号

正如我们在上一张图表中所见,我们在左上角有以下信号作为注释:

  • 买入信号
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

在卖出信号的情况下:

HA 结合 2EMA - 卖出信号

我们在图表上得到以下值作为信号:

  • 卖出信号
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

结束语

如果您已经理解了我们在本文中讨论的所有内容,那么您就应该能够自行创建自定义 Heiken Ashi 指标,甚至可以根据您的喜好添加更多功能。 这对于读取图表,并根据您的理解做出有效的决策非常有用。 除此之外,您将能够在您的交易系统中将此创建的自定义指标用于智能系统,因为我们曾在两个交易系统中提到并用它作为示例。

  • Heiken Ashi 系统
  • Heiken Ashi-EMA 系统

我希望您能发现本文对您很有用,并且您对它的主题或任何相关主题都有良好的见解。 我也希望您尝试应用您在文章中学到的知识,因为它在您的编程学习之旅中非常有用,因为练习是有效教育过程中非常重要的因素。 请注意,在真实账户中使用之前,您必须测试在本文或其它资源中学到的任何内容,因为如果它不适合您,则也许会伤害到您。 本文的主要目的只是教学,所以请您务必小心。

如果您发现这篇文章有用,并想阅读更多文章,您可以浏览作者的其它文章阅读更多内容。 我希望您能发现它们也很有用。

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/12510

附加的文件 |
开发回放系统 — 市场模拟(第 08 部分):锁定指标 开发回放系统 — 市场模拟(第 08 部分):锁定指标
在本文中,我们将亲眼见证如何在简单地利用 MQL5 语言锁定指标,我们将以一种非常有趣和迷人的方式做到这一点。
开发回放系统 — 市场模拟(第 07 部分):首次改进(II) 开发回放系统 — 市场模拟(第 07 部分):首次改进(II)
在上一篇文章中,我们针对复现系统进行了一些修复并加入了测试,以确保可能的最佳稳定性。 我们还着手为这个系统创建和使用配置文件。
以 MQL5 实现 ARIMA 训练算法 以 MQL5 实现 ARIMA 训练算法
在本文中,我们将实现一种算法,该算法应用了 Box 和 Jenkins 的自回归集成移动平均模型,并采用了函数最小化的 Powells 方法。 Box 和 Jenkins 表示,大多数时间序列可以由两个框架中之一个或两个来建模。
神经网络变得轻松(第三十八部分):凭借分歧进行自我监督探索 神经网络变得轻松(第三十八部分):凭借分歧进行自我监督探索
强化学习中的一个关键问题是环境探索。 之前,我们已经见识到基于内在好奇心的研究方法。 今天我提议看看另一种算法:凭借分歧进行探索。