探索创建多彩烛条的选项

29 十月 2021, 13:11
Samuel Manoel De Souza
0
707

概述

在本文中,我将探讨创建烛条图表自定义指标的可能性,并指出它们的优缺点。 我将在 4 个主题中定位这个话题:

1-构建只有一种颜色的蜡烛,且不区分高低蜡烛。

2-构建多彩蜡烛,颜色会根据一些业务规则上色。

3-构造有填充物和无填充物的蜡烛,区分填充物的颜色和蜡烛边缘的颜色。

4-构造有填充物和无填充物的多彩蜡烛。

首先,我们需要澄清在蜡烛图中实现上色规则的原因,以及为了创建您自己的指标,而进行正确选择的重要性。 鉴于用户与程序的交互,或者鉴于程序针对硬件的优化,每种方法都有其特殊性、优点和缺点。

我们首先研究一个适用于 3 个置换价格线的操作模型。 第一条线(黑色)是价格本身,第二条线(蓝色)是向前偏移 10 个周期的 1 周期移动平均线,第三条线(红色)是向前偏移 20 个周期的 1 周期移动平均线。 模型在价格图上的构建如下所示,在其中我插入了两条移动平均线,并将价格图更改为折线。

乍一看,这是一个不友好的模型,难以解释,因为它不仅需要辨别线条的颜色,还需要辨别它们之间的关系。 这通常会导致决策混乱和错误。 另一个可能导致混淆和错误的模型是方向走势指数指标,出于同样的原因,不仅需要辨别线条的颜色,还需要辨别它们之间的关系。

事实上,要考虑的变量或指标越多,解释错误就越频繁,导致决策和结果不一致。 我们可以使用任意数量的指标和变量,只要我们将这些数据转化为易于理解的客观信息即可。

采用上色规则是一种浓缩所有信息的有效方式,从而准确地告诉我们自己想知道什么:我们什么时候可以买入、卖出,以及什么时候应该离场。 所以我们可以合成 3 种颜色的信息。 一种针对买入,一种针对卖出,一种针对买入或卖出条件均不满足的情况。 在本文中,我用绿色代表买入,红色代表卖出,其它情况则用黄色。 下表总结了这一点。

颜色 方向
绿 做多
做空
 黄  中性

在这一点上,我们忘记蜡烛上色规则背后的交易规则,看看如何在 MQL5 中构建蜡烛图。 如果这是您第一次用 MQL5 为 Metatrader 5 创建程序,我建议您寻求 MetaEditor(Metatrader 5 开发环境)的帮助。


构建烛条图表

针对这一点,我将演示如何构建一个简单的烛条图表,并解释一些基本功能。 烛条图表由一序列烛条组成。 每根蜡烛均由四个骰子组成,即该周期的开盘价、最高价、最低价和收盘价。 为了知道所研讨的周期内是否存在高收或低收,需要验证收盘价是大于亦或小于开盘价。 如果它是一根高收蜡烛,我们将其上色为绿色,如果它是低收蜡烛,我们将其上色为红色。

我们从利用 MQL 向导创建指标开始。


我们为自己的指标命名,并更改版权信息,就是作者姓名和网页地址。


我们将调用以开盘价、最高价、最低价和收盘价序列作为参数的 OnCalculate 函数。


由于我们的指标将是烛条图表,故我们在“类型”中选择烛条图表,并将标签重命名为烛条。 该名称会出现在用户界面和处理指标缓冲区。


这是由我们的 MQL 向导生成的代码。

//+------------------------------------------------------------------+
//|                                                      Candles.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   1
//--- plot Candle
#property indicator_label1  "Candle"
#property indicator_type1   DRAW_CANDLES
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- indicator buffers
double         CandleBuffer1[];
double         CandleBuffer2[];
double         CandleBuffer3[];
double         CandleBuffer4[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,CandleBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,CandleBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,CandleBuffer3,INDICATOR_DATA);
   SetIndexBuffer(3,CandleBuffer4,INDICATOR_DATA);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---

//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

现在只需编译代码,我们的蜡烛指标即在 MetaTrader 5 的文件浏览器中就位。 但是,当您将其放置在价格图表上时,它无法正确显示,因为我们还没有给指标缓冲区赋予数值。 所以我们来完成这一步。 在第一种方法里,我们有 4 个缓冲区:CandleBuffer1 [], CandleBuffer2 [], CandleBuffer3 [], CandleBuffer4 []; 下表解释了这些缓冲区的用途。

缓冲区 价格序列
CandleBuffer1 开盘价
CandleBuffer2 最高价
CandleBuffer3 最低价
CandleBuffer4 收盘价

缓冲区的数量需要通过 indicator_buffers 属性在我们的代码中详细指定。 MQL 向导已经替我们完成了这项工作,但是您可以根据指标的需要更改缓冲区的数量。 我们稍后会这样做。

#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 4

我们将在 OnCalculated 函数中循环遍历整个价格范围,并为缓冲区赋值。 不过,一旦分配了数值,即使序列的大小增加,也不需要重新分配。 就这样。 如果在一个函数调用中我们有 n 根蜡烛,而在下一次调用中我们有 n + 1,我们只需要计算最后一根蜡烛的值。 在 OnCalcultate 函数中,图表中的蜡烛数量由 rate_total 参数通知,而在上次调用函数时图形中的蜡烛数由 prev_calculated 参数通知。

这是 OnCalculate 函数的处理结果。

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 = prev_calculated;
   if(start>=rates_total)
      start = rates_total-1;

   for(int i = start; i<rates_total; i++)
     {
      CandleBuffer1[i]=open[i];
      CandleBuffer2[i]=high[i];
      CandleBuffer3[i]=low[i];
      CandleBuffer4[i]=close[i];
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

请注意,在我们的指标中,所有蜡烛均为红色,这是我们在 MQL 向导中定义的颜色。 然而,这个颜色可由用户更改,也可以在我们的代码中通过 indicator_color1 属性更改。 若要了解有关在 MQL5 中定义和使用颜色的更多信息,请参阅有关 类型颜色 数据的文档。

//--- plot Candle
#property indicator_label1  "Candle"
#property indicator_type1   DRAW_CANDLES
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1


构建多彩烛条图表

到目前为止,我们已经看到了烛条图表的创建,没有区分颜色,或低收蜡烛和高收蜡烛。 我们现在将看到如何按照一些业务规则制作五彩缤纷的彩色蜡烛。 但首先,我们将遵照规则仅通过颜色区分高首或低收蜡烛。

您可以看到我们在指标类型 1 的指标属性中定义采用 DRAW_CANDLES 绘图类型。 我们可以将此属性更改为 DRAW_COLOR_CANDLES 以处理多色蜡烛。 由于绘图类型 DRAW_COLOR_CANDLES 需要存储每根蜡烛的颜色,故我们要有一个额外的缓冲区, 称为 CandleColor。 我们的缓冲区数量增加到 5。 此外,我们需要为 indicator_color1 属性添加颜色。

#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots   1
//--- plot Candle
#property indicator_label1  "Candle"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrGreen,clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- indicator buffers
double         CandleBuffer1[];
double         CandleBuffer2[];
double         CandleBuffer3[];
double         CandleBuffer4[];
double         CandleColor[];

然后我们初始化存储蜡烛颜色的新 CandleColor 缓冲区,通知编译器我们要用此缓冲区来存储颜色。 我们通过函数SetIndexBuffer 并传递INDICATOR_COLOR_INDEX 作为参数来完成这一点。 在我们的例子中,有两种颜色,绿色和红色,第一种颜色的索引为 0,第二种颜色的索引为 1。 如果我们在 indicator_color1 中定义了 n 种颜色,我们将拥有从 0 到 n-1 的颜色索引;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,CandleBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,CandleBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,CandleBuffer3,INDICATOR_DATA);
   SetIndexBuffer(3,CandleBuffer4,INDICATOR_DATA);
   SetIndexBuffer(4,CandleColor,INDICATOR_COLOR_INDEX);

//---
   return(INIT_SUCCEEDED);
  }

请注意,这些修改可以直接在 MQL 向导中进行,该向导定义和初始化缓冲区,以及所需的缓冲区数量。 只需在 MQL 向导窗口中将绘图类型参数更改为 DRAW_COLOR_CANDLES 及其颜色。 当您想要在图形上绘制不止一种绘图类型的指标时,这是一个非常有用的过程。 我们稍后会看到这一点。

现在我们需要为 CandleColor 缓冲区赋值。 我们来研究一个上色规则,即收盘价大于开盘价,因此它必须是绿色的,否则它必须是红色的。 我们看看它在 OnCalculate 函数中的样子。

   for(int i = start; i<rates_total; i++)
     {
      CandleBuffer1[i]=open[i];
      CandleBuffer2[i]=high[i];
      CandleBuffer3[i]=low[i];
      CandleBuffer4[i]=close[i];

      //if the close price is higher than the open price we set the 
      //green color (index 0), otherwise, the red color (index 1)
      CandleColor[i]=(close[i]>open[i])?0:1;
 

正如预期的那样,结果是一个标准图表,区分了看涨蜡烛和看跌蜡烛。

我们来修改上色规则。 我们将采用一个非常简单的交易规则,替代区分高收和低收蜡烛,且我们将在下一个主题中看到另一种区分高收和低收蜡烛的方法。

我们来研究一下本文开头介绍的操作模型。 我们拥有业务规则,如果黑线(收盘价)大于蓝线(10 个周期的收盘价)和红线(20 个周期的收盘价),那么我们就要做多。 如果黑线(收盘价)小于蓝线和红线,那么我们就要做空。 在其它情况下,我们必须等待行情方向的定义。 下表总结了该规则。

交易规则 烛条颜色
close[0] > close[10] 且 close[0] > close[20] 绿
close[0] < close[10] 且 close[0] < close[20]
close[0] > close[10] 且 close[0] < close[20]
 close[0] < close[10] 且 close[0] > close[20] 

对于这个模型,我们需要向 indicator_color1 属性添加一种颜色。

#property indicator_color1  clrGreen,clrRed,clrYellow

我们现在可以在我们的代码中定义规则,并根据它赋值。 这是 OnCalculate 函数内部的结果;

  {
//---
   int start = prev_calculated;
   if(prev_calculated<20)
      start = 20;
   if(start>=rates_total)
      start = rates_total-1;

   for(int i = start; i<rates_total; i++)
     {
      CandleBuffer1[i]=open[i];
      CandleBuffer2[i]=high[i];
      CandleBuffer3[i]=low[i];
      CandleBuffer4[i]=close[i];

      //Close[0] > Close[10] and Close[0] > Close[20]
      bool buy = close[i]>close[i-10] && close[i]>close[i-20];

      //Close[0] < Close[10] and Close[0] < Close[20]
      bool sell  = close[i]<close[i-10] && close[i]<close[i-20];

      CandleColor[i]=(buy)?0:(sell)?1:2;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }

这是我们新指标的结果。

现在,我们看看用户界面中的 Metatrader 5 指标参数窗口。 双击价格图表内的指标将打开参数窗口。 我们可在下图中看到,作为参数传递的颜色,并没有告知哪种颜色对应买入、卖出和中性条件。 如果我们想要用到更多颜色,例如 6 种颜色,这可能会令用户感到困惑。 故此我们需要向用户解释每种颜色所指的是什么含义。 我们将在本文的最后一个主题中执行此操作。



构建有填充和无填充的烛条图表

我们回到最初的代码,使用单一颜色的蜡烛。 请记住,我们采用了 DRAW_CANDLES 设计类型,带有 4 个缓冲区。 我们可以通过 indicator_color1 属性中定义的两种颜色来区分填充颜色和蜡烛边框的颜色。 所以第一种颜色将用于边缘,第二种颜色用于填充蜡烛。 出于演示目的,我们看看黑白结果。

#property indicator_type1   DRAW_CANDLES
#property indicator_color1  clrBlack,clrWhite

如果我们在 indicator_color1 属性中定义 3 种颜色,我们现在可以区分看涨蜡烛和看跌蜡烛。 这种蜡烛的构造形式取代了我们在本文中创建的第一个上色规则。 最大的区别是我们继续使用 4 个缓冲区,且我们可以定义边缘的颜色。 在这种情况下,第一种颜色应用于蜡烛的边缘,第二种颜色填充看涨蜡烛,第三种颜色填充看跌蜡烛。 下图演示了这种可能性,其中第三种颜色被定义为深灰色,从而区别于边缘。

#property indicator_type1   DRAW_CANDLES
#property indicator_color1  clrBlack,clrWhite,clrDarkGray

构建带填充和不带填充的多彩烛条图

为了完成我们在 MQL5 中创建多彩蜡烛的研究,我们打算令指标参数窗口中的用户界面拥有更多信息。 这是创建带填充物和不带填充物的多彩蜡烛的过渡步骤。 此外,两者所需的缓冲区数量相同,但高于目前所见版本中的缓冲区数量。 这是因为我们并不会绘制所有颜色,而是绘制选用的每种颜色。 在我们的模型中,我们有 3 种贴图,一张用于做多,一张用于做空,一张用于其它条件,如本文开头所述。 也就是说,我们将有 12 个缓冲区来实现这个模型。 此外,我们将根据之前看到的置换价格遵循相同的业务规则。

我们将再次使用 MQL 向导跳过定义和初始化 12 个缓冲区的步骤。 我们将使用做多、做空和中性设计,取代蜡烛类型设计。


我们不希望同时显示所有贴图。 根据业务规则,我们希望显示其中一张贴图,且隐藏其它贴图。 为此,必须用空值填充隐藏的蜡烛缓冲区。 第一步是定义应省略绘图的值。 我们调用 PlotIndexSetDouble 函数执行此操作,如下所示。

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BuyBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,BuyBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,BuyBuffer3,INDICATOR_DATA);
   SetIndexBuffer(3,BuyBuffer4,INDICATOR_DATA);
   SetIndexBuffer(4,SellBuffer1,INDICATOR_DATA);
   SetIndexBuffer(5,SellBuffer2,INDICATOR_DATA);
   SetIndexBuffer(6,SellBuffer3,INDICATOR_DATA);
   SetIndexBuffer(7,SellBuffer4,INDICATOR_DATA);
   SetIndexBuffer(8,NeutralBuffer1,INDICATOR_DATA);
   SetIndexBuffer(9,NeutralBuffer2,INDICATOR_DATA);
   SetIndexBuffer(10,NeutralBuffer3,INDICATOR_DATA);
   SetIndexBuffer(11,NeutralBuffer4,INDICATOR_DATA);

   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0);

//---
   return(INIT_SUCCEEDED);
  }

在我们的例子中,我们用数值 0.0 来定义缓冲区中的空值。 在 PlotIndexSetDouble 函数中作为第一个参数传递的值 0、1 和 2 是要绘制在价格图上的绘图的索引。 该索引值与我们声明的指标设计属性相同。

我们现在要做的就是处理我们的 OnCalculate 函数,应用之前创建的业务规则。 由于只需要显示一个贴图,故每次调用 OnCalculate 函数时,我们可以通过将数值 0.0 分配给所有蜡烛,如此即可将所有贴图定义为不可见。 接下来,我们根据业务规则,为图中所要显示的蜡烛分配开盘价、最高价、最低价和收盘价。 操作结果如下所示。

  {
//---
   int start = prev_calculated;
   if(prev_calculated<20)
      start = 20;
   if(start>=rates_total)
      start = rates_total-1;

   for(int i = start; i<rates_total; i++)
     {
      //initializing the candles data
      BuyBuffer1[i]=0.0;
      BuyBuffer2[i]=0.0;
      BuyBuffer3[i]=0.0;
      BuyBuffer4[i]=0.0;

      SellBuffer1[i]=0.0;
      SellBuffer2[i]=0.0;
      SellBuffer3[i]=0.0;
      SellBuffer4[i]=0.0;

      NeutralBuffer1[i]=0.0;
      NeutralBuffer2[i]=0.0;
      NeutralBuffer3[i]=0.0;
      NeutralBuffer4[i]=0.0;

      //Close[0] > Close[10] e Close[0] > Close[20]
      bool buy= close[i]>close[i-10] && close[i]>close[i-20];

      //Close[0] < Close[10] e Close[0] < Close[20]
      bool sell= close[i]<close[i-10] && close[i]<close[i-20];

      //Setting the values to the candles according to the trading rules
      if(buy)
        {
         BuyBuffer1[i]=open[i];
         BuyBuffer2[i]=high[i];
         BuyBuffer3[i]=low[i];
         BuyBuffer4[i]=close[i];
        }
      else
         if(sell)
           {
            SellBuffer1[i]=open[i];
            SellBuffer2[i]=high[i];
            SellBuffer3[i]=low[i];
            SellBuffer4[i]=close[i];
           }
         else
           {
            NeutralBuffer1[i]=open[i];
            NeutralBuffer2[i]=high[i];
            NeutralBuffer3[i]=low[i];
            NeutralBuffer4[i]=close[i];
           }

     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

视觉效果与之前使用 DRAW_COLOR_CANDLES 绘图类型所看到的完全相同。 后一种方法的巨大优势在于,尽管所需的缓冲区数量显著增加了,但我们将拥有更丰富信息的用户界面。 不过,我们不仅可以依据上色规则为我们提供有关业务规则的信息,而且还能提供看涨蜡烛和看跌蜡烛之间的区别,进一步拓展了这一优势。 这可以通过处理之前看到的蜡烛的边缘颜色和填充物来做到。 对于每种设计,我们希望低收蜡烛的边缘和填充颜色相同,而对于高收蜡烛,我们将用白色填充,对于白色背景的价格图表,这样会给人一种无填充蜡烛的错觉。 下表中简化了此颜色模式。

交易规则 边界 阳线填充 阴线填充
做多 绿 绿
做空
中性

我们代码的修改如下所示。

#property indicator_color1  clrGreen,clrWhite,clrGreen
#property indicator_color2  clrRed,clrWhite,clrRed
#property indicator_color3  clrYellow,clrWhite,clrYellow

如此,我们达成了本文的目标,即演示如何根据一些业务规则创建上色规则,并将其应用于有填充和无填充的蜡烛图表。 我们的最终工作成果如下图所示。


结束语

我们看到,我们可以使用两种类型的设计创建蜡烛图表,DRAW_CANDLES 和 DRAW_COLOR_CANDLES;我们也看到了,如何把基于交易规则的上色规则应用于蜡烛图表,以及如何区分边缘和填充蜡烛之间的颜色, 这令我们可以为蜡烛上色,从而区分看涨蜡烛和看跌蜡烛。 重点要注意,根据自定义指标的用途,低收烛条和高收烛条的区别可能无关紧要,且如果颜色数量太多,例如 10 种颜色,则后一种方法用着更不方便,因为它会过多地增加缓冲区的数量,并导致占用更多地用户硬件。

在这种情况下,有两个选项可以用来代替在指标的参数窗口中解释每种颜色的适用性。 您可用 DRAW_COLOR_CANDLES 设计类型,亦或 DRAW_CANDLES 设计类型,该设计中低收蜡烛边缘和填充均为透明,造成创建未填充蜡烛的错觉;根据业务规则上色,低收蜡烛的填充则是价格图表底部的颜色,实现看涨和看跌蜡烛之间的区别,叠加在 DRAW_COLOR_CANDLES 贴图上。


由MetaQuotes Software Corp.从英文翻译成
原始文章: https://www.mql5.com/en/articles/7815

DoEasy 函数库中的图形(第八十三部分):抽象标准图形对象类 DoEasy 函数库中的图形(第八十三部分):抽象标准图形对象类
在本文中,我将创建抽象图形对象类。 该对象用作创建标准图形对象类的基础。 图形对象拥有多种属性。 因此,在实际创建抽象图形对象类之前,我还需要做很多的准备工作。 这项工作包括在函数库的枚举中设置属性。
MetaTrader 5 中的出价/要价(Bid/Ask)点差分析 MetaTrader 5 中的出价/要价(Bid/Ask)点差分析
一款能为您报告经纪商平台出价/要价(Bid/Ask)水平的指标。 现在我们可以利用 MT5 的即时报价数据来分析近期的历史真实平均买卖点差是多少。 您不需要查看当前点差,因为若您同时显示出价和要价指示线时,该值已出示。
DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类 DoEasy 函数库中的图形(第八十四部分):抽象标准图形对象的衍生后代类
在本文中,我将研究为终端的抽象标准图形对象创建衍生后代对象。 该类对象定义了所有图形对象通用的属性。 因此,它只是某个种类的图形对象。 为了阐明它与真实图形对象的从属关系,我们需要在衍生后代对象类中设置该图形对象特定的固有属性。
DoEasy 函数库中的图形(第八十二部分):函数库对象重构和图形对象集合 DoEasy 函数库中的图形(第八十二部分):函数库对象重构和图形对象集合
在本文中,我将通过为每个对象分配唯一类型来改进所有库对象,并继续开发库图形对象集合类。