DoEasy 函数库中的时间序列(第四十二部分):抽象指标缓冲区对象类(基础篇)
📘

DoEasy 函数库中的时间序列(第四十二部分):抽象指标缓冲区对象类(基础篇)

第 1/3 篇

「给指标缓冲区造一个抽象基类」

在 DoEasy 函数库的时间序列扩展里,第四十二部分落地了一个关键基建:CBuffer 抽象缓冲区类。它的职责是把指标里各种缓冲区(价格线、彩色线、柱状图数据等)的公共行为抽出来,让上层指标对象不再各自造轮子。 MT5 里指标缓冲区本质是一段按时间倒序排列的双精度数组,挂载到 Plot 上由终端渲染。CBuffer 作为抽象基类,只定义接口和通用内存管理,具体读写逻辑交给派生类实现,这样后续新增缓冲区类型时不用动旧代码。 要验证这套对象是否真的建出来了,最直接的方式是在指标 OnInit 里打印缓冲区对象的创建计数与句柄。如果终端日志里出现预期数量的 buffer 实例且无 4014(缓冲区分配失败)报错,说明抽象类的实例化链路是通的。 外汇与贵金属品种波动受杠杆和消息面影响大,这类底层封装仅解决代码结构问题,不预示任何行情方向,实盘前请在策略测试器用历史数据跑通对象生命周期。

用对象类接管指标缓冲区

上一篇文章里用 DoEasy 时间序列对象做了指标操作示例,当时靠手工定义缓冲区结构来存数据、认图表品种和周期,但给每种线型都写一套字段结构既不方便也不现实。 更顺手的路子是指标缓冲区对象类:用一个抽象基类兜住所有缓冲区共有的属性,再让具体图形类型的衍生类去继承,各自管自己的独有参数。 本文先写这个抽象缓冲区类。它要装下 ENUM_PLOT_PROPERTY_INTEGER、ENUM_PLOT_PROPERTY_DOUBLE、ENUM_PLOT_PROPERTY_STRING 三组枚举,以及缓冲区类型(数据/计算/状态)、绑定品种(当前或指定)、时间帧(当前或指定)、DataWindow 里的绘制序号、显隐标志、基础数据缓冲索引、辅助数据量、颜色缓冲索引、下一个可分配数组索引等属性。 等整套类写完,程序里只要说“建一个某类型缓冲区”,函数库就会自动建好数组、绑属性、排好后续缓冲区,不用再手写声明和绑定,直接拿缓冲区列表访问任意历史缓冲数据即可。 MQL5 本身支持单色和彩色两种相近绘图样式,所以这个函数库统一按着色缓冲区来建:想要单色线就全量设同一种颜色,想分色画柱线就按每根柱线给颜色编号。

◍ 抽象缓冲区类的对象标识与绘图绑定

做指标缓冲区之前,得先给对象一个能在集合里被检索的身份。函数库里每个对象创建时都会分到所属集合的 ID,缓冲区对象也一样:在 Defines.mqh 末尾加上指标缓冲区集合 ID,同时补上缓冲区对象状态枚举、整型/实型/字符串型属性定义,以及集合内排序条件。这些枚举和宏替换在库里都是标准件,熟手直接照用即可。 CBuffer 类放在 \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh,基类是 CBaseObj。它内部维持三个属性数组(整型、实型、字符串型),配合返回/设置属性索引的方法,以及按属性搜索、排序、判等的虚方法。受保护的参数化构造函数本应在 protected 区,但为了能在 MT5 里直接验证对象,这里把修饰符注释掉公开了。 绘图类型由缓冲区状态决定。ENUM_BUFFER_STATUS 枚举常量按顺序循环,能和 ENUM_DRAW_TYPE 里几乎同名的常数对齐;差别只在于绘图样式枚举多出了单色/彩色缓冲区的常量,且有一种样式不需要彩色缓冲区(两价位间填充)。所有缓冲区都着色,SetDrawType() 里做的实质是:状态为 BUFFER_TYPE_CALCULATE(0) 或 BUFFER_STATUS_NONE(0) 时设“不绘图”;为 BUFFER_STATUS_FILLING 时设对应填充样式;其余值直接加 8 偏移,跳到彩色绘图样式常数区。 构造函数吃进缓冲区状态、类型、绘制索引(市场观察索引)和基础数组索引,把对象归到缓冲区集合,用默认值填好三类属性,再把指标缓冲区绑到数组,并依默认填充值设好绘制缓冲区的属性。这样产出的就是单色指标缓冲区,从指标里建时不用再声明分配数组——BUFFER_PROP_INDEX_PLOT 存着绘制缓冲区索引,数据收发都走它。外汇与贵金属 MT5 编程属高风险操作,改文件前建议先备份 Include 目录。

MQL5 / C++
  MSG_LIB_TEXT_WAIT,                                      class=class="str">"cmt">// Wait
  MSG_LIB_TEXT_END,                                      class=class="str">"cmt">// End
  MSG_LIB_TEXT_PERIOD_CURRENT,                           class=class="str">"cmt">// Current chart period

  MSG_LIB_TEXT_TS_TEXT_ATTEMPT,                          class=class="str">"cmt">// Attempt:
  MSG_LIB_TEXT_TS_TEXT_WAIT_FOR_SYNC,                    class=class="str">"cmt">// Waiting for data synchronization ...
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,                   class=class="str">"cmt">// Index of the free array to be assigned as the next indicator 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

「指标缓冲区的属性枚举清单」

在 MT5 自定义指标开发里,文本缓冲区(Text Buffer)相关的中文描述通常由一组枚举常量驱动,便于在 DataWindow 与图表上正确呈现。下面这组 MSG_LIB_TEXT_BUFFER_TEXT_* 常量覆盖了从箭头垂直偏移、初始不绘制 bar 数,到绘制类型、线型线宽、空值定义等完整配置面。 其中 MSG_LIB_TEXT_BUFFER_TEXT_DRAW_BEGIN 控制最左侧多少根初始 bar 既不画线也不在 DataWindow 显示数值;MSG_LIB_TEXT_BUFFER_TEXT_EMPTY_VALUE 则约定哪个数值代表「此处不画」的空点位。绘制类型细分到 ZigZag、双缓冲直方图、蜡烛与竹节线,线型从实线到「 dash-dot-dot」共 5 种。 开 MT5 用 MetaEditor 搜 MSG_LIB_TEXT_BUFFER_TEXT_ARROW 这类常量,能直接定位标准库里缓冲区本地化文本的定义位置,改一处即可影响全指标的多语言标签。外汇与贵金属指标调试波动剧烈,参数误设可能在高风险行情下产生误导性图形。

MQL5 / C++
  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
  MSG_LIB_TEXT_BUFFER_TEXT_LINE_WIDTH,                      class=class="str">"cmt">// Line width
  MSG_LIB_TEXT_BUFFER_TEXT_COLOR_NUM,                       class=class="str">"cmt">// Number of colors
  MSG_LIB_TEXT_BUFFER_TEXT_COLOR,                           class=class="str">"cmt">// Drawing class="type">class="kw">color
  MSG_LIB_TEXT_BUFFER_TEXT_EMPTY_VALUE,                     class=class="str">"cmt">// Empty value for plotting where nothing will be drawn
  MSG_LIB_TEXT_BUFFER_TEXT_SYMBOL,                          class=class="str">"cmt">// Buffer symbol
  MSG_LIB_TEXT_BUFFER_TEXT_LABEL,                           class=class="str">"cmt">// Name of the graphical indicator series displayed in DataWindow
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NAME,                     class=class="str">"cmt">// Indicator buffer with graphical construction type 
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NONE,                     class=class="str">"cmt">// No drawing
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_FILLING,                  class=class="str">"cmt">// Color filling between two levels
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_LINE,                     class=class="str">"cmt">// Line
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_HISTOGRAM,                class=class="str">"cmt">// Histogram from the zero line
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_ARROW,                    class=class="str">"cmt">// Drawing with arrows
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_SECTION,                  class=class="str">"cmt">// Segments
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_HISTOGRAM2,               class=class="str">"cmt">// Histogram on two indicator buffers
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_ZIGZAG,                   class=class="str">"cmt">// Zigzag
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_BARS,                     class=class="str">"cmt">// Display as bars
  MSG_LIB_TEXT_BUFFER_TEXT_STATUS_CANDLES,                  class=class="str">"cmt">// Display as candles

  MSG_LIB_TEXT_BUFFER_TEXT_TYPE_CALCULATE,                  class=class="str">"cmt">// Calculated buffer
  MSG_LIB_TEXT_BUFFER_TEXT_TYPE_DATA,                       class=class="str">"cmt">// Colored data buffer

  MSG_LIB_TEXT_BUFFER_TEXT_STYLE_SOLID,                     class=class="str">"cmt">// Solid line
  MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASH,                      class=class="str">"cmt">// Dashed line
  MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DOT,                       class=class="str">"cmt">// Dotted line
  MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOT,                   class=class="str">"cmt">// Dot-dash line
  MSG_LIB_TEXT_BUFFER_TEXT_STYLE_DASHDOTDOT,                class=class="str">"cmt">// Dash - two dots
};

指标缓冲区与绘图类型的字段映射

在 MT5 自定义指标里,缓冲区(buffer)不是只存数据就完事,它同时绑定了绘图方式、颜色、线型等显示属性。上面这段俄英对照的字符串数组,实际是某套本地化封装里给 PlotIndexSetXXX 系列函数做的文案映射,开 MT5 调指标属性面板时能直接对应上。 比如 "Current chart period" 对应缓冲区绑定的周期参数,"Plot buffer sequence number" 是绘图缓冲区的序号,"Color buffer index" 则指向含颜色的缓冲区索引——这些字段错一个,DataWindow 里就可能显示空值或绘图错位。 绘图类型那组更实用:Line 是普通线,Histogram from the zero line 是从零轴画的直方图,Zigzag 是之字转向,Display as a sequence of candlesticks 能把缓冲区渲染成 K 线序列。线型方面 Solid line / Dotted line / Dash-dot line 分别对应实线、点线、点划线,改线型只动风格字段不影响计算。 外汇和贵金属波动快、杠杆高,缓冲区若设了错误空值(An empty value for plotting)可能导致信号在极端行情下不绘制,复盘时容易漏掉关键转折。建议把这段映射直接抄进你的指标调试注释,逐个字段在策略测试器里改参数验证。

◍ 缓冲区状态枚举与集合 ID 的落地定义

在 MT5 指标内核里,绘图缓冲区的抽象状态靠一个枚举来区分。ENUM_BUFFER_STATUS 把「不画、双线填色、普通线、零轴直方图、箭头、线段、双缓冲直方图」归成 7 类,写自定义指标时直接套用比自己硬编字符串稳。 集合列表用 16 进制 ID 做隔离,历史序列是 0x777A,实时行情 0x777B,事件 0x777C,账户 0x777D,品种 0x777E,时间序列 0x777F,指标缓冲专门留了 0x7780。这些宏定义直接贴进 EA 或指标头文件,调 Collection 相关函数时传对应 ID 就不会串数据。 外汇和贵金属杠杆高、滑点随机,用缓冲区状态切换做可视化时,先在策略测试器跑历史再生效,别直接挂实盘。

MQL5 / C++
class="macro">#define COLLECTION_HISTORY_ID(0x777A)       class=class="str">"cmt">// Historical collection list ID
class="macro">#define COLLECTION_MARKET_ID(0x777B)       class=class="str">"cmt">// Market collection list ID
class="macro">#define COLLECTION_EVENTS_ID(0x777C)       class=class="str">"cmt">// Event collection list ID
class="macro">#define COLLECTION_ACCOUNT_ID(0x777D)       class=class="str">"cmt">// Account collection list ID
class="macro">#define COLLECTION_SYMBOLS_ID(0x777E)       class=class="str">"cmt">// Symbol collection list ID
class="macro">#define COLLECTION_SERIES_ID(0x777F)       class=class="str">"cmt">// Timeseries collection list ID
class="macro">#define COLLECTION_BUFFERS_ID(0x7780)       class=class="str">"cmt">// Indicator buffer collection list ID

enum ENUM_BUFFER_STATUS
  {
   BUFFER_STATUS_NONE,                                            class=class="str">"cmt">// No drawing
   BUFFER_STATUS_FILLING,                                         class=class="str">"cmt">// Color filling between two levels(MQL5)
   BUFFER_STATUS_LINE,                                            class=class="str">"cmt">// Line
   BUFFER_STATUS_HISTOGRAM,                                        class=class="str">"cmt">// Histogram from the zero line
   BUFFER_STATUS_ARROW,                                           class=class="str">"cmt">// Drawing with arrows
   BUFFER_STATUS_SECTION,                                         class=class="str">"cmt">// Segments
   BUFFER_STATUS_HISTOGRAM2,                                      class=class="str">"cmt">// Histogram on two indicator buffers
  };

常见问题

可以建一个抽象缓冲区基类,把颜色、绘图类型、状态等公共属性收进对象,子类只填差异字段,初始化代码量能砍掉一大半。
在抽象类里用字段映射把缓冲区属性枚举和绘图类型一一对应,创建对象时传绘图类型即可自动绑对,避免手填类型错位。
可以,把指标代码贴给小布,它会按抽象缓冲区类的属性清单比对,标出缺失的枚举字段和状态定义,省去人工逐行核。
集合 ID 用来在运行时定位该缓冲区所属分组,不写会导致多缓冲区指标刷新时找不到对应数据,出现错图或空白。
绘图类型、颜色模式、缓冲区状态、集合 ID 这四项必须进枚举清单,缺一个编译期或运行期就会报未定义引用。