多交易品种多周期指标中的颜色缓冲区·进阶篇
🎨

多交易品种多周期指标中的颜色缓冲区·进阶篇

(2/3)·单色缓冲区复制易上手,多色索引数组却常让跨周期绘制踩坑,本篇拆开讲清

含代码示例实战向 第 2/3 篇
不少人在写多交易品种多周期指标时,直接把单色缓冲区的 CopyBuffer 逻辑套到彩色线上,结果图表只显示一种颜色或干脆不画。颜色索引数组若没同步跨周期传递,绘制部分就拿不到对应的色彩映射。

◍ 多缓冲区的绑定与空算骨架

在 MT5 自定义指标里,一个绘图缓冲(plot)可以挂多组数据数组。上面这段把第 4 个 plot 绑了 2 个数据数组加 1 个颜色索引数组(索引 9/10/11),第 5 个 plot 直接绑了 4 根线(Open/High/Low/Close)加颜色索引,共占 5 个 buffer 槽位(12~16)。这种写法适合把 OHLC 四价或双线组合画在同一个子图里,省去重复建指标的麻烦。 OnCalculate 这里故意写成直接 return(rates_total),没有写任何计算逻辑。也就是说指标加载后每根 K 线都会触发,但缓冲里没填数,图表上什么都不会画——这通常是先搭好 buffer 框架、后续再补绘制代码的占位结构。 外汇与贵金属波动剧烈、杠杆风险高,这类半成品指标绝不能直接挂实盘。开 MT5 按 F4 把代码贴进新指标,先编译确认 buffer 索引不越界(本例最大用到 16,需在 #property indicator_buffers 里至少声明 17 个),再决定往哪根线填价格。

MQL5 / C++
class=class="str">"cmt">//--- Plot buffer class="num">3. Two arrays for construction
   SetIndexBuffer(class="num">7,Label4Buffer,INDICATOR_DATA);          class=class="str">"cmt">// Data buffer
   SetIndexBuffer(class="num">8,Label4Colors,INDICATOR_COLOR_INDEX);   class=class="str">"cmt">// Buffer of class="type">color indexes
   
class=class="str">"cmt">//--- Plot buffer class="num">4. Three arrays for construction
   SetIndexBuffer(class="num">9,Label5Buffer1,INDICATOR_DATA);         class=class="str">"cmt">// Data buffer for line class="num">1
   SetIndexBuffer(class="num">10,Label5Buffer2,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">2
   SetIndexBuffer(class="num">11,Label5Colors,INDICATOR_COLOR_INDEX);  class=class="str">"cmt">// Buffer of class="type">color indexes
   
class=class="str">"cmt">//--- Plot buffer class="num">5. Five arrays for construction
   SetIndexBuffer(class="num">12,Label6Buffer1,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">1 Open
   SetIndexBuffer(class="num">13,Label6Buffer2,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">2 High
   SetIndexBuffer(class="num">14,Label6Buffer3,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">3 Low
   SetIndexBuffer(class="num">15,Label6Buffer4,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">4 Close
   SetIndexBuffer(class="num">16,Label6Colors,INDICATOR_COLOR_INDEX);  class=class="str">"cmt">// Buffer of class="type">color indexes
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],
                const class="type">class="kw">double &close[],
                const class="type">long &tick_volume[],
                const class="type">long &volume[],
                const class="type">int &spread[])
  {
class=class="str">"cmt">//--- class="kw">return value of prev_calculated for the next call
   class="kw">return(rates_total);
   }

「缓冲区与绘图类型的硬约束」

在 MT5 自定义指标里,#property 预处理器指令直接决定了图表上能画什么、怎么画。上面这段声明里 indicator_buffers 设成 17,意味着指标总共开了 17 个数据数组;而 indicator_plots 只有 6,说明其中仅 6 个数组组会被实际渲染成图形序列,其余 11 个只能闷头算中间量。 六种绘图类型对数组数的胃口完全不同。DRAW_LINE 吃掉 1 个数组,DRAW_FILLING 要 2 个(两条线夹出填充区),DRAW_CANDLES 直接吞掉 4 个 OHLC 数组,DRAW_COLOR_LINE 也要 2 个但第二个是颜色索引数组。开缓冲区时数错数组,编译能过、画图必崩。 颜色切换不是装饰。DRAW_FILLING 的 clrRed,clrDeepSkyBlue 会根据上下线谁高自动选色,DRAW_COLOR_LINE 最多挂 64 色,靠颜色索引数组逐根 bar 指认。外汇和贵金属波动快,这种视觉分层对盯盘分辨结构有帮助,但杠杆品种高风险,别把颜色信号当方向背书。 直接把这段声明贴进 MQ5 文件头,改 indicator_buffers 前先算清 6 个 plot 一共占了多少数组——上面例子 1+2+4+2 已用掉 9 个,剩下 8 个留给计算缓冲,账要对得上才能跑。

MQL5 / C++
class=class="str">"cmt">//|                                                                 [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2023, MetaQuotes Ltd."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property indicator_chart_window
class="macro">#class="kw">property indicator_buffers class="num">17                 class=class="str">"cmt">// class="num">17 arrays for indicator calculations in total
class="macro">#class="kw">property indicator_plots   class="num">6                  class=class="str">"cmt">// Out of class="num">17  arrays, class="num">6 graphic series are plotting buffers
class=class="str">"cmt">//--- plot Label1
class="macro">#class="kw">property indicator_label1  "Label1"
class="macro">#class="kw">property indicator_type1   DRAW_LINE           class=class="str">"cmt">// Plot buffer with index class="num">0 is a simple line, requires one array to plot
class="macro">#class="kw">property indicator_color1  clrRed              class=class="str">"cmt">// Color line: Red
class="macro">#class="kw">property indicator_style1  STYLE_SOLID
class="macro">#class="kw">property indicator_width1  class="num">1
class=class="str">"cmt">//--- plot Label2
class="macro">#class="kw">property indicator_label2  "Label2"
class="macro">#class="kw">property indicator_type2   DRAW_FILLING        class=class="str">"cmt">// Plot buffer with index class="num">1 is a colored area drawn between two indicator lines, requires two arrays to plot
class="macro">#class="kw">property indicator_color2  clrRed,clrDeepSkyBlue class=class="str">"cmt">// Area class="type">color: wither Red or DeepSkyBlue depending on which line is higher
class="macro">#class="kw">property indicator_style2  STYLE_SOLID
class="macro">#class="kw">property indicator_width2  class="num">1
class=class="str">"cmt">//--- plot Label3
class="macro">#class="kw">property indicator_label3  "Label3"
class="macro">#class="kw">property indicator_type3   DRAW_CANDLES        class=class="str">"cmt">// Plot buffer with index class="num">2, display as single-class="type">color candlesticks, requires class="num">4 arrays of OHLC data to plot
class="macro">#class="kw">property indicator_color3  clrDarkSalmon       class=class="str">"cmt">// Color: DarkSalmon
class="macro">#class="kw">property indicator_style3  STYLE_SOLID
class="macro">#class="kw">property indicator_width3  class="num">1
class=class="str">"cmt">//--- plot Label4
class="macro">#class="kw">property indicator_label4  "Label4"
class="macro">#class="kw">property indicator_type4   DRAW_COLOR_LINE     class=class="str">"cmt">// Plot buffer with index class="num">3, class="type">color line, requires two arrays to plot: data array + class="type">color index array
class="macro">#class="kw">property indicator_color4  clrRed,clrRoyalBlue class=class="str">"cmt">// Two colors: Red and RoyalBlue. Can have up to class="num">64 colors
class="macro">#class="kw">property indicator_style4  STYLE_SOLID
class="macro">#class="kw">property indicator_width4  class="num">1
class=class="str">"cmt">//--- plot Label5
class="macro">#class="kw">property indicator_label5  "Label5"

双线直方图与彩K线的缓冲阵列配置

在 MT5 自定义指标里,DRAW_COLOR_HISTOGRAM2 这种绘图类型看着像一根柱,实则要吃三块数组:两条数据线加一个颜色索引。上面那段声明把第 5 号图(index 4)设成了红、绿、原木色三色切换,最多可扩到 64 色,但线宽锁在 1。 第 6 号图(index 5)走的是 DRAW_COLOR_CANDLES,也就是彩色蜡烛。它比双线直方图更吃资源——四条 OHLC 数据数组外加一个颜色索引数组,合计五块缓冲。颜色用了红、蓝、灰三套,同样支持最多 64 色。 输入项里只有一个 InpHidePlotIndex,默认 0,用来控制隐藏某条绘图序列。缓冲声明部分能看到 Label5Buffer1、Label5Buffer2 配 Label5Colors,正好对应前面说的「2 数据数组 + 颜色数组」结构;Label6 那边则是 4 个数据数组加 1 个颜色数组。 开 MT5 新建一个指标把这段声明贴进 mq5 头部,编译后能在数据窗口数出 13 个缓冲队列(Label1 到 Label5Colors 全算上)。外汇和贵金属波动剧烈,这类多缓冲指标在低频品种上可能卡顿,实盘前先在模拟盘验证资源占用。

MQL5 / C++
class="macro">#class="kw">property indicator_type5   DRAW_COLOR_HISTOGRAM2   class=class="str">"cmt">// Plot buffer with index class="num">4, class="type">color histogram between two lines, requires three arrays: class="num">2 data arrays + class="type">color index array
class="macro">#class="kw">property indicator_color5   clrRed,clrForestGreen,clrBurlyWood class=class="str">"cmt">// Three colors: Red, ForestGreen and BurlyWood. Can have up to class="num">64 colors
class="macro">#class="kw">property indicator_style5   STYLE_SOLID
class="macro">#class="kw">property indicator_width5   class="num">1
class=class="str">"cmt">//--- plot Label6
class="macro">#class="kw">property indicator_label6   "Label6"                class=class="str">"cmt">// Plot buffer with index class="num">5, class="type">color histogram between two lines, requires class="num">5 arrays: class="num">4 OHLC data arrays + class="type">color index array
class="macro">#class="kw">property indicator_type6    DRAW_COLOR_CANDLES      class=class="str">"cmt">// Three colors: Red, Blue and Gray. Can have up to class="num">64 colors
class="macro">#class="kw">property indicator_color6   clrRed,clrBlue,clrGray
class="macro">#class="kw">property indicator_style6   STYLE_SOLID
class="macro">#class="kw">property indicator_width6   class="num">1
class=class="str">"cmt">//--- input variables
input class="type">uchar     InpHidePlotIndex  =  class="num">0;             class=class="str">"cmt">// Hide Plot Index
class=class="str">"cmt">//--- indicator buffers
class="type">class="kw">double          Label1Buffer[];                    class=class="str">"cmt">// Plot buffer with index class="num">0
class="type">class="kw">double          Label2Buffer1[];                   class=class="str">"cmt">// Plot buffer with index class="num">1, array class="num">1
class="type">class="kw">double          Label2Buffer2[];                   class=class="str">"cmt">// Plot buffer with index class="num">1, array class="num">2
class="type">class="kw">double          Label3Buffer1[];                   class=class="str">"cmt">// Plot buffer with index class="num">2, array class="num">1
class="type">class="kw">double          Label3Buffer2[];                   class=class="str">"cmt">// Plot buffer with index class="num">2, array class="num">2
class="type">class="kw">double          Label3Buffer3[];                   class=class="str">"cmt">// Plot buffer with index class="num">2, array class="num">3
class="type">class="kw">double          Label3Buffer4[];                   class=class="str">"cmt">// Plot buffer with index class="num">2, array class="num">4
class="type">class="kw">double          Label4Buffer[];                    class=class="str">"cmt">// Plot buffer with index class="num">3
class="type">class="kw">double          Label4Colors[];                    class=class="str">"cmt">// Color index array for plot buffer with index class="num">3
class="type">class="kw">double          Label5Buffer1[];                   class=class="str">"cmt">// Plot buffer with index class="num">4, array class="num">1
class="type">class="kw">double          Label5Buffer2[];                   class=class="str">"cmt">// Plot buffer with index class="num">4, array class="num">2
class="type">class="kw">double          Label5Colors[];                    class=class="str">"cmt">// Color index array for plot buffer with index class="num">4

◍ 多数组绘图缓冲的绑定套路

在 MT5 自定义指标里,一个 Plot 可以挂多根线,靠的是把多个数组依次映射到连续索引的缓冲区。上面这段声明了 Label6Buffer1~4 四个 double 数组加一个 Label6Colors 颜色索引数组,准备给索引 5 的 Plot 做四线同绘加变色。 OnInit 里能看到清晰规律:Plot 0 只占缓冲 0;Plot 1 用缓冲 1、2 两根线;Plot 2 用缓冲 3~6 拼出 OHLC 四线;Plot 3 是缓冲 7 数据加缓冲 8 颜色索引;Plot 4 是 9、10 数据加 11 颜色;Plot 5 从缓冲 12 起接着排。总共已用到 13 个缓冲槽(0~12),写指标时数错索引会直接编译报 Array out of range。 hide_index 那行做了个截断:InpHidePlotIndex 大于 5 就锁成 5,避免外部输入越界隐藏不存在的 Plot。外汇和贵金属波动大,这类边界处理能减少实盘加载指标时的闪退概率。 把缓冲分配抄进自己指标,开 MT5 用 MetaEditor 编译看缓冲总数是否和 Plot 数匹配,是验证多线绘制逻辑最快的一步。

MQL5 / C++
class="type">class="kw">double       Label6Buffer1[];                   class=class="str">"cmt">// Plot buffer with index class="num">5, array class="num">1
class="type">class="kw">double       Label6Buffer2[];                   class=class="str">"cmt">// Plot buffer with index class="num">5, array class="num">2
class="type">class="kw">double       Label6Buffer3[];                   class=class="str">"cmt">// Plot buffer with index class="num">5, array class="num">3
class="type">class="kw">double       Label6Buffer4[];                   class=class="str">"cmt">// Plot buffer with index class="num">5, array class="num">4
class="type">class="kw">double       Label6Colors[];                   class=class="str">"cmt">// Color index array for plot buffer with index class="num">5
class=class="str">"cmt">//--- global variables
class="type">int   hide_index=(InpHidePlotIndex>class="num">5 ? class="num">5 : InpHidePlotIndex);
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- indicator buffers mapping
class=class="str">"cmt">//--- Plot buffer class="num">0. One array to plot
   SetIndexBuffer(class="num">0,Label1Buffer,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer

class=class="str">"cmt">//--- Plot buffer class="num">1. Two arrays for construction
   SetIndexBuffer(class="num">1,Label2Buffer1,INDICATOR_DATA);       class=class="str">"cmt">// Line class="num">1 data buffer
   SetIndexBuffer(class="num">2,Label2Buffer2,INDICATOR_DATA);       class=class="str">"cmt">// Line class="num">2 data buffer

class=class="str">"cmt">//--- Plot buffer class="num">2. Four arrays for construction
   SetIndexBuffer(class="num">3,Label3Buffer1,INDICATOR_DATA);       class=class="str">"cmt">// Data buffer for line class="num">1 Open
   SetIndexBuffer(class="num">4,Label3Buffer2,INDICATOR_DATA);       class=class="str">"cmt">// Data buffer for line class="num">2 High
   SetIndexBuffer(class="num">5,Label3Buffer3,INDICATOR_DATA);       class=class="str">"cmt">// Data buffer for line class="num">3 Low
   SetIndexBuffer(class="num">6,Label3Buffer4,INDICATOR_DATA);       class=class="str">"cmt">// Data buffer for line class="num">4 Close

class=class="str">"cmt">//--- Plot buffer class="num">3. Two arrays for construction
   SetIndexBuffer(class="num">7,Label4Buffer,INDICATOR_DATA);         class=class="str">"cmt">// Data buffer
   SetIndexBuffer(class="num">8,Label4Colors,INDICATOR_COLOR_INDEX); class=class="str">"cmt">// Buffer of class="type">color indexes

class=class="str">"cmt">//--- Plot buffer class="num">4. Three arrays for construction
   SetIndexBuffer(class="num">9,Label5Buffer1,INDICATOR_DATA);       class=class="str">"cmt">// Data buffer for line class="num">1
   SetIndexBuffer(class="num">10,Label5Buffer2,INDICATOR_DATA);      class=class="str">"cmt">// Data buffer for line class="num">2
   SetIndexBuffer(class="num">11,Label5Colors,INDICATOR_COLOR_INDEX);class=class="str">"cmt">// Buffer of class="type">color indexes

class=class="str">"cmt">//--- Plot buffer class="num">5. Five arrays for construction
   SetIndexBuffer(class="num">12,Label6Buffer1,INDICATOR_DATA);      class=class="str">"cmt">// Data buffer for line class="num">1 Open

「把多线缓冲挂进数据窗口的细节」

这段初始化收尾把第 13~16 号缓冲区绑给了指标绘图:13/14/15 分别是第二根线的 High、Low、Close 数据缓冲,16 号存颜色索引,类型用 INDICATOR_DATA 和 INDICATOR_COLOR_INDEX 区分开。 PlotIndexSetInteger 从 0 到 5 都把 PLOT_SHOW_DATA 设为 true,意味着前 6 条画线会在数据窗口里显示数值;而 hide_index 那一条设成 false,是被刻意藏起来的辅助线,不占数据窗口行。 OnCalculate 这里直接 return rates_total,没做具体计算逻辑,属于占位骨架——你抄这段时若忘了补计算循环,指标会出白线但无数值。外汇与贵金属波动剧烈,这类多缓冲指标在实盘只作参考,信号失效概率不低。 开 MT5 新建指标把这段塞进 OnInit 末尾,把 hide_index 改成 6 看辅助线是否如预期隐藏,就能验证缓冲绑定对不对。

MQL5 / C++
   SetIndexBuffer(class="num">13,Label6Buffer2,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">2 High
   SetIndexBuffer(class="num">14,Label6Buffer3,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">3 Low
   SetIndexBuffer(class="num">15,Label6Buffer4,INDICATOR_DATA);        class=class="str">"cmt">// Data buffer for line class="num">4 Close
   SetIndexBuffer(class="num">16,Label6Colors,INDICATOR_COLOR_INDEX);class=class="str">"cmt">// Buffer of class="type">color indexes
class=class="str">"cmt">//--- Hode  the specified plot buffer in the data window
   PlotIndexSetInteger(class="num">0,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(class="num">1,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(class="num">2,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(class="num">3,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(class="num">4,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(class="num">5,PLOT_SHOW_DATA,true);
   PlotIndexSetInteger(hide_index,PLOT_SHOW_DATA,false);
   class="kw">return(INIT_SUCCEEDED);
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],
                const class="type">class="kw">double &close[],
                const class="type">long &tick_volume[],
                const class="type">long &volume[],
                const class="type">int &spread[])
  {
class=class="str">"cmt">//--- class="kw">return value of prev_calculated for the next call
   class="kw">return(rates_total);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+

用缓冲区索引取代数组记忆负担

把多数组指标缓冲区的访问方式改成「绘图缓冲区索引 + 所需数组索引」二元定位后,外部调用方不再需要背下每个数组挂在第几个指标缓冲区。比如绘图缓冲区 0 要取第一份数据数组,传 (0,0);取第二份传 (0,1);颜色索引数组则只传绘图缓冲区索引 0,由类内部方法处理。 库文件 \MQL5\Include\IndMSTF\IndMSTF.mqh 里把缓冲区结构重做了:五个数组的初始化和Resize统一进私有段,绘制样式在创建时写进结构,并记下源指标数组索引。之前 Calculate() 里手写复制,现在改成调用一个复制全部数组的方法,复制失败会直接返回错误。 颜色缓冲区的复制与单色类似,只是多传一个绘图侧颜色索引数组,同时拷数据数组和颜色数组。由于颜色缓冲区永远排在数据缓冲区之后,计算侧颜色索引 = 数据缓冲区索引 + 1,这个关系写进类结构后,从计算部分取色变得可推算。 指标集合类也同步扩了方法:添加对象时立即设数字、数据、颜色缓冲区的初始空值,还可顺手设水平线数量和数值。以前只返回句柄或 INVALID_HANDLE,现在创建成功还会在图表上设小数位和水平。外汇与贵金属行情跳空频繁,这类多周期多品种库在实盘使用前,建议先在 MT5 策略测试器用历史数据验证缓冲区复制是否漏帧。

MQL5 / C++
class=class="str">"cmt">//--- class="kw">struct
class="kw">struct SBuffer                                          class=class="str">"cmt">// Structure of the indicator buffer
  {
class="kw">private:
   class="type">class="kw">double               init_value;                     class=class="str">"cmt">// Initializing value
   class="type">uchar                init_color_idx;                 class=class="str">"cmt">// Initializing value of the class="type">color index
   class="type">int                  shift;                          class=class="str">"cmt">// Horizontal shift of the buffer
   class="type">uint                 source;                         class=class="str">"cmt">// Buffer number of the source indicator
   class="type">bool                 colored;                        class=class="str">"cmt">// Flag of the class="type">color buffer
   ENUM_DRAW_TYPE       draw_type;                      class=class="str">"cmt">// Buffer drawing style
class=class="str">"cmt">//--- Changes the size of all arrays
   class="type">bool                 ResizeArrays(const class="type">int new_size)
     {
      class="type">bool res=true;
      class="kw">switch(draw_type)
        {
         class=class="str">"cmt">//--- One buffer
         case DRAW_LINE             :
让小布替你跑这套跨周期检查
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到多周期缓冲同步状态,把重复劳动交给小布,你专注决策。

常见问题

一条绘制的彩色指标线最多可设置 64 种不同颜色,由颜色索引数组与数据数组配合实现。
可以,小布盯盘的 AIGC 模块已内置多周期缓冲诊断,打开品种页能直接看到同步状态和可能的丢失环节。
通常是因为只复制了数据数组而没复制颜色索引数组,绘制部分缺失色彩映射,倾向回退到默认单色。
扩展类封装了跨周期缓冲区和颜色索引的通用读写,避免每个指标重写一套同步逻辑,降低出错概率。