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

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

第 1/3 篇

「在 DoEasy 里把多周期指标拉进同一根 K 线」

DoEasy 函数库走到第四十七部分,核心是把标准指标从「单品种单周期」扩展成「多品种多周期」的统一时间序列。原作者在 2020-11-20 发布的这篇里,把这类指标封装进库的类结构,让调用端不必再为每个货币对、每个周期反复写指标句柄。 实际意义很直接:比如同时盯 XAUUSD 的 M15 与 EURUSD 的 H1,传统写法要在 EA 里开两个 iMA 句柄并分别 CopyBuffer;纳入库之后,指标对象自身携带周期与品种属性,EA 只管按时间序列索引取缓冲值。外汇与贵金属杠杆高、跳空频繁,多周期共振信号失效的概率不低,任何跨周期调用都先在小账户验证。 这部分的落地动作只有一个:打开 MT5 的 MetaEditor,把库的时间序列类编译进你的 Include 路径,然后写三行代码测一个跨品种 MA 差值。能跑通,后面才有资格谈信号合成。

◍ 让自定义指标跨品种跨周期读取标准指标

标准终端里的指标只能画在当前图表品种和周期上,数据范围被锁死。本文要做的,是给自定义指标加上能力:在 EURUSD H1 图表上,直接算并画出 XAUUSD M15 的 AC 加速振荡器值,这类跨域读取在常规环境里做不到。 实现思路是把标准指标封装成可复用的缓冲区对象。每个对象除了常规缓冲属性,还要带三个标识:所属标准指标的句柄(按指标句柄使用缓冲区)、指标类型枚举 ENUM_INDICATOR(按指标类型使用缓冲区)、以及指标名称字符串(按指标名称使用缓冲区)。这样同一个自定义指标能按不同参数挂多个相同标准指标,靠标识符区分每条缓冲归属哪次调用。 除了数据库层改造,我对“新柱线”对象和时间序列类也动了刀。连接断开、睡眠模式切换等异常恢复后,函数库历史里常会漏掉若干根柱线。新增的跟踪逻辑会记录跳过柱线数量,并抛出“跳过柱线”事件,你在 EA 里可以捕获它决定重算还是报警。外汇和贵金属市场高波动、断线频发,这类缺口处理直接影响信号可靠性。

给缓冲区与时间序列补上跳过柱线的感知

在 DoEasy 函数库里做标准指标操控前,先把底层数据结构和时间序列类补齐。Datas.mqh 中新增了一批消息 ID 及对应文本,专门用于描述缓冲区的绘制索引、指标句柄、时间帧等属性;Defines.mqh 里把原先含糊的 TOTAL_TRY 常量改名为带归属的 TRADE 尝试次数常量,后续再加别的尝试类常量时就不必改旧名。 整数型属性枚举从 20 扩到 23,字符串型从 2 扩到 3,同时排序标准枚举里加了新缓冲区对象的排序类型,保证新增属性可被检索和选择。 NewBarObj.mqh 的“新柱线”类加了四个私有成员:前次事件时间(手动/自动各一)、两事件间隔秒数、间隔柱数。公开方法里把 Period 改名为 Timeframe,并暴露新变量的读取接口。构造函数初始化列表设秒数和柱线数为初值,其余在主体置零。 自动时间管理下,新柱形成后保存前一根时间,并算出间隔秒数与柱计数;手动管理下也补存前次时间、修掉自动期时间赋值的错。间隔柱数大于 1 即意味着断线后跳过了历史柱,或服务器侧本就缺数据——这是检测掉线缺口的硬信号。 Bar.mqh 增加无参构造函数,避免参数化构造自顾自拉历史、在没数据的品种周期上刷错误日志。SeriesDE.mqh 改为用空对象建时间序列,再按品种/周期/时间填数据;其创建事件的方法新增输入参数,可分别发“新柱线”或“跳过柱线”事件,跳过数量经 EventChartCustom() 的 lparam 传出。 TimeSeriesDE.mqh 的更新方法嵌了跳过柱线判定块:有新柱就发新柱事件,有缺失柱就补发跳过事件。TimeSeriesCollection.mqh 加了重创全部时间序列的公开方法,断线恢复或新柱时一键重建比逐个处理更省事。外汇与贵金属行情在跳空后重构时序易出偏差,实操前建议在 MT5 用模拟品种断网复现验证。

MQL5 / C++
  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_HANDLE,                 class=class="str">"cmt">// Handle of an indicator class="kw">using a buffer
  MSG_LIB_TEXT_BUFFER_TEXT_IND_TYPE,                   class=class="str">"cmt">// Type of an indicator class="kw">using a buffer
  MSG_LIB_TEXT_BUFFER_TEXT_TIMEFRAME,                  class=class="str">"cmt">// Buffer(timeframe) data period
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS,                     class=class="str">"cmt">// Buffer status
  MSG_LIB_TEXT_BUFFER_TEXT_TYPE,                       class=class="str">"cmt">// Buffer type
  MSG_LIB_TEXT_BUFFER_TEXT_ACTIVE,                     class=class="str">"cmt">// Active
  MSG_LIB_TEXT_BUFFER_TEXT_ARROW_CODE,                 class=class="str">"cmt">// Arrow code
  MSG_LIB_TEXT_BUFFER_TEXT_ARROW_SHIFT,                class=class="str">"cmt">// The vertical shift of the arrows
  MSG_LIB_TEXT_BUFFER_TEXT_DRAW_BEGIN,                 class=class="str">"cmt">// The number of initial bars that are not drawn and values in DataWindow
  MSG_LIB_TEXT_BUFFER_TEXT_DRAW_TYPE,                  class=class="str">"cmt">// Graphical construction type
  MSG_LIB_TEXT_BUFFER_TEXT_SHOW_DATA,                  class=class="str">"cmt">// Display construction values in DataWindow
  MSG_LIB_TEXT_BUFFER_TEXT_SHIFT,                      class=class="str">"cmt">// Indicator graphical construction shift by time axis in bars
  MSG_LIB_TEXT_BUFFER_TEXT_LINE_STYLE,                 class=class="str">"cmt">// Line style

「文本缓冲区的枚举与错误定位宏」

在 MQL5 指标库里,文本缓冲区相关的消息枚举覆盖了从线宽、箭头尺寸到空值绘制的完整属性。上面列出的 MSG_LIB_TEXT_BUFFER_TEXT_* 常量,对应 DataWindow 中图形序列的显示名、所用指标名等字段,其中 MSG_LIB_TEXT_BUFFER_TEXT_IND_NAME 专门标记调用该缓冲区的指标名称。 紧随其后的俄英双语文组定义了缓冲区运行时元数据:下一可绘缓冲区索引、缓冲区 ID、所属指标句柄与类型、周期、状态、箭头代码及垂直偏移等。例如『Number of initial bars without drawing and values in DataWindow』说明前若干根 bar 可能不绘制也不在 DataWindow 给值,这是回测时容易误读成『数据缺失』的点。 宏替换段给了两个调试用的预处理定义。DFUN_ERR_LINE 会根据终端语言拼接函数名、『Line 』加 __LINE__ 行号与冒号;DFUN 则只输出函数名加冒号。俄文终端下它把『Line 』换成『Page 』,多语言环境排错时别被这处差异搞晕。 开 MT5 后,把 DFUN_ERR_LINE 粘进自定义指标源码,故意写错 #property indicator_buffers 数量,编译器报错行会直接带出函数与行号,比默认报错更省定位时间。外汇与贵金属指标调试同样受 MT5 运行时限制,缓冲区超限会触发『Maximum number of indicator buffers reached』,实盘前务必在策略测试器跑一遍。

MQL5 / C++
class="macro">#define DFUN_ERR_LINE(__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(class="type">class="kw">string)__LINE__+": ")
class="macro">#define DFUN(__FUNCTION__+": ")    class=class="str">"cmt">// "Function description"

◍ 库底层宏与事件枚举的硬参数

写 MT5 通用库时,先把一批全局宏钉死,能省掉后续大量魔法数字。下面这段把语言、历史请求截止、定时器最小频率、默认下单重试次数都成了编译期常量:TIMER_FREQUENCY 取 16 毫秒,意味着库内轻量轮询的节拍上限约 62.5 次/秒;TOTAL_TRADE_TRY 默认 5 次,是下单失败后的重试上限而非保证成交。 IND_COLORS_TOTAL 给到 64、IND_BUFFERS_MAX 给到 512,这两个数字对应 MT5 指标缓冲区与配色缓冲的硬上限,超了编译器或运行时就会拒载,写多缓冲指标时得心里有数。 事件侧用枚举 ENUM_SERIES_EVENT 描述时序事件:除无事件、新柱外,还显式列出 SERIES_EVENTS_MISSING_BARS(跳柱)。它的枚举值紧跟 SYMBOL_EVENTS_NEXT_CODE,而宏 SERIES_EVENTS_NEXT_CODE 又定义为跳柱事件值 +1,保证自定义事件码不与原生符号事件冲突。 缓冲区整数属性枚举 ENUM_BUFFER_PROP_INTEGER 从 0 开始:INDEX_PLOT 是绘图缓冲序号,STATUS 取绘制状态下的枚举,TYPE 区分缓冲类型,TIMEFRAME 绑定所属周期。直接读这些属性比自己维护平行数组更不容易错位。

MQL5 / C++
class="macro">#define COUNTRY_LANG("Russian")            class=class="str">"cmt">// Country language
class="macro">#define END_TIME(D&class="macro">#x27;class="num">31.12.class="num">3000 class="num">23:class="num">59:class="num">59&class="macro">#x27;)  class=class="str">"cmt">// End date for account history data requests
class="macro">#define TIMER_FREQUENCY(class="num">16)                       class=class="str">"cmt">// Minimal frequency of the library timer in milliseconds
class="macro">#define TOTAL_TRADE_TRY(class="num">5)                        class=class="str">"cmt">// Default number of trading attempts
class="macro">#define IND_COLORS_TOTAL(class="num">64)                       class=class="str">"cmt">// Maximum possible number of indicator buffer colors
class="macro">#define IND_BUFFERS_MAX(class="num">512)                      class=class="str">"cmt">// Maximum possible number of indicator buffers
class=class="str">"cmt">//--- Standard sounds
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| List of possible timeseries events                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_SERIES_EVENT
  {
   SERIES_EVENTS_NO_EVENT = SYMBOL_EVENTS_NEXT_CODE,       class=class="str">"cmt">// no event
   SERIES_EVENTS_NEW_BAR,                                  class=class="str">"cmt">// "New bar" event
   SERIES_EVENTS_MISSING_BARS,                             class=class="str">"cmt">// "Bars skipped" event
   };
class="macro">#define SERIES_EVENTS_NEXT_CODE(SERIES_EVENTS_MISSING_BARS+class="num">1)   class=class="str">"cmt">// Code of the next event after the "Bars skipped" event
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)
   };

指标缓冲区的可配置属性清单

在 MT5 自定义指标里,每个绘图缓冲区(buffer)并不是裸数组,而是通过一组 ENUM_BUFFER_PROPERTY 枚举来定义外观与行为。上面列出的属性覆盖了从是否启用、画线类型,到箭头代码、线宽、偏移等全部图形参数。 例如 BUFFER_PROP_DRAW_BEGIN 控制前 N 根 bar 不绘制,常用于均线类指标在窗口左侧留空;BUFFER_PROP_SHIFT 则把整个图形沿时间轴平移若干根 bar,做指标领先/滞后实验时直接改这个数就行。 被高亮部分的 BUFFER_PROP_ID、BUFFER_PROP_IND_HANDLE、BUFFER_PROP_IND_TYPE 是 MT5 后期加入的,用于支撑同一指标内多缓冲区的 ID 区分与外部句柄追溯。开 MT5 的 MetaEditor,新建指标时在 OnInit 里用 PlotIndexSetInteger 挨个设这些属性,编译后拖到 EURUSD 图表上就能看到缓冲区的实际渲染差异。外汇与贵金属杠杆高,指标视觉偏差可能放大交易误判,参数验证请在模拟盘完成。

MQL5 / C++
  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
  BUFFER_PROP_COLOR,                                                                       class=class="str">"cmt">// Drawing class="type">class="kw">color
  BUFFER_PROP_INDEX_BASE,                                                                  class=class="str">"cmt">// Base data buffer index
  BUFFER_PROP_INDEX_NEXT_BASE,                                                             class=class="str">"cmt">// Index of the array to be assigned as the next indicator buffer
  BUFFER_PROP_INDEX_NEXT_PLOT,                                                             class=class="str">"cmt">// Index of the next drawn buffer
  BUFFER_PROP_ID,                                                                          class=class="str">"cmt">// ID of multiple buffers of a single indicator
  BUFFER_PROP_IND_HANDLE,                                                                  class=class="str">"cmt">// Handle of an indicator class="kw">using a buffer
  BUFFER_PROP_IND_TYPE,                                                                    class=class="str">"cmt">// Type of an indicator class="kw">using a buffer
  BUFFER_PROP_NUM_DATAS,                                                                   class=class="str">"cmt">// Number of data buffers
  BUFFER_PROP_INDEX_COLOR,                                                                 class=class="str">"cmt">// Color buffer index
};

常见问题

在库里创建指标对象时指定目标品种与周期参数,再把缓冲区和当前图表K线按时间对齐,即可在同一根K线显示跨品种标准指标值。
先用文本缓冲区枚举把各缓冲区的标签打印出来,配合错误定位宏确认是哪根柱线越界,再检查时间序列是否开了跳过柱线感知。
可以,小布能扫描当前品种页的跨周期指标加载状态,提示缓冲区越界与柱线错位风险,省去手动翻代码核对。
硬参数错会导致事件不触发或指标不刷新,对照库文档的可配置属性清单逐项核对,并用错误宏捕获初始化返回值。
优先确认缓冲区类型、绘制样式与跳过柱线开关,这三项直接决定跨周期读数是否连续且不和主图错位。