English Русский Español Deutsch 日本語 Português
preview
Heiken-Ashi指标与移动平均指标组合能够提供好的信号吗?

Heiken-Ashi指标与移动平均指标组合能够提供好的信号吗?

MetaTrader 5交易系统 | 29 一月 2024, 08:58
721 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

概述

策略的组合可能会提供更好的机会,我们可以把指标和形态一起使用,或者更进一步,多个指标和形态一起,这样我们可以获得额外的确认因子。在这篇文章中,我们将看到如何将Heiken-Ashi 图表和移动平均线作为趋势确认技术一起使用。然后,在最后,我们可以看看优化选项。

portada



Heiken-Ashi 蜡烛图方法

蜡烛图是理解OHLC数据和检测形态的快速方法,它非常简单易懂。当市场收盘价高于开盘价时,就会出现看涨(通常是绿色)烛形,当市场收盘价低于开盘价时,就会出现看跌(通常是红色)烛形。


烛形 ohlc


交易形态


让我们看一张完整的蜡烛图,以更好地了解它是如何显示的。趋势明显是看涨的,在红色烛形周围可以看到一些修正。注意那些小的烛形,它们的开盘价和收盘价几乎相同。这被称为Doji,意味着犹豫不决以及可能的逆转或企稳。

烛形


Heiken Ashi(也称为Heikin Ashi)烛形试图通过平滑OHLC数据来清理图片并显示更清晰的趋势。以下是如何计算Heiken Ashi烛形:

(open + high + low + close)  ÷  4


Heikin-Ashi High=Max value of (High-0, Open-0, and Close-0) 

Heikin-Ashi Low=Min value (Low-0, Open-0, and Close-0)


Heikin-Ashi是日本的一个交易指标和金融图表,意思是“平均速度”。Heikin-Ashi图表类似于蜡烛图,但由于它们跟踪一系列价格走势,而不是像蜡烛图那样跟踪每一个价格走势,因此外观更平滑。Heikin Ashi是18世纪由本间宗久(Munehisa Homma)发明的,他也发明了蜡烛图。交易员和投资者使用这些图表来帮助确定和预测价格走势。

像标准的蜡烛图一样,Heikin-Ashi 烛形也有实体和影线,然而,它们的用途与标准蜡烛图上的不同。Heikin Ashi蜡烛的最后价格是根据当前烛形或时间框架的平均价格计算的(例如,每日的时间框架将使每个烛形代表该特定日期的价格变动)。Heikin-Ashi 柱形或烛形最后价格的计算公式为:(open + high + low + close)  ÷  4。Heikin-Ashi 烛形的开盘价格是前一个烛形的中点,它的计算公式为:(前一个柱的开盘价+前一个柱的收盘价) ÷ 2。最高价和最低价的点和蜡烛图一样,由影线表示。

以上公式将使烛形变得平滑,给我们一个更明确的趋势。


heiken ashi (1) candles(2)


这两张图是一张普通的蜡烛图和Heiken-Ashi 图之间的比较。我们可以看到相似之处,但我们也可以看到第一个更平滑。然而,我们应该注意到,由于Heiken-Ashi方法只是一个平均值,所显示的价格可能不是真正的市场价格。


移动平均的概念

移动平均帮我们确认和驾驭趋势,它们是最为人所知的技术指标,这是因为它们的简单性和为分析增加价值的良好记录。我们可以使用它们来寻找支撑和阻力水平、止损点和目标以及潜在趋势。这种多功能性使它们成为我们交易武器库中不可或缺的工具。

在统计学中,移动平均值(滚动平均值或运行平均值,rolling average, running average)是通过创建完整数据集的不同选择的一系列平均值来分析数据点的计算。它也被称为移动平均(moving mean, MM)或滚动平均(rolling mean),是一种有限脉冲响应过滤器。变体包括:简单形式、累积形式或加权形式(如下所述)。

移动平均过滤器有时被称为箱式过滤器,尤其是在进行抽取之后。

给定一系列数字和固定子集大小,通过取数字序列的初始固定子集的平均值来获得移动平均值的第一个元素。然后通过“向前移动”来修改子集;即排除序列的第一个数并包括子集中的下一个值。

移动平均通常与时间序列数据一起使用,以平滑短期波动并突出长期趋势或周期。短期和长期之间的阈值取决于应用,移动平均线的参数将相应设置。它在经济学中也用于研究国内生产总值、就业或其他宏观经济时间序列。从数学上讲,移动平均是一种卷积,因此它可以被视为信号处理中使用的低通滤波器的一个例子。当与非时间序列数据一起使用时,移动平均值过滤较高频率的分量,而与时间没有任何特定的联系,尽管通常隐含某种排序。简单地看,它可以被视为平滑数据。


ma


顾名思义,这是你简单明了的意思,在统计数据中随处可见,基本上在我们生活的任何其他部分都可以使用。它只是观测值的总值除以观测值的数量。从数学上讲,它可以写为:

ma form


我们可以看到,移动平均线提供了不错的动态支撑和阻力水平,在市场下跌的情况下,我们可以从中下单。



计划

买入


与任何适当的研究方法一样,目的是测试该策略,并能够亲眼看看它是否值得作为我们现有交易框架的附加组件。

第一步是创建交易规则,这个系统什么时候买入,什么时候做空?换句话说,告诉系统当前市场将上涨或下跌的信号是什么时候发出的?

我们可以选择的交易条件有:

  • 每当Heikin-Ashi 图表看涨,而市场价格向上与100周期期移动平均线交叉时,做多(买入)。
  • 每当Heikin-Ashi 图表看跌,而市场价格向下与100周期期移动平均线交叉时,做空(卖出)。

当我们开发交易算法时,我们必须记住信号的频率。用于根据上述条件生成触发器的信号函数。



结果

这是在 EURUSD 30分钟时段图表上从2022年1月1日到2023年7月5日的运行结果。如果进行优化以及使用其它时段图表应该会有更好的结果。如果在所有交易品种上使用它,应该做优化和测试。

图表

策略测试器报告



代码

int OnInit()
  {
//---
   handle_iCustomMA=iCustom(_Symbol,my_timeframe,"\\folder/s where you have the indicator\\sma",MAPeriod,MAShift);
   handle_iCustomHeiken=iCustom(_Symbol,my_timeframe_Heiken,"\\folder/s where you have the indicator\\Heiken_Ashi_copy");
//---
   if(handle_iCustomMA==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(my_timeframe),
                  GetLastError());
      //--- the indicator is stopped early
      return(INIT_FAILED);
     }
   if(handle_iCustomHeiken==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  _Symbol,
                  EnumToString(my_timeframe_Heiken),
                  GetLastError());
      //--- the indicator is stopped early
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

此代码用于初始化MQL5语言中的两个自定义指标。第一个指标是使用MAPeriod和MAShift为参数的简单移动平均(Simple Moving Average, SMA),第二个指标是 Heiken Ashi。代码创建每个指标的句柄并且检查错误,如果发现错误,代码就打印错误编号并返回 INIT_FAILED 的值,如果没有发现错误,代码就返回 INIT_SUCCEEDED 的值。

void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(handle_iCustomHeiken,0,0,2,heikenAshiOpen);
   CopyBuffer(handle_iCustomHeiken,1,0,2,heikenAshiHigh);
   CopyBuffer(handle_iCustomHeiken,2,0,2,heikenAshiLow);
   CopyBuffer(handle_iCustomHeiken,3,0,2,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));
//---
   MqlTick tick;
   double last_price = tick.ask;
   SymbolInfoTick(_Symbol,tick);
   int total = PositionsTotal();
//---
// Retrieve the current value
   MqlTradeResult  result;
   MqlRates rates[];
//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos2=0,count2=5;
   if(!iGetArray2(handle_iCustomMA,0,start_pos2,count2,array_ma))
      return;
//------------------------------------------------------------------------------
     {
      if(DoubleToString(heikenAshiClose[0],_Digits) < DoubleToString(heikenAshiOpen[0],_Digits) && (DoubleToString(heikenAshiClose[1],_Digits) > DoubleToString(heikenAshiOpen[1],_Digits)))
        {
         Print("Open Order Buy");
         Alert(" Buying");
         Orden="Buy";
         sl=NormalizeDouble(tick.ask - ptsl*_Point,_Digits);
         tp=NormalizeDouble(tick.bid + pttp*_Point,_Digits);
         trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,get_lot(tick.bid),tick.bid,sl,tp,"Buy");
         return;
        }
     }
     {
      if(DoubleToString(heikenAshiClose[0],_Digits) > DoubleToString(heikenAshiOpen[0],_Digits) && (DoubleToString(heikenAshiClose[1],_Digits) < DoubleToString(heikenAshiOpen[1],_Digits)))
        {
         Print("Open Order Sell");
         Alert(" Selling");
         Orden="Sell";
         sl=NormalizeDouble(tick.bid + ptsl*_Point,_Digits);
         tp=NormalizeDouble(tick.ask - pttp*_Point,_Digits);
         trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,get_lot(tick.ask),tick.ask,sl,tp,"Sell");
         return;
        }
     }
   if(total>0)
     {
      if(Orden=="Sell" &&(DoubleToString(heikenAshiClose[0],_Digits) < DoubleToString(heikenAshiOpen[0],_Digits) ))
        {
         trade.PositionClose(_Symbol,5);
         Print("cerró sell");
         return;
        }
      if(Orden=="Buy" &&(DoubleToString(heikenAshiClose[0],_Digits) > DoubleToString(heikenAshiOpen[0],_Digits) ))
        {
         trade.PositionClose(_Symbol,5);
         Print("cerró buy");
         return;
        }
     }
  }

这段代码是一个MQL5脚本,用于在外汇市场中打开和关闭头寸。它首先声明四个double型数组(heikenAshiOpen、heikenAshiHigh、heikenAshiLow和heikenAshiClose),并从自定义指标“iCustomHeiken”中复制数值。然后,它从交易品种中取得当前的分时数据,并声明MqlTradeResult和MqlRates数组。然后,它为移动平均值声明一个数组(array_ma),并将该数组设置为一个序列。然后,它从自定义指标“iCustomMA”中读取数值,并将它们存储在array_ma数组中。最后,它检查当前 Heiken-Ashi 的收盘价是否低于开盘价,以及上一个 Heiken-Ashi 开盘价是否高于开盘价,如果是,它将打开一个具有指定止损和获利的买入订单。它还检查当前 Heiken-Ashi 收盘价是否高于开盘价,以及上一次 Heiken-Ashi 开盘价是否低于开盘价,如果是,它将打开一个具有指定止损和获利的卖出订单。如果有任何持仓,它会检查 Heiken-Ashi 的收盘价是否低于卖出订单的开盘价,高于买入订单的收盘价,如果是,它会平仓。

为了阐释清楚,CopyBuffer的第二个int是开始计数的位置的值,第三个是计数数量的值。我用的是2,而不是1,来处理1-n(在这种情况下,就是紧靠前方的Heiken Ashi烛形)。这已经在strat中用于查看if条件下的颜色变化,以打开或不打开订单。

打开或关闭订单的两个条件是您应该在代码中修改的条件,例如,您可以在打开订单之前使用更多相同颜色的烛形,或者跳到不同颜色的第二个烛形来关闭订单。

为了关闭订单,另一个好的解决方案是另一个具有不同周期数的SMA,并使用交叉信号来关闭订单,如图中所示:

heiken ashi 2 ma


//+------------------------------------------------------------------+
double get_lot(double price)
  {
   if(inp_lot_type==LOT_TYPE_FIX)
      return(normalize_lot(inp_lot_fix));
   double one_lot_margin;
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,one_lot_margin))
      return(inp_lot_fix);
   return(normalize_lot((AccountInfoDouble(ACCOUNT_BALANCE)*(inp_lot_risk/100))/ one_lot_margin));
  }
double normalize_lot(double lt)
  {
   double lot_step = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lt = MathFloor(lt / lot_step) * lot_step;
   double lot_minimum = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   lt = MathMax(lt, lot_minimum);
   return(lt);
  }
bool iGetArray2(const int handle2,const int buffer2,const int start_pos2,
                const int count2,double &arr_buffer2[])
  {
   bool result2=true;
   if(!ArrayIsDynamic(arr_buffer2))
     {
      //if(InpPrintLog)
      PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__);
      return(false);
     }
   ArrayFree(arr_buffer2);
//--- reset error code
   ResetLastError();
//--- fill a part of the iBands array with values from the indicator buffer
   int copied2=CopyBuffer(handle2,buffer2,start_pos2,count2,arr_buffer2);
   if(copied2!=count2)
     {
      //--- if the copying fails, tell the error code
      //if(InpPrintLog)
      PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d",
                  __FILE__,__FUNCTION__,count2,copied2,GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
   return(result2);
  }

此代码是MQL5中的一个函数,用于计算交易量的手数大小。该函数接受一个名为 price 的 double 类型的变量,并使用它来计算手数大小。 

函数首先检查手数类型是否是固定的,如果是,则返回规范化的手数大小。如果不是,它会计算一手的保证金,然后根据账户余额和风险百分比计算手数大小,在返回规范化的手数大小。 

然后使用 normalize_lot 函数将手数大小四舍五入到最接近的步长大小,并确保手数大小不小于最小手数大小。 

GetArray2函数用于从指标缓冲区复制数值并检查是否有任何错误,如果发现错误,函数就返回false。



结论

我们已经看到如何把 Heikin Ashi 指标与另一个指标一起使用。

显然,这里可以进行大量优化来调节信号的频率并提高其质量:

  • 我们可以选择与Heikin-Ashi图相关的条件,在该条件下,我们在连续烛形后触发信号。
  • 我们可以调整移动平均线的回顾周期期数。我们也可以添加其他移动平均线,并将策略切换到移动平均线交叉,而不是市场价格和单个移动平均线之间的简单交叉。
  • 我们可以在Heikin Ashi中包含蜡烛图,并与移动平均线相结合。
  • 我们还可以将 Heikin-Ashi接近移动平均线的距离作为风险的衡量标准,甚至作为反向触发因素。
  • 我们可以用蜡烛实体的宽度来衡量趋势的强度。我们还可以将移动平均线的陡度包括在公式中。

我们已经学会了如何实施这一策略,也学会了如何实现自定义指标。我们现在已经学会了使用固定手数或有一定百分比风险的手数。我们已经学习了如何打开和关闭订单,以及如何使用订单的条件。我们已经在Heiken-Ashi指标和MA指标上使用了CopyBuffer。我们进行了一次有获利的测试,并显示了结果。我们已经学习了如何为止损和获利添加点数,并使用交易品种的小数位数进行规范化。我们已经使用交易品种的交易量步长和交易品种交易量的最小值来规范化手数。

希望你喜欢这篇文章。

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

附加的文件 |
sma.mq5 (1.78 KB)
简单均值回归交易策略 简单均值回归交易策略
均值回归是一种逆势交易,交易者预估价格将返回到某种形式的均衡点位,通常依据均值或其它向心趋势统计值来衡量。
神经网络变得轻松(第四十六部分):条件导向目标强化学习(GCRL) 神经网络变得轻松(第四十六部分):条件导向目标强化学习(GCRL)
在本文中,我们要看看另一种强化学习方式。 它被称为条件导向目标强化学习(GCRL)。 按这种方式,代理者经过训练,可以在特定场景中达成不同的目标。
MQL5中的ALGLIB数值分析库 MQL5中的ALGLIB数值分析库
本文简要介绍了ALGLIB 3.19数值分析库、它的应用以及可以提高金融数据分析效率的新算法。
在 MQL5 中利用 ARIMA 模型进行预测 在 MQL5 中利用 ARIMA 模型进行预测
在本文中,我们继续开发构建 ARIMA 模型的 CArima 类,添加支持预测的直观方法。