DoEasy 函数库中的时间序列(第四十二部分):抽象指标缓冲区对象类(基础篇)
「给指标缓冲区造一个抽象基类」
在 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 目录。
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 这类常量,能直接定位标准库里缓冲区本地化文本的定义位置,改一处即可影响全指标的多语言标签。外汇与贵金属指标调试波动剧烈,参数误设可能在高风险行情下产生误导性图形。
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 就不会串数据。 外汇和贵金属杠杆高、滑点随机,用缓冲区状态切换做可视化时,先在策略测试器跑历史再生效,别直接挂实盘。
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 };