DoEasy 函数库中的时间序列(第四十九部分):多周期、多品种、多缓冲区标准指标(基础篇)
📘

DoEasy 函数库中的时间序列(第四十九部分):多周期、多品种、多缓冲区标准指标(基础篇)

第 1/3 篇

多周期多品种指标怎么塞进函数库

DoEasy 函数库这一版把标准指标接进了统一时间序列框架,核心变化是允许同一指标在多个品种、多个周期、多个缓冲区上同时取数,而不必为每个图表开独立句柄。 原来写跨周期指标要反复调用 iCustom 或 iMACD 并手动维护句柄数组,现在库内封装后,调用方只关心「我要哪个品种、哪根周期线、第几个缓冲区」这三个参数。 公开示例数据:该文发布于 2021 年 1 月 4 日,截至统计时帖文浏览量 2278、评论 1,说明这类底层封装在早期社区关注度偏低,但它是后续多时间框架 EA 的基础件。 外汇与贵金属杠杆交易高风险,多周期拉取若不加品种白名单,可能在流动性差的品种上返回空序列,实盘前务必在 MT5 策略测试器用 EURUSD 与 XAUUSD 各跑一遍空图验证。

◍ 给多缓冲区指标打上三条隶属标记

前文已经能拉取任意品种、周期的数据画到当前图表,但只解决了单缓冲区指标。多缓冲区指标(如随机振荡、布林带)一条指标里有多条线,函数库若不加区分,引用时就会撞车。 核心改法是给每个绘制/计算缓冲对象补三个属性:指标类型(Indicator type)标明它归哪类标准指标;指标标识符(Indicator identifier)在同类型多个实例里分身用,比如三个 MA 分别给 ID 1、2、3,类型都是 IND_MA;指标线(Indicator line)再指定具体归该指标的哪条曲线,顶线、底线还是中线。 此外加一个短名称(Short indicator name)参数,让函数库里的指标名和 MT5 子窗口显示名对齐。随机振荡在标准终端里显示的就是「Stochastic」,多周期版本则会带品种周期后缀,靠这个短名才能正确匹配。 实操上,开 MT5 用 iStochastic 挂两个不同周期实例,若不在缓冲对象里写清 identifier 和 line,你大概率只能取到第一条 %K 线,其余曲线在自定义指标里直接丢失。

「给缓冲区对象补上指标线身份标签」

重构 DoEasy 函数库时,先把旧名 Datas.mqh 改成 Data.mqh,顺手删掉旧文件,避免包含冲突。真正动手的是给缓冲区对象加两个新属性:指标线用途描述(整数型)和指标线简称(字符串型),整数属性总数从 23 扩到 24,字符串属性加到 4 个。 新增的 ENUM_INDICATOR_LINE_MODE 枚举用来标记缓冲对象属于哪条标准指标线。比如 ADX 有主线和 ±DI 三条线,给每个计算/绘制缓冲绑上对应常量后,按名称访问就能精准拿到目标对象,不用再猜索引。 代码层要在 Buffer.mqh 公开段写 setter/getter,构造函数给新属性设默认。衍生类(BufferLine、BufferCalculate 等共 11 个文件)都得覆写两个虚方法返回支持属性标志,否则集合类的搜索、排序用不了。下面这段消息索引常量里,高亮行就是新加的线型描述项: 布林带是个坑:数据窗口里曲线顺序是上、下、中,但缓冲区索引是上(1)、中(0)、下(2),所以在准备计算数据的方法里用 idx0/idx1 做了索引交换。其余指标曲线连续 0、1、2 不用管。 主窗口单缓冲指标(MA、SAR 等)和子窗口逻辑一致,只是线型强制设 Main;多缓冲的 ADX、MACD、Bands 等每条线建一对计算+绘制缓冲,隶属关系从新枚举取值。外汇与贵金属波动剧烈,这类底层改动能让 EA 在 MT5 里更稳地抓线,但高频切换品种仍属高风险操作,建议先在策略测试器跑一遍。

MQL5 / C++
class=class="str">"cmt">//--- CBuffer
  MSG_LIB_TEXT_BUFFER_TEXT_INDEX_BASE,           class=class="str">"cmt">// Base data buffer index
  MSG_LIB_TEXT_BUFFER_TEXT_INDEX_PLOT,           class=class="str">"cmt">// Plotted buffer serial number
  MSG_LIB_TEXT_BUFFER_TEXT_INDEX_COLOR,          class=class="str">"cmt">// Color buffer index
  MSG_LIB_TEXT_BUFFER_TEXT_NUM_DATAS,            class=class="str">"cmt">// Number of data buffers
  MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_BASE,      class=class="str">"cmt">// Index of the array to be assigned as the next indicator buffer
  MSG_LIB_TEXT_BUFFER_TEXT_INDEX_NEXT_PLOT,      class=class="str">"cmt">// Index of the next drawn buffer
  MSG_LIB_TEXT_BUFFER_TEXT_ID,                   class=class="str">"cmt">// Indicator buffer ID
  MSG_LIB_TEXT_BUFFER_TEXT_IND_LINE_MODE,        class=class="str">"cmt">// Indicator line
  MSG_LIB_TEXT_BUFFER_TEXT_IND_HANDLE,           class=class="str">"cmt">// Handle of an indicator using a buffer
  MSG_LIB_TEXT_BUFFER_TEXT_IND_TYPE,             class=class="str">"cmt">// Type of an indicator using a buffer

正文

&nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_TIMEFRAME,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// Buffer (timeframe) data period</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_STATUS,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">// Buffer status</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_TYPE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">// Buffer type</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_ACTIVE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">// Active</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_ARROW_CODE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">// Arrow code</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SHIFT,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">// The vertical shift of the arrows</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_DRAW_BEGIN,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">// The number of initial bars that are not drawn and values in DataWindow</span> &nbsp;&nbsp; MSG_LIB_TEXT_BUFFER_TEXT_DRAW_TYPE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&

◍ 指标缓冲区与多文件引用的底层枚举

写自定义指标时,缓冲区属性有一长串可配置项:缓冲状态、类型、是否激活、箭头代码、垂直偏移、初始无绘制 bar 数、图形构造类型、DataWindow 显示开关、时间轴偏移、线型线宽、箭头尺寸、颜色数、空值定义、所属 symbol 与调用方指标名等。这些字段直接决定 MT5 里指标在副图和数据窗口的行为,调错一个就可能让前 N 根 bar 不画线。 工程化指标通常不会把所有逻辑塞进一个 mq5。上面片段用 #include 拉进了 DataSND.mqh、DataIMG.mqh、Data.mqh,并在 __MQL4__ 宏下额外引入 ToMQL4.mqh,说明同一套代码可能跨 MT4/MT5 编译。你开 MT5 写指标时,也可以把缓冲区描述和数据结构拆到 .mqh 里复用。 片段里的 ENUM_INDICATOR_LINE_MODE 枚举把常见线角色固化下来:主线、信号线、上下轨、中轨,以及鳄鱼指标的颚部(Jaws)、齿部(Teeth)等。共出现 7 个枚举值,对应至少 7 种画线槽位。后续用这个枚举传参,比硬编码数字可读性高,也方便小布类工具自动识别线型。 别把缓冲区数量写死 #property indicator_buffers 若和实际申请的 buffer 数对不上,终端会报“Number of indicator buffers incorrect”或直接触达最大缓冲上限。动手前先数清楚你枚举里用了几条线,再填 property,能省掉一半编译期诡异报错。

MQL5 / C++
class="macro">#include "DataSND.mqh"
class="macro">#include "DataIMG.mqh"
class="macro">#include "Data.mqh"
class="macro">#ifdef __MQL4__
class="macro">#include "ToMQL4.mqh"
class="macro">#endif
enum ENUM_INDICATOR_LINE_MODE
  {
   INDICATOR_LINE_MODE_MAIN,        class=class="str">"cmt">// Main line
   INDICATOR_LINE_MODE_SIGNAL,      class=class="str">"cmt">// Signal line
   INDICATOR_LINE_MODE_UPPER,       class=class="str">"cmt">// Upper line
   INDICATOR_LINE_MODE_MIDDLE,      class=class="str">"cmt">// Middle line
   INDICATOR_LINE_MODE_LOWER,       class=class="str">"cmt">// Lower line
   INDICATOR_LINE_MODE_JAWS,        class=class="str">"cmt">// Jaws line
   INDICATOR_LINE_MODE_TEETH,       class=class="str">"cmt">// Teeth line
  };

「缓冲区整型属性枚举怎么排」

在自定义指标里,缓冲区(buffer)不是画出来就完事,MT5 用 ENUM_BUFFER_PROP_INTEGER 把每个缓冲区的可控维度列成一张整型属性表,方便在运行时用 PlotIndexSetInteger 一类函数逐个改写。 下面这段枚举直接给出 14 个成员,从 BUFFER_PROP_INDEX_PLOT = 0 开始编号,到 BUFFER_PROP_COLOR_INDEXES 收尾,覆盖了绘图序号、状态、类型、周期、开关、画线方式、箭头代码与偏移、线型线宽、起绘位置、数据窗显示、时间轴偏移和颜色数。 实际调参时最常被动的有三个:BUFFER_PROP_DRAW_BEGIN 决定前多少根 bar 不画(常见设 0~N 避免历史不足报错),BUFFER_PROP_SHIFT 让线整体左右错开(用于鳄鱼唇线相对于价格的视觉领先),BUFFER_PROP_LINE_WIDTH 控制像素粗细。外汇与贵金属杠杆高、跳空频繁,改这些属性后务必在 MT5 用 EURUSD 或 XAUUSD 的 M1~H1 多周期验证渲染表现。

MQL5 / C++
  INDICATOR_LINE_MODE_LIPS,                                                                       class=class="str">"cmt">// Lips line
  INDICATOR_LINE_MODE_DI_PLUS,                                                                     class=class="str">"cmt">// +DI line
  INDICATOR_LINE_MODE_DI_MINUS,                                                                    class=class="str">"cmt">//  -DI line
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Buffer integer properties                                                                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_BUFFER_PROP_INTEGER
  {
   BUFFER_PROP_INDEX_PLOT = class="num">0,                                                                     class=class="str">"cmt">// Plotted buffer serial number
   BUFFER_PROP_STATUS,                                                                             class=class="str">"cmt">// Buffer status(by drawing style) from the ENUM_BUFFER_STATUS enumeration
   BUFFER_PROP_TYPE,                                                                               class=class="str">"cmt">// Buffer type(from the ENUM_BUFFER_TYPE enumeration)
   BUFFER_PROP_TIMEFRAME,                                                                          class=class="str">"cmt">// Buffer period data(timeframe)
   BUFFER_PROP_ACTIVE,                                                                             class=class="str">"cmt">// Buffer usage flag
   BUFFER_PROP_DRAW_TYPE,                                                                          class=class="str">"cmt">// Graphical construction type(from the ENUM_DRAW_TYPE enumeration)
   BUFFER_PROP_ARROW_CODE,                                                                         class=class="str">"cmt">// Arrow code for DRAW_ARROW style
   BUFFER_PROP_ARROW_SHIFT,                                                                        class=class="str">"cmt">// The vertical shift of the arrows for DRAW_ARROW style
   BUFFER_PROP_LINE_STYLE,                                                                         class=class="str">"cmt">// Line style
   BUFFER_PROP_LINE_WIDTH,                                                                         class=class="str">"cmt">// Line width
   BUFFER_PROP_DRAW_BEGIN,                                                                         class=class="str">"cmt">// The number of initial bars that are not drawn and values in DataWindow
   BUFFER_PROP_SHOW_DATA,                                                                          class=class="str">"cmt">// Flag of displaying construction values in DataWindow
   BUFFER_PROP_SHIFT,                                                                              class=class="str">"cmt">// Indicator graphical construction shift by time axis in bars
   BUFFER_PROP_COLOR_INDEXES,                                                                      class=class="str">"cmt">// Number of colors
  };

常见问题

在指标对象初始化时传入目标品种和周期参数,函数库会按品种+周期生成独立缓冲区实例,避免互相覆盖。
给每个缓冲区对象打上品种、周期、指标名三条隶属标记,运行时就能按标记回溯所属指标上下文。
小布可读取当前品种页的指标配置,自动列出各缓冲区隶属标记与线标签,一眼看出跨周期引用是否串档。
需补指标线索引与显示名标签,这样日志输出时能直接看到是哪条线在第几缓冲区报错。
按功能分组连续编号,先放通用容量属性再放线索引与隶属标识,可减少跨文件引用时的错位风险。