DoEasy 函数库中的时间序列(第五十一部分):复合多周期、多品种标准指标·进阶篇
📊

DoEasy 函数库中的时间序列(第五十一部分):复合多周期、多品种标准指标·进阶篇

(2/3)· 单指标多缓冲区的混乱刚理清,跨品种跨周期复合指标的对象模型才是实盘脚本的真正的门槛

含代码示例 第 2/3 篇

不少交易者把多周期指标当成简单叠加,结果在 EA 里反复重算缓冲区,既拖慢回测又漏掉跨品种信号。其实标准指标对象一旦支持多品种多周期,关键不在画几条线,而在给每条附加曲线编好号、归好类。

◍ 缓冲区整数属性的枚举与排序偏移

在 MQL5 指标架构里,缓冲区(buffer)不只是存价格序列的容器,它有一组整数属性用来描述绘制关系与归属。下面这段枚举列出了从下一个绘制缓冲区索引到颜色缓冲区索引的多个属性,其中 BUFFER_PROP_IND_LINE_ADDITIONAL_NUM 表示指标附加线的编号,是容易被忽略的一项。 宏定义给出了两个关键计数:BUFFER_PROP_INTEGER_TOTAL 为 25,代表缓冲区整数属性总数;BUFFER_PROP_INTEGER_SKIP 为 2,代表排序时不参与的整数属性数量。用总数减跳过数,就能算出双精度属性区的起始偏移 FIRST_BUFFER_DBL_PROP = 23。 基于上述偏移,代码进一步定义了 ENUM_SORT_BUFFER_MODE 枚举,支持按绘制序号、状态、类型、周期、激活标志等维度给缓冲区排序。实际写多缓冲指标时,可以照这个枚举去遍历 PlotIndex 顺序,避免手动硬编码下标。 开 MT5 新建一个空指标,把这段枚举和宏贴进源码,编译后通过 BufferIntegerProperty 读取 SORT_BY_BUFFER_TYPE 对应值,就能验证你的缓冲区分类是否符合预期。外汇与贵金属市场波动剧烈,此类底层结构改动仅用于工具验证,实盘前请充分回测。

MQL5 / C++
  BUFFER_PROP_INDEX_NEXT_PLOT,                                                                     class=class="str">"cmt">// Index of the next plotted buffer
  BUFFER_PROP_ID,                                                                                   class=class="str">"cmt">// ID of multiple buffers of the same indicator
  BUFFER_PROP_IND_LINE_MODE,                                                                       class=class="str">"cmt">// Indicator line
  BUFFER_PROP_IND_HANDLE,                                                                          class=class="str">"cmt">// Indicator handle that uses the buffer
  BUFFER_PROP_IND_TYPE,                                                                            class=class="str">"cmt">// Indicator type that uses the buffer
  BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,                                                             class=class="str">"cmt">// Number of indicator additional line
  BUFFER_PROP_NUM_DATAS,                                                                           class=class="str">"cmt">// Number of data buffers
  BUFFER_PROP_INDEX_COLOR,                                                                         class=class="str">"cmt">// Color buffer index
  };
class="macro">#define BUFFER_PROP_INTEGER_TOTAL(class="num">25)                                                              class=class="str">"cmt">// Total number of buffer integer properties
class="macro">#define BUFFER_PROP_INTEGER_SKIP(class="num">2)                                                               class=class="str">"cmt">// Number of buffer properties not used in sorting
class="macro">#define FIRST_BUFFER_DBL_PROP(BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP)
class="macro">#define FIRST_BUFFER_STR_PROP(BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP+BUFFER_PROP_DOUBLE_TOTAL-BUFFER_PROP_DOUBLE_SKIP)
enum ENUM_SORT_BUFFER_MODE
  {
class=class="str">"cmt">//--- Sort by integer properties
  SORT_BY_BUFFER_INDEX_PLOT = class="num">0,                                                                   class=class="str">"cmt">// Sort by the plotted buffer serial number
  SORT_BY_BUFFER_STATUS,                                                                           class=class="str">"cmt">// Sort by buffer drawing style(status) (from the ENUM_BUFFER_STATUS enumeration)
  SORT_BY_BUFFER_TYPE,                                                                             class=class="str">"cmt">// Sort by buffer type(from the ENUM_BUFFER_TYPE enumeration)
  SORT_BY_BUFFER_TIMEFRAME,                                                                        class=class="str">"cmt">// Sort by the buffer data period(timeframe)
  SORT_BY_BUFFER_ACTIVE,                                                                           class=class="str">"cmt">// Sort by the buffer usage flag
  };

「指标缓冲区排序枚举的细粒度切分」

在 MT5 自定义指标里,想对缓冲区做排序或批量检索,底层靠的是一组 SORT_BY_BUFFER_* 枚举。它们把缓冲区的图形属性、数据属性和宿主指标属性拆成了可单独命中的字段,而不是笼统地按句柄排。 比如 SORT_BY_BUFFER_DRAW_TYPE 对应 ENUM_DRAW_TYPE 里的绘制类型,SORT_BY_BUFFER_ARROW_CODE 专抓 DRAW_ARROW 风格的箭头代码,SORT_BY_BUFFER_LINE_WIDTH 只认线宽。若你的指标同时画了三种线宽,用这个枚举就能把宽线缓冲区先筛出来。 枚举里还区分了「真实属性」和「字符串属性」两段。SORT_BY_BUFFER_EMPTY_VALUE 从 FIRST_BUFFER_DBL_PROP 起算,管的是不绘制的空值;SORT_BY_BUFFER_SYMBOL 从 FIRST_BUFFER_STR_PROP 起算,按缓冲区绑定的交易品种符号排序。 实盘外接小布类 AIGC 工具扫描多指标时,直接按 SORT_BY_BUFFER_IND_HANDLE 或 SORT_BY_BUFFER_ID 拉列表,能避开把不同品种缓冲区混在一起的高风险误读。外汇与贵金属波动剧烈,这类底层枚举只解决「认得准」,不解决「看得对」。

MQL5 / C++
  SORT_BY_BUFFER_DRAW_TYPE,                                                                     class=class="str">"cmt">// Sort by graphical construction type(from the ENUM_DRAW_TYPE enumeration)
  SORT_BY_BUFFER_ARROW_CODE,                                                                     class=class="str">"cmt">// Sort by the arrow code for DRAW_ARROW style
  SORT_BY_BUFFER_ARROW_SHIFT,                                                                    class=class="str">"cmt">// Sort by the vertical shift of the arrows for DRAW_ARROW style
  SORT_BY_BUFFER_LINE_STYLE,                                                                     class=class="str">"cmt">// Sort by the line style
  SORT_BY_BUFFER_LINE_WIDTH,                                                                     class=class="str">"cmt">// Sort by the line width
  SORT_BY_BUFFER_DRAW_BEGIN,                                                                     class=class="str">"cmt">// Sort by the number of initial bars that are not drawn and values in DataWindow
  SORT_BY_BUFFER_SHOW_DATA,                                                                      class=class="str">"cmt">// Sort by the flag of displaying construction values in DataWindow
  SORT_BY_BUFFER_SHIFT,                                                                          class=class="str">"cmt">// Sort by the indicator graphical construction shift by time axis in bars
  SORT_BY_BUFFER_COLOR_INDEXES,                                                                  class=class="str">"cmt">// Sort by a number of attempts
  SORT_BY_BUFFER_COLOR,                                                                          class=class="str">"cmt">// Sort by the drawing class="type">class="kw">color
  SORT_BY_BUFFER_INDEX_BASE,                                                                     class=class="str">"cmt">// Sort by the basic data buffer index
  SORT_BY_BUFFER_INDEX_NEXT_BASE,                                                                class=class="str">"cmt">// Sort by the index of the array to be assigned as the next indicator buffer
  SORT_BY_BUFFER_INDEX_NEXT_PLOT,                                                                class=class="str">"cmt">// Sort by the index of the next drawn buffer
  SORT_BY_BUFFER_ID,                                                                             class=class="str">"cmt">// Sort by ID of multiple buffers of the same indicator
  SORT_BY_BUFFER_IND_LINE_MODE,                                                                  class=class="str">"cmt">// Sort by indicator line
  SORT_BY_BUFFER_IND_HANDLE,                                                                     class=class="str">"cmt">// Sort by indicator handle that uses the buffer
  SORT_BY_BUFFER_IND_TYPE,                                                                       class=class="str">"cmt">// Sort by indicator type that uses the buffer
  SORT_BY_BUFFER_IND_LINE_ADDITIONAL_NUM,                                                        class=class="str">"cmt">// Sort by number of additional indicator line
class=class="str">"cmt">//--- Sort by real properties
  SORT_BY_BUFFER_EMPTY_VALUE = FIRST_BUFFER_DBL_PROP,                                            class=class="str">"cmt">// Sort by the empty value for plotting where nothing will be drawn
class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties
  SORT_BY_BUFFER_SYMBOL = FIRST_BUFFER_STR_PROP,                                                 class=class="str">"cmt">// Sort by the buffer symbol

指标缓冲区排序与属性设置的接口细节

在 MQL5 的缓冲区封装类里,排序枚举决定了 DataWindow 中系列名称的呈现顺序。SORT_BY_BUFFER_LABEL 按数据窗口显示名排,SORT_BY_BUFFER_IND_NAME 按指标全名排,SORT_BY_BUFFER_IND_NAME_SHORT 则按短名排,三者差异直接影响多缓冲指标在客户端的阅读效率。 Print() 方法支持 full_prop 参数:传 true 会 dump 全部缓冲区属性到日志,false 只输出当前类支持的属性,调试自定义指标时建议先用 false 快速看结构。 SetSymbol、SetTimeframe、SetActive 这类 setter 直接走 SetProperty 写入 BUFFER_PROP_* 字段,而 SetArrowCode、SetArrowShift 在基类里是空实现,返回即结束——说明箭头类参数要留给具体绘图子类去重写。 开 MT5 自建一个多缓冲指标,把 SORT_BY_BUFFER_IND_NAME_SHORT 接进去,对比数据窗口排列变化,就能验证短名排序是否真的省眼。外汇与贵金属指标调试涉及实盘加载,存在滑点与重载失败的高风险,验证请在模拟环境先做。

MQL5 / C++
  SORT_BY_BUFFER_LABEL,                                                                       class=class="str">"cmt">// Sort by the name of the graphical indicator series displayed in DataWindow
  SORT_BY_BUFFER_IND_NAME,                                                                     class=class="str">"cmt">// Sort by indicator name that uses the buffer
  SORT_BY_BUFFER_IND_NAME_SHORT,                                                               class=class="str">"cmt">// Sort by a class="type">class="kw">short name of indicator that uses the buffer
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">public:  
class=class="str">"cmt">//--- Display the description of the buffer properties in the journal(full_prop=true - all properties, class="kw">false - supported ones only)
   class="type">void                Print(class="kw">const class="type">bool full_prop=class="kw">false);
class=class="str">"cmt">//--- Display a class="type">class="kw">short buffer description in the journal(implementation in the descendants)
   class="kw">virtual class="type">void        PrintShort(class="type">void) {;}
  
class=class="str">"cmt">//--- Set(class="num">1) the arrow code, (class="num">2) vertical shift of arrows, (class="num">3) symbol, (class="num">4) timeframe, (class="num">5) buffer activity flag
class=class="str">"cmt">//--- (class="num">6) drawing type, (class="num">7) number of initial bars without drawing, (class="num">8) flag of displaying construction values in DataWindow,
class=class="str">"cmt">//--- (class="num">9) shift of the indicator graphical construction along the time axis, (class="num">10) line style, (class="num">11) line width,
class=class="str">"cmt">//--- (class="num">12) total number of colors, (class="num">13) one drawing class="type">class="kw">color, (class="num">14) class="type">class="kw">color of drawing in the specified class="type">class="kw">color index,
class=class="str">"cmt">//--- (class="num">15) drawing colors from the class="type">class="kw">color array, (class="num">16) empty value, (class="num">17) name of the graphical series displayed in DataWindow
   class="kw">virtual class="type">void        SetArrowCode(class="kw">const class="type">uchar code)                                            { class="kw">return;                                                                                      }
   class="kw">virtual class="type">void        SetArrowShift(class="kw">const class="type">int shift)                                            { class="kw">return;                                                                                      }
   class="type">void                SetSymbol(class="kw">const class="type">class="kw">string symbol)                                            { this.SetProperty(BUFFER_PROP_SYMBOL,symbol);                                                 }
   class="type">void                SetTimeframe(class="kw">const ENUM_TIMEFRAMES timeframe)                             { this.SetProperty(BUFFER_PROP_TIMEFRAME,timeframe);                                           }
   class="type">void                SetActive(class="kw">const class="type">bool flag)                                                { this.SetProperty(BUFFER_PROP_ACTIVE,flag);                                                   }
   class="type">void                SetDrawType(class="kw">const ENUM_DRAW_TYPE draw_type);

◍ 指标缓冲区外观与绑定的 setter 清单

在 MT5 自定义指标里,缓冲区对象靠一组 Set 方法控制绘制与数据来源。下面这段声明覆盖了从线宽、偏移、样式到颜色数组的全部视觉参数,也包含绑定外部指标句柄的接口。 [CODE] void SetDrawBegin(const int value); void SetShowData(const bool flag); void SetShift(const int shift); void SetStyle(const ENUM_LINE_STYLE style); void SetWidth(const int width); void SetColorNumbers(const int number); void SetColor(const color colour); void SetColor(const color colour,const uchar index); void SetColors(const color &array_colors[]); void SetEmptyValue(const double value); virtual void SetLabel(const string label); void SetID(const int id) { this.SetProperty(BUFFER_PROP_ID,id); } void SetIndicatorHandle(const int handle) { this.SetProperty(BUFFER_PROP_IND_HANDLE,handle); } void SetIndicatorType(const ENUM_INDICATOR type) { this.SetProperty(BUFFER_PROP_IND_TYPE,type); } void SetIndicatorName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME,name); } void SetIndicatorShortName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME_SHORT,name); } void SetLineMode(const ENUM_INDICATOR_LINE_MODE mode){ this.SetProperty(BUFFER_PROP_IND_LINE_MODE,mode); } void SetIndicatorLineAdditionalNumber(const int number){this.SetProperty(BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,number); } [/CODE] 逐行拆解:SetDrawBegin 决定从哪根 K 线开始画,常用于跳过指标前导空值区;SetShift 把整条线向右移 N 根,做信号滞后对比时很实用。SetStyle 吃 ENUM_LINE_STYLE,虚线、点线随你换;SetWidth 控制像素粗细,超过 5 在 4K 屏上才可能明显。 SetColor 有两个重载,单色直接传 colour,多缓冲用 index 定位;SetColors 则一口气接 color 数组,做渐变或阈值变色就靠它。SetEmptyValue 设无效值,EMPTY_VALUE 是默认坑点,不显式改可能在图表上画出怪异横线。 后半段全是属性写入:SetIndicatorHandle 把缓冲区绑到别的指标句柄,做跨指标引用不必重算;SetLineMode 区分画线是普通模式还是直方图/箭头模式。最后那个 SetIndicatorLineAdditionalNumber 是附加线编号,多线指标里用来区分第几根副线。外汇与贵金属波动剧烈,这类绑定若句柄失效,图表可能静默不刷新,实盘前务必在策略测试器跑一遍。

MQL5 / C++
class="type">void SetDrawBegin(class="kw">const class="type">int value);
class="type">void SetShowData(class="kw">const class="type">bool flag);
class="type">void SetShift(class="kw">const class="type">int shift);
class="type">void SetStyle(class="kw">const ENUM_LINE_STYLE style);
class="type">void SetWidth(class="kw">const class="type">int width);
class="type">void SetColorNumbers(class="kw">const class="type">int number);
class="type">void SetColor(class="kw">const class="type">class="kw">color colour);
class="type">void SetColor(class="kw">const class="type">class="kw">color colour,class="kw">const class="type">uchar index);
class="type">void SetColors(class="kw">const class="type">class="kw">color &array_colors[]);
class="type">void SetEmptyValue(class="kw">const class="type">class="kw">double value);
class="kw">virtual class="type">void SetLabel(class="kw">const class="type">class="kw">string label);
class="type">void SetID(class="kw">const class="type">int id) { this.SetProperty(BUFFER_PROP_ID,id); }
class="type">void SetIndicatorHandle(class="kw">const class="type">int handle) { this.SetProperty(BUFFER_PROP_IND_HANDLE,handle); }
class="type">void SetIndicatorType(class="kw">const ENUM_INDICATOR type) { this.SetProperty(BUFFER_PROP_IND_TYPE,type); }
class="type">void SetIndicatorName(class="kw">const class="type">class="kw">string name) { this.SetProperty(BUFFER_PROP_IND_NAME,name); }
class="type">void SetIndicatorShortName(class="kw">const class="type">class="kw">string name) { this.SetProperty(BUFFER_PROP_IND_NAME_SHORT,name); }
class="type">void SetLineMode(class="kw">const ENUM_INDICATOR_LINE_MODE mode){ this.SetProperty(BUFFER_PROP_IND_LINE_MODE,mode); }
class="type">void SetIndicatorLineAdditionalNumber(class="kw">const class="type">int number){this.SetProperty(BUFFER_PROP_IND_LINE_ADDITIONAL_NUM,number); }

「缓冲区对象暴露的 30 个内部属性」

在 MT5 自定义指标里,每一个绘图缓冲都被封装成一个对象,通过 GetProperty 拉取运行时元数据。上面这组方法只是冰山一角:注释里列了从序列号、绑定数组下标、颜色索引,到时间周期、状态、类型、箭头代码、线宽、空值设定等共 30 个属性槽位。 实际写类的时候,通常只把高频用的几个包成内联方法。例如 IndexPlot 取的是 BUFFER_PROP_INDEX_PLOT,返回该缓冲在第几个绘图序列上;IndexBase 对应 BUFFER_PROP_INDEX_BASE,指向绑定的数据数组下标;Timeframe 直接转型 ENUM_TIMEFRAMES,能知道这个缓冲挂在哪根周期线上。 开 MT5 新建一个空指标,故意把两个缓冲的 IndexPlot 设成相同值,编译后拖到 EURUSD 图表,数据窗口里会看到两条线挤在同一绘图号下——这时 Status 属性往往返回 BUFFER_STATUS_WRONG 一类的异常码,说明绑定冲突。外汇与贵金属杠杆高,这类底层错绑不会爆仓但会让信号完全失真,调试时值得逐个打印属性确认。

MQL5 / C++
class="type">int IndexPlot(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_PLOT); }
class="type">int IndexBase(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_BASE); }
class="type">int IndexColor(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_COLOR); }
class="type">int IndexNextBaseBuffer(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_BASE); }
class="type">int IndexNextPlotBuffer(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_PLOT); }
ENUM_TIMEFRAMES Timeframe(class="type">void) class="kw">const { class="kw">return (ENUM_TIMEFRAMES)this.GetProperty(BUFFER_PROP_TIMEFRAME); }
ENUM_BUFFER_STATUS Status(class="type">void) class="kw">const { class="kw">return (ENUM_BUFFER_STATUS)this.GetProperty(BUFFER_PROP_STATUS); }
ENUM_BUFFER_TYPE TypeBuffer(class="type">void) class="kw">const { class="kw">return (ENUM_BUFFER_TYPE)this.GetProperty(BUFFER_PROP_TYPE); }

缓冲区属性的取值接口怎么写

在自定义指标里,每一个绘图缓冲区(buffer)都有一套只读属性接口,靠 GetProperty 统一拉取。下面这组方法覆盖了激活状态、箭头样式、偏移与线型等常用字段,返回类型与缓冲区属性枚举严格对应。 对外汇与贵金属交易者来说,这类接口的价值在于:你能在 EA 里实时读取某缓冲区的 DrawBegin 或 Shift,判断指标从哪根 K 线开始画、有没有整体平移,从而避开“信号看起来滞后”的误判。MT5 中缓冲区属性以整型或枚举存于底层,强转返回值是标准做法。 代码逐行拆解:IsActive 读 BUFFER_PROP_ACTIVE,返回布尔表示缓冲区是否参与绘制;ArrowCode 读 BUFFER_PROP_ARROW_CODE,得到 uchar 箭头字符码;ArrowShift 与 Shift 分别取箭头像素偏移和整体水平位移,都是 int。 DrawBegin 返回 int,限定指标最少已成型 K 线数才画线;DrawType 与 LineStyle 分别给 ENUM_DRAW_TYPE 和 ENUM_LINE_STYLE,决定连线方式与点线虚线;LineWidth 取线宽像素。IsShowData 控制数据窗是否显示,ColorsTotal 回传可用颜色索引数(即 BUFFER_PROP_COLOR_INDEXES),通常决定多色缓冲区的配色上限。

MQL5 / C++
  class="type">bool                IsActive(class="type">void)                class="kw">const { class="kw">return (class="type">bool)this.GetProperty(BUFFER_PROP_ACTIVE);                }
  class="type">uchar               ArrowCode(class="type">void)              class="kw">const { class="kw">return (class="type">uchar)this.GetProperty(BUFFER_PROP_ARROW_CODE);           }
  class="type">int                 ArrowShift(class="type">void)             class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_ARROW_SHIFT);            }
  class="type">int                 DrawBegin(class="type">void)              class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_DRAW_BEGIN);             }
  ENUM_DRAW_TYPE      DrawType(class="type">void)               class="kw">const { class="kw">return (ENUM_DRAW_TYPE)this.GetProperty(BUFFER_PROP_DRAW_TYPE);    }
  class="type">bool                IsShowData(class="type">void)             class="kw">const { class="kw">return (class="type">bool)this.GetProperty(BUFFER_PROP_SHOW_DATA);             }
  class="type">int                 Shift(class="type">void)                  class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_SHIFT);                  }
  ENUM_LINE_STYLE     LineStyle(class="type">void)              class="kw">const { class="kw">return (ENUM_LINE_STYLE)this.GetProperty(BUFFER_PROP_LINE_STYLE);  }
  class="type">int                 LineWidth(class="type">void)              class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_LINE_WIDTH);             }
  class="type">int                 ColorsTotal(class="type">void)            class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_COLOR_INDEXES);          }
把跨周期诊断交给小布盯盘
这些多品种多周期指标的缓冲区状态,小布盯盘的 AIGC 已内置,打开对应品种页即可看到实时曲线归属与冲突提示,你只管判断信号强弱。

常见问题

需要为两条 Senkou 线各建一个辅助缓冲区,并复制对应曲线的样式与颜色,用曲线编号绑定到主指标对象,避免被归到错误描述。
可以,小布盯盘品种页已内置多品种多周期标准指标的可视化,不需要自己写 MQL5 就能对照检查缓冲归属。
这是合并处理常数的副作用,并非逻辑错误,但会在日志里造成阅读混乱,需按本篇改消息索引与枚举顺序来规避。
基于上篇的 Alligator 对象直接引用其缓冲,再建 Gator 的差值缓冲,按附加曲线编号挂到同一指标对象下即可。