English Русский Español Deutsch 日本語 Português
preview
如何利用 MQL5 检测蜡烛形态

如何利用 MQL5 检测蜡烛形态

MetaTrader 5交易 | 4 九月 2023, 10:52
1 803 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

概述

如果我们正确使用烛条,那么它们就是一种非常实用的技术工具,因为我们可以根据它们的形态发现潜在的走势。 蜡烛图可以在图表上形成特定的形态,这些形态可以分为两种类型的单蜡烛形态,和混合蜡烛形态(多于一根蜡烛)。 在本文中,我们将学习如何利用 MQL5 在 MetaTrader 5 交易终端中自动检测其中一些形态,我们将通过以下主题进行介绍:

我需要提示的是,这些形态与其它技术工具一起配合使用,对于获取有意义的信号非常重要。 故此,您需要理解利用 MQL5 检测上述形态的主要思想,使之成为您的交易系统的一部分,从而简化您的交易,并获得良好的结果。

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

单烛形态

在这一部分中,我们将看到两个常在图表上出现的单烛形态示例。 您可以在任何时间帧内看到它们,而当它们出现在与价格行为相对应的位置时,它会尤为重要。 我们将看到十字星(Doji)和锤子(Hammer)形态。

十字星(Doji)形态:

它在烛条形态中非常受欢迎,它是开盘价和收盘价几乎相同的蜡烛,我们能看到非常短小的蜡烛实体、或图表上的一条线,实体的顶底价格相同,甚至没有阴影。 下图就是这样的蜡烛:

十字星

这根十字星蜡烛表明买卖双方之间存在平衡,在价格出现的时间段内,没有人能控制市场将价格推高或拉低。 如果它在调整之前或趋势结束时出现在图表上的适当位置,则可能预示着市场的逆转或调整,如果它出现在更大的时间帧内,则它将更加重要。 蜡烛有很多类型和形成方式,每一个都有很多信息可用于我们的交易,如蜻蜓和长腿。

我们需要做的是通过定义最后一根蜡烛的价格和时间来通知计算机检测十字星形态,我们需要程序在这个定义的时间检查和比较这些值,并判定每一个的位置。 如果开盘价等于收盘价,我们需要程序返回一个信号,表明这是十字星蜡烛形态。

现在,我们需要创建一个可以检测此形态的程序,以下是执行此操作的方法步骤:

我们将针对这个十字星创建一个函数(getDoji),我们将在每次跳价 OnTick() 中调用它来检查搜索此形态

void OnTick()
  {
   getDoji();
  }

创建(getDoji) 函数,并返回整数型变量

int getDoji()

定义该函数需定义最后一根蜡烛的时间、开盘价、最高价、最低价和收盘价

调用 iTime 函数返回蜡烛开盘时间,调用 iOpen 返回蜡烛开盘价,调用 iHigh 返回最高价,调用 iLow 返回最低价,以及调用 iClose 返回蜡烛收盘价。 所有这些参数都相同:

  • symbol: 定义品种名称,我们将采用(_Symbol)对应当前交易品种。
  • timeframe: 定义图表的周期或时间帧,我们将采用(PERIOD_CURRENT)对应当前时间帧。
  • shift: 定义返回值的柱线索引,我们将采用(1)对应最后一根蜡烛。
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);

使用 if 语句设置我们需要检测的十字星的条件

if(open==close)

如果此条件为 true,我们需要程序基于 createObj 函数创建一个对象,我们将依据时间、价格、箭头代码、颜色和我们需要的文本等参数创建该函数。 然后在函数终止时返回 1。

   if(open==close)
     {
      createObj(time,low,217, clrBlack,"Doji");
        {
         return 1;
        }
     }

我们将返回 0 来终止 getDoji 函数

   return 0;

以 void 数据类型创建(createObj)函数,其中包含时间、价格、箭头代码、颜色和文本的参数

void createObj(datetime time, double price, int arrawCode, color clr, string txt)

创建字符串变量(objName),并分配(“ ”)值

string objName=" ";

调用(StringConcatenate)函数将字符串合并为一,并将它们分配给(objName)变量,该函数把所传递参数的字符串合并,并返回所形成字符串的总长。 其参数是:

  • string_var: 定义连接后将形成的字符串,我们将采用(objName)。
  • argument1: 定义任何简单类型的参数,我们将采用 “Signal at  ” 文本。
  • argument2: 定义检测到的蜡烛时间,我们将采用预设变量的时间。
  • argument3: 我们将文本设置为 " at "。
  • argument4: 我们将调用 DoubleToString 将双精度类型转换为字符串类型,并取四舍五入价格来设置文本。
  • argument5: 我们将文本设置为 " ("。
  • argument6: 我们将为所需的预定整数型变量(箭头代码)分配一个数值。 可以通过在 mql5 参考中搜索 Wingdings 来找到此代码。
  • argument7: 我们将文本设置为 ")"。
StringConcatenate(objName, "Signal at ",time, " at ",DoubleToString(price,_Digits)," (",arrawCode,")");

我们将使用 if 语句和(ObjectCreate)函数作为表达式来设置要评估的条件,(ObjectCreate)函数采用预定义的名称(objName)为我们创建一个对象,其参数为:

  • chart_id: 为了识别图表,我们将采用 0 对应当前图表。
  • name: 定义对象名称,我们将采用预定义的名称(objName)。
  • type: 定义对象类型,我们将采用(OBJ_ARROW)。
  • nwin: 定义图表子窗口的编号,我们将采用(0) 对应主图表窗口。
  • time1: 定义锚点的时间,我们将采用预定义的(time)变量。
  • price1: 定义锚点的价格,我们将采用预定义的(price)变量。
if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))

如若创建对象实现此条件后,我们需要通过调用设置对象属性值的(ObjectSetInteger)函数确定箭头代码和颜色,并设置对象属性值。 其参数是:

  • chart_id: 为了识别图表,我们将采用 0 对应当前图表。
  • name: 定义对象名称,我们将采用(objName)。
  • prop_id: 定义对象的属性,我们将采用 ENUM_OBJECT_PROPERTY_INTEGER 中之一,即箭头代码的(OBJPROP_ARROWCODE)和颜色的(OBJPROP_COLOR)。
  • prop_value: 定义属性值,我们将采用(arrawCode)对应箭头代码,并采用预定义变量(clr)对应颜色。
ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);

之后,我们需要定义所需的蜡烛文本,即创建一个字符串变量(candleName),并赋值预定义的(objName)和(txt)变量

string candleName=objName+txt;

利用 if 语句创建文本并编辑对象,其中(ObjectCreate)函数作为表达式,操作符是调用(ObjectSetString)设置对象属性的字符串值,以及调用(ObjectSetInteger)设置文本对象的颜色。

      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);

现在,我们可以看到该智能系统的完整代码,如下所示:

//+------------------------------------------------------------------+
//|                                        Doji pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getDoji();
  }
int getDoji()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
//Doji
   if(open==close)
     {
      createObj(time,low,217, clrBlack,"Doji");
        {
         return 1;
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal at ",time, " at ",DoubleToString(price,_Digits)," (",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

编译此代码后,若没有错误,我们可以在导航器窗口中找到它。 通过拖动它来执行,我们可以得到它检测十字星模式的信号,以下是测试的示例:

十字星示例

正如我们在上面一张图表中看到的,我们在蜡烛下方有一个黑色箭头对象和十字星文本来定义蜡烛形态。

锤子(Hammer)形态:

锤子形态是一种非常流行的烛条形态,我们可在许多时间帧的图表上看到它。 它的名字指的是它的形状,因为它有一个长长的阴影和一段小的实体,根据小实体的位置有两种类型的锤子形态,锤子和倒锤。 如果它有一个很长的下影线,蜡烛的实体在上面,它是一个锤子,基于开盘价和收盘价,它即可是一个看涨亦或看跌的蜡烛,下图是这个锤子形态的例子:

  • 看涨锤子

看涨锤子

这表明卖方试图压低价格,但买方控制市场,且收盘价高于开盘价,这意味着买方强势。

  • 看跌锤子

看跌锤子

这表明卖方试图压低价格,但买方把收盘价控制在开盘价附近,这意味着买方仍在游戏中。

如果蜡烛有一个长上影线,它的实体在下面,它是一个倒锤形态,根据开盘价和收盘价的位置,它即也可看涨亦或看跌。 下图是这种倒锤的示例。

  • 看涨倒锤

看涨倒锤

这表明买方试图推高价格,但卖方把收盘价控制在开盘价附近且以低点收盘,这意味着尽管买方的实力很强,但卖方仍在游戏中。

  • 看跌倒锤

看跌倒锤

它表明买方试图推低价格,但卖方控制市场,且收盘价低于开盘价,这意味着卖方的强势。

这种形态也与所有烛条形态相同,当它与其它技术工具结合使用时,将更加有意义。 

现在,我们需要创建一个可检测这种形态的程序,如此我们就能让程序找出蜡烛价格、时间和蜡烛大小,并与蜡烛的实体和阴影进行比较,我们需要程序在每次跳价中不断检查和比较它们,来判定它们的位置。 当程序检测到锤子或倒锤子之一(看涨或看跌)时,我们需要程序返回图表上的一个对象,其类型名称和箭头颜色为绿色或红色,并且基于蜡烛的颜色(看涨或看跌),将其绘制在蜡烛下方或上方。

以下是创建此类程序的完整代码:

//+------------------------------------------------------------------+
//|                                      Hammer pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getHammer(0.07,0.7);
  }
int getHammer(double smallShadowRatio, double longShadowRatio)
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double candleSize=high-low;
   if(open<close)
     {
      if(high-close < candleSize*smallShadowRatio)
        {
         if(open-low>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Hammer");
           {
            return 1;
           }
        }
     }
   if(open>close)
     {
      if(high-open<candleSize*smallShadowRatio)
        {
         if(close-low>candleSize*longShadowRatio)
            createObj(time,high,218,clrRed,"Hammer");
           {
            return 1;
           }
        }
     }
   if(open<close)
     {
      if(open-low < candleSize*smallShadowRatio)
        {
         if(high-close>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
   if(open>close)
     {
      if(close-low < candleSize*smallShadowRatio)
        {
         if(high-open>candleSize*longShadowRatio)
            createObj(time,high,218, clrRed,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

此代码中的区别与以下内容相同:

在 OnTick() 中,按确定的所需参数 smallShadowRatio 和 longShadowRatio 调用 getHammer 函数

void OnTick()
  {
   getHammer(0.07,0.7);
  }

创建(getHammer)函数,其中用到两个双精度变量(smallShadowRatio)和(longShadowRatio)作为参数

int getHammer(double smallShadowRatio, double longShadowRatio)

创建一个双精度变量(candleSize),以便与比率进行比较,

double candleSize=high-low;

锤形蜡烛的条件,

在看涨锤(开盘价<收盘价)的情况下,我们需要最后一根看涨蜡烛,蜡烛的上影线(最高价-收盘价)小于短影线的比率为 0.07,下影线(开盘价-最低价)大于长影线比率 0.7。 取 Wingdings 代码(217)和 “Hammer” 文本对象,创建一个绿色箭头,在图表上的位置低于该锤子蜡烛最低价,然后退出该函数。

   if(open<close)
     {
      if(high-close < candleSize*smallShadowRatio)
        {
         if(open-low>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Hammer");
           {
            return 1;
           }
        }
     }

在看跌锤(开盘价>收盘价)的情况下,我们需要最后一根看跌蜡烛,蜡烛的上影线(最高价-开盘价)小于短影线的比率为 0.07,下影线(收盘价-最低价)大于长影线比率 0.7。 取 Wingdings 代码(218)和 “Hammer” 文本对象,创建一个红色箭头,在图表上的位置高于该锤子蜡烛最高价,然后退出该函数。

   if(open>close)
     {
      if(high-open<candleSize*smallShadowRatio)
        {
         if(close-low>candleSize*longShadowRatio)
            createObj(time,high,218,clrRed,"Hammer");
           {
            return 1;
           }
        }
     }

在看涨倒锤(开盘价<收盘价)的情况下,我们需要最后一根看涨蜡烛,蜡烛的下影线(开盘价-最低价)小于短影线的比率为 0.07,上影线(最高价-收盘价)大于长影线比率 0.7。 取 Wingdings 代码(217)和 “Inverted Hammer” 文本对象,创建一个绿色箭头,在图表上的位置低于该锤子蜡烛最低价,然后退出该函数。

   if(open<close)
     {
      if(open-low < candleSize*smallShadowRatio)
        {
         if(high-close>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Inverted Hammer");
           {
            return -1;
           }
        }
     }

在看跌倒锤(开盘价>收盘价)的情况下,我们需要最后一根看涨蜡烛,蜡烛的下影线(收盘价-最低价)小于短影线的比率为 0.07,上影线(最高价-开盘价)大于长影线比率 0.7。 取 Wingdings 代码(218)和 “Inverted Hammer” 文本对象,创建一个红色箭头,在图表上的位置高于该锤子蜡烛最高价,然后退出该函数。

   if(open>close)
     {
      if(close-low < candleSize*smallShadowRatio)
        {
         if(high-open>candleSize*longShadowRatio)
            createObj(time,high,218, clrRed,"Inverted Hammer");
           {
            return -1;
           }
        }
     }

我们使用 “if” 运算符根据蜡烛类型编辑箭头位置和颜色。 表达式将是颜色,而 “if” 运算符(如果为 true)将在 ObjectSetInteger 函数的帮助下设置箭头位置。

如果其为绿色则在蜡烛下方

      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);

如果其为红色则在蜡烛上方

      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);

编译此代码,若没有错误,则执行它后,我们可以得到我们的信号,以下是测试示例:

  • 看涨锤子:

看涨锤子示例

正如我们所见,我们在图表上有一个绿色箭头和 “Hammer” 文本对象,低于看涨的锤子蜡烛的最低价。

  • 看跌锤子:

看跌锤子示例

正如我们所见,我们在图表上有一个红色箭头和 “Hammer” 文本对象,高于看涨的锤子蜡烛的最高价。

  • 看涨倒锤

看涨倒锤示例

正如我们所见,我们在图表上有一个绿色箭头和 “Inverted Hammer” 文本对象,低于看涨倒锤蜡烛的最低价。

  • 看跌倒锤:

看跌倒锤示例

正如我们所见,我们在图表上有一个红色箭头和 “Inverted Hammer” 文本对象,高于看涨倒锤蜡烛的最高价。

双烛形态

在这一部分中,我们将看到另一种由两根蜡烛组成的烛台形态,我们将见识两种流行的形态,它们是吞噬(看涨和看跌),和看涨刺透线及其相反的看跌乌云形态。

吞噬形态:

这种烛条形态在图表和技术分析中也非常流行,它由两根蜡烛组成,其中一根吞没另一根,这意味着它有一根小蜡烛,然后是一根较大的蜡烛,而这个较大的蜡烛完全覆盖了较小的蜡烛。

根据蜡烛的颜色或类型,这种吞噬形态有多种类型:

  • 看涨吞噬:

它有一根较小的看跌蜡烛,然后是一根较大的看涨蜡烛,这根看涨蜡烛吞没了较小的蜡烛,下图是它:

看涨吞噬

取决于其显著性,它表明买方控制市场,价格可能会在之后继续上涨。

  • 看跌吞噬:

它有一根较小的看涨蜡烛,然后是一根较大的看跌蜡烛,这根看跌蜡烛吞没了较小的蜡烛,下图是它:

看跌吞噬

取决于其显著性,它表明卖方控制市场,价格可能会在之后继续下降。

现在,如果我们想创建一个可自动检测此形态的程序,我们需要定义最后一根蜡烛的时间,和最后两根蜡烛的价格,我们需要程序在每次跳价时连续检查这些值,并判定其彼此相关的位置,从而验证我们是否得到了这种类型的吞噬形态。 一旦我们得到了这个吞噬形态,我们需要程序返回一个特定的信号,这是一个基于其类型(看涨或看跌)的彩色箭头和文本对象。

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

//+------------------------------------------------------------------+
//|                                   Engulfing pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getEngulfing();
  }
int getEngulfing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(high>high2&&low<low2)
           {
            if(close>open2&&open<close2)
              {
               createObj(time,low,217, clrGreen,"Bullish Engulfing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(high>high2&&low<low2)
           {
            if(close<open2&&open>close2)
              {
               createObj(time,high,218, clrRed,"Bearish Engulfing");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

此代码的不同之处:

创建双精度变量,在创建(getEngulfing)函数里,保存最后一根蜡烛的时间,和最后两根蜡烛的价格,time、open、high、low 和 close 对应最后一根蜡烛,open2、high2、low2 和 close2 对应最后一根之前的那根蜡烛

   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);

定义此类蜡烛形态的条件

在看涨吞噬的情况下,最后一根蜡烛是看涨的(open<close),最后一根蜡烛的前一根是看跌的(open2>close2),high>high2,且 low<low2,close>open2,且 open<close2。 一旦识别出后,基于已创建的函数 (createObj),按照以下参数创建一个对象:

  • time: 这是最后一根蜡烛的时间,这是预定义的变量。
  • price: 这是最后一根蜡烛的最低价,我们需要它下面的对象。
  • arrowCode: 它是来自 Wingdings 的代码 217。
  • clr: 它是 clrGreen。
  • txt: 它是 "Bullish Engulfing"。

然后终止函数。

   if(open<close)
     {
      if(open2>close2)
        {
         if(high>high2&&low<low2)
           {
            if(close>open2&&open<close2)
              {
               createObj(time,low,217, clrGreen,"Bullish Engulfing");
                 {
                  return 1;
                 }
              }
           }
        }
     }

在看跌吞噬的情况下,最后一根蜡烛是看跌的(open>close),最后一根蜡烛的前一根是看涨的(open2<close2),high>high2,且 low<low2,且 close<open2,且 open>close2。 一旦识别出后,基于已创建的函数 (createObj),按照以下参数创建一个对象:

  • time: 这是最后一根蜡烛的时间,这是预定义的变量。
  • price: 这是最后一根蜡烛的最高价,我们需要把对象放在它的上方。
  • arrowCode: 它是来自 Wingdings 的代码 218。
  • clr: 它是 clrRed。
  • txt: 它是 "Bearish Engulfing"。

然后终止函数。

   if(open>close)
     {
      if(open2<close2)
        {
         if(high>high2&&low<low2)
           {
            if(close<open2&&open>close2)
              {
               createObj(time,high,218, clrRed,"Bearish Engulfing");
                 {
                  return -1;
                 }
              }
           }
        }
     }

在编译此代码,且没有错误,并执行其 EA 后,我们可以从测试中获得其信号,如以下示例所示:

  • 看涨吞噬:

看涨吞噬示例

正如我们在上一张图表上所见,我们在形态中最后一根蜡烛的低点下方有一个绿色箭头和看涨吞噬文本。

  • 看跌吞噬:

看跌吞噬示例

正如我们在上一张图表上所见,我们在形态中最后一根蜡烛的高点上方有一个红色箭头和看跌吞噬文本。

刺透线和乌云盖顶形态:

  • 刺透线形态:

它是一根看涨烛条,由两根蜡烛组成,因为第一根蜡烛是看跌的,然后是一根开盘低于看跌的看涨蜡烛,然后向上移动并收于第一根看跌蜡烛的中点上方。 下图是示意它的图例:

刺透线

它表明买方自卖方控盘下突围,变得更强大,并控制市场。 因此,它指的是从卖出到买入的转变,因为买方能够将价格推高到前一根看跌蜡烛的中点以上,尽管开盘时存在缺口。

  • 乌云盖顶形态:

它与刺透线形态相反,因为它是一种看跌形态,具有两根蜡烛结构,第一根是看涨的,然后是带有开仓缺口的看跌蜡烛,收盘价低于第一根看涨形态的中点。 下图是它的图例:

乌云盖顶形态

它表明卖方自买方控盘下突围,变得更强大,并控制市场。 因此,它指的是从买入到卖出的转变,因为卖方能够将价格压低到前一根看涨蜡烛的中点以下,尽管开盘时存在缺口。

当我们想要创建一个可检测此类形态的程序时,我们需要定义第一根蜡烛的时间和价格(time、open、high、low 和 close),以及第二根蜡烛的价格(open2、high2、low2 和 close2)、第一根蜡烛的蜡烛大小 (candleSize2) 和倒数第二根蜡烛的中点(candleMidPoint2)。 我们需要程序不断检查这些数值,并判定它们彼此的相对位置,并根据看涨或看跌的特定条件返回特定信号。

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

//+------------------------------------------------------------------+
//|                      Piercing && Dark Cloud pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getPiercing();  
  }
int getPiercing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double candleSize2=high2-low2;
   double candleMidPoint2=high2-(candleSize2/2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(open<low2)
           {
            if(close>candleMidPoint2&&close<high2)
              {
               createObj(time,low,217, clrGreen,"Piercing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(open>high2)
           {
            if(close<candleMidPoint2&&close>low2)
              {
               createObj(time,high,218, clrRed,"Dark Cloud");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

此代码的不同之处

定义 candleSize2 和 candleMidPoint2

   double candleSize2=high2-low2;
   double candleMidPoint2=high2-(candleSize2/2);

形态的条件

若为刺透线形态的情况:

如果最后一根蜡烛看涨(open<close),open2>close2,open<low2,close>candleMidPoint2,且 close<high2,我们需要程序在图表上返回一个带有绿色箭头的对象,并在形态低点下方返回 “Piercing” 的文本, 然后终止函数。

   if(open<close)
     {
      if(open2>close2)
        {
         if(open<low2)
           {
            if(close>candleMidPoint2&&close<high2)
              {
               createObj(time,low,217, clrGreen,"Piercing");
                 {
                  return 1;
                 }
              }
           }
        }
     }

若为乌云盖顶形态的情况:

如果最后一根蜡烛看跌(open>close),open2<close2,open>low2,close<candleMidPoint2,且 close>high2,我们需要程序在图表上返回一个带有红色箭头的对象,并在形态高点上方返回 “Dark Cloud” 的文本, 然后终止函数。

   if(open>close)
     {
      if(open2<close2)
        {
         if(open>high2)
           {
            if(close<candleMidPoint2&&close>low2)
              {
               createObj(time,high,218, clrRed,"Dark Cloud");
                 {
                  return -1;
                 }
              }
           }
        }
     }

编译此代码,并执行其 EA 后,我们可从测试中获得与以下示例相同的所需信号:

  • 刺透线形态

刺透线示例

正如我们在上一张图表中所见,我们在形态低点下方有绿色箭头和刺穿文本,与我们需要的相同。

  • 乌云盖顶形态:

乌云盖顶形态示例

正如我们在上一张图表中所见,我们在形态高点上方有红色箭头和乌云盖顶文本,与我们需要的相同。

三烛形态

在这一部分中,我们将看到混合形态中的两种形态,它们是星形(Star)形态(晨星、暮星),和三个内部形态(向上、向下)。

星形(Star)形态:

  • 晨星:

它与我们提过的三根蜡烛结构相同。 它由两根蜡烛之间的小蜡烛形成,第一根是较长看跌,第二根是较长看涨。 下图是它的图例:

晨星

取决于其显著性,它表明推动力从卖出转向买入,因为自卖方控制下的压低后,买方控制市场,并推高价格。

  • 暮星形态:
它与我们提过的三根蜡烛结构相同。 它由两根蜡烛之间的小蜡烛形成,第一根是较长看涨,第二根是较长看跌。 下图是它的图例:

暮星

取决于其显著性,它表明推动力从买入转向卖出,因为自买方控制下的推高后,卖方控制市场,并压低价格。

当我们想要创建一个可检测这种形态的程序时,我们需要定义最后一根蜡烛的时间和价格,以及最后一根蜡烛之前两根蜡烛的价格数据,之前第三根蜡烛的大小,并将它们相互比较,以便判定它们彼此的相对位置,从而根据特定条件获得特定信号。

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

//+------------------------------------------------------------------+
//|                                        Star pattern detector.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"
void OnTick()
  {
   getStar(0.5);
  }
int getStar(double middleCandleRatio)
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   double candleSize=high-low;
   double candleSize2=high2-low2;
   double candleSize3=high3-low3;
   if(open<close)
     {
      if(open3>close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,low,217, clrGreen,"Morning Star");
              {
               return 1;
              }
           }
        }

     }
   if(open>close)
     {
      if(open3<close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,high,218, clrRed,"Evening Star");
              {
               return -1;
              }
           }
        }

     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

此代码的不同之处

依据 middleCandleRatio 参数,创建(getStar)

int getStar(double middleCandleRatio)

创建变量保存最后一根蜡烛时间和价格数据(open、high、low、close),和最后三根蜡烛的大小(candlesize、candleSize2 和  candleSize3

   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   double candleSize=high-low;
   double candleSize2=high2-low2;
   double candleSize3=high3-low3;

形态的条件

若为晨星形态的情况:

如果最后一根蜡烛看涨(open<close),第三根蜡烛看跌(open3>close3),candleSize2<candleSize 的 middleCandleRatio 0.5,同时 candleSize2<candleSize3 的 middleCandleRatio,我们需要程序在形态低点下方返回一个绿色箭头对象,和 “Morning Star” 文本, 然后终止函数。

   if(open<close)
     {
      if(open3>close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,low,217, clrGreen,"Morning Star");
              {
               return 1;
              }
           }
        }
     }

若为暮星形态的情况:

如果最后一根蜡烛看跌(open>close),第三根蜡烛看涨(open3<close3),candleSize2<candleSize 的 middleCandleRatio 0.5,同时 candleSize2<candleSize3 的 middleCandleRatio,我们需要程序在形态低点下方返回一个红色箭头对象,和 “Evening Star” 文本, 然后终止函数。

   if(open>close)
     {
      if(open3<close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,high,218, clrRed,"Evening Star");
              {
               return -1;
              }
           }
        }
     }

在编译此代码,且没有错误,并执行其 EA 后,我们可从测试中获得与以下示例相同的信号:

  • 晨星:

晨星示例

如我们所见,我们在检测到的形态下方的图表上得到所需对象的期望信号。

  • 暮星:

暮星示例

如我们所见,我们在检测到的形态下方的图表上得到所需对象的期望信号。

作为星形形态的注解,相同的形态形成与中间的小蜡烛有间隙,如果您想获得相同的形态,可以将其作为附加条件添加到代码之中。

三内含形态:

  • 三内含向上:

这也是三根蜡烛形态,第一根蜡烛是较长看跌,第二根是较短看涨蜡烛,且全部在第一根蜡烛内部,第三根是较长看涨蜡烛,收于第一根高点上方。 以下是此形态的图例。

三内含向上

取决于其显著性,它表明买方控制的潜在看涨。

  • 三内含向下:

这也是三根蜡烛形态,第一根蜡烛是较长看涨,第二根是较短看跌蜡烛,且全部在第一根蜡烛内部,第三根是较长看跌蜡烛,收于第一根低点下方。 以下是此形态的图例。

三内含向下

取决于其显著性,它表明卖方控制的潜在看跌。 如果我们想创建一个可检测此类形态的程序,我们还需定义最后一根蜡烛的时间和最后三根蜡烛的价格数据,程序会在每次跳价时检查这些数值,并判定其彼此的相对位置,以便根据形态返回相应的信号作为图表上的对象。 以下是该程序的完整代码:
//+------------------------------------------------------------------+
//|                                Three inside pattern detector.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"
void OnTick()
  {
   getthreeInside();
  }
int getthreeInside()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   if(open3>close3)
     {
      if(open2<close2)
        {
         if(open2>low3&&close2<high3)
           {
            if(open<close&&open>open2&&open<close2)
              {
               if(close>high3)
                 {
                  createObj(time,low,217, clrGreen,"3 Inside Up");
                    {
                     return 1;
                    }
                 }
              }
           }
        }

     }
   if(open3<close3)
     {
      if(open2>close2)
        {
         if(open2<high3&&close2>low3)
           {
            if(open>close&&open<open2&&open>close2)
              {
               if(close<low3)
                 {
                  createObj(time,high,218, clrRed,"3 Inside Down");
                    {
                     return -1;
                    }
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

此代码中的不同之处在于形态的条件

若为三内含向上情况

   if(open3>close3)
     {
      if(open2<close2)
        {
         if(open2>low3&&close2<high3)
           {
            if(open<close&&open>open2&&open<close2)
              {
               if(close>high3)
                 {
                  createObj(time,low,217, clrGreen,"3 Inside Up");
                    {
                     return 1;
                    }
                 }
              }
           }
        }

     }

若为三内含向下情况

   if(open3<close3)
     {
      if(open2>close2)
        {
         if(open2<high3&&close2>low3)
           {
            if(open>close&&open<open2&&open>close2)
              {
               if(close<low3)
                 {
                  createObj(time,high,218, clrRed,"3 Inside Down");
                    {
                     return -1;
                    }
                 }
              }
           }
        }
     }

编译此代码,并执行其 EA 后,我们可以获得与以下示例相同的信号:

  • 三内含向上:

三内含向上示例

正如我们在图表上所见,我们得到期望的三内含向上信号。

  • 三内含向下:

三内含向下示例

正如我们在图表上所见,我们得到期望的三内含向下信号。

结束语

在本文前面的主题之后,假设您已经了解了如何编写代码来检测不同形态(单烛、双烛和三烛形态)的烛条形态:

  • 单烛形态:我们学习了如何检测十字星和锤形形态。
  • 双烛形态:我们学习了如何检测吞噬、刺透线和乌云盖顶形态。
  • 三烛形态:我们学习了如何创建一个可以检测星状形态和三内含形态的程序。

我希望您能发现本文对您获得更佳的见解很有用。

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

利用 MQL5 实现 Janus 因子 利用 MQL5 实现 Janus 因子
加里·安德森(Gary Anderson)基于他称之为Janus因子的理论,开发了一套市场分析方法。 该理论描述了一套可揭示趋势和评估市场风险的指标。 在本文中,我们将利用 mql5 实现这些工具。
MQL5 中的范畴论 (第 5 部分):均衡器 MQL5 中的范畴论 (第 5 部分):均衡器
范畴论是数学的一个多样化和不断扩展的分支,直到最近才在 MQL5 社区中得到一些报道。 这些系列文章旨在探索和验证一些概念和公理,其总体目标是建立一个开放的函数库,提供洞察力,同时也希望进一步在交易者的策略开发中运用这个非凡的领域。
开发回放系统 — 市场模拟(第 05 部分):加入预览 开发回放系统 — 市场模拟(第 05 部分):加入预览
我们已设法开发了一套以逼真和可访问的方式来实现市场回放的系统。 现在,我们继续我们的项目,并添加数据,从而提升回放行为。
如何在 MQL5 中使用 ONNX 模型 如何在 MQL5 中使用 ONNX 模型
ONNX(开放式神经网络交换)是一种开源的机器学习模型格式。 在本文中,我们将研究如何创建 CNN-LSTM 模型,来预测金融时间序列。 我们还将展示如何在 MQL5 智能系统中运用创建的 ONNX 模型。