DoEasy 函数库中的时间序列(第四十四部分):指标缓冲区对象类集合(基础篇)
用缓冲区集合给指标装多通道
在 DoEasy 函数库里,指标缓冲区不再是一个个零散数组,而是被收进一个对象集合统一管理。第四十四部分给出的思路是:把每个指标线对应的缓冲区封装成对象,再用集合容器持有它们,调用时按索引或名称取用。 这样做直接带来的好处是,新建指标时不必重复写缓冲区绑定、颜色、宽度等样板代码。原示例在 2020-09-28 发布,截至统计显示阅读量 1 444、评论 6,说明这类底层封装对实盘工具开发者有稳定需求。 集合对象内部维护了缓冲区的数量与类型,支持动态增删。你在 MT5 里打开对应示例,能看到原本要在 OnInit 里写四五行的缓冲区注册,被压缩成集合的初始化调用。
◍ 把 512 个指标缓冲区收进一个集合
从第三十九篇起,我用函数库搭自定义指标的底子,已经做好了时间序列对象及其集合,还有指标缓冲区对象——基准抽象缓冲区和基于它的指标缓冲区。这一节要落地的是指标缓冲区集合,目标是在单个程序里快速开任意数量的缓冲区,上限是 MT5 规定的 512 个,并且能方便地取数和访问。 时间序列集合和缓冲区集合之间的链接,理论上能拼出任意多品种多周期指标,下一篇才真正动手。本篇先把缓冲区集合开发并测通,支持九种绘图样式里任选来建缓冲区。 对做实盘图表的人来说,512 这个硬上限意味着足够在大量图表上堆复杂指标,但关键不在多,而在维护成本。库把访问过程压到三种方式:按绘制样式、按创建顺序编号、或按集合内索引,省掉手写一大堆 Buffer 数组和句柄的脏活。外汇与贵金属波动剧烈、杠杆高风险大,这类结构只解决工程效率,不预示任何方向。
「给缓冲区对象补齐搜索与排序的底子」
之前做的指标缓冲区对象继承自基准抽象缓冲区,只带着绘图样式相关的辅助读取方法。要在自定义指标里按状态灵活抓 double 数组,光靠继承不够,得在后代里补自定义方法,否则访问和排序都别扭。 MT5 里一个指标最多挂 512 个缓冲区。在 Defines.mqh 用宏替换代替裸写 512,以后开发员改上限,只动宏数值就行,不用全局搜文件。这个习惯能少踩很多坑。 排序属性得从枚举尾巴提到前面。原先整数型属性里只有 2 个能排序,未使用属性数量是 6,现在改成 2,新属性在排序标准枚举里的位置必须和属性枚举位置对齐,否则 CSelect 类在第三部分讲过的匹配逻辑会失效。 抽象缓冲区类 Buffer.mqh 现在 include 了 CSelect,公开部分加了 SetCustomName()——给缓冲区起自定义名,后面就能按名字在集合里搜。另外补了 GetColorBufferValueIndex() 返回颜色索引,原来的 GetColorBufferValue() 重命名为 GetColorBufferValueColor(),计算挪到独立方法里。箭头缓冲区漏写的虚拟方法也在 BufferArrow.mqh 补上了。 不同渲染类型(线、段、直方图、之字、填充、柱线、蜡烛)分别加了 2 到 8 个 set/get 方法,对接缓冲区数组和文件。最终用户不用管缓冲区编号,直接按用途调方法。集合类准备好后,就能用相同缓冲区可视化不同事件,不查重。
MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE, class=class="str">"cmt">// Failed to change the class="type">color array size MSG_LIB_SYS_FAILED_ADD_BUFFER, class=class="str">"cmt">// Failed to add buffer object to the list MSG_LIB_SYS_FAILED_CREATE_BUFFER_OBJ, class=class="str">"cmt">// Failed to create "Indicator buffer" object MSG_LIB_TEXT_YES, class=class="str">"cmt">// Yes MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF, class=class="str">"cmt">// Invalid number of indicator buffers(class="macro">#class="kw">property indicator_buffers) MSG_LIB_TEXT_BUFFER_TEXT_MAX_BUFFERS_REACHED, class=class="str">"cmt">// Reached maximum possible number of indicator buffers MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NONE, class=class="str">"cmt">// No drawing {"Не удалось изменить размер массива цветов","Failed to resize class="type">color array"}, {"Не удалось добавить объект-буфер в список","Failed to add buffer object to list"}, {"Не удалось создать объект \"Индикаторный буфер\"","Failed to create object \"Indicator buffer\""}, {"Да","Yes"}, {"Неправильно указано количество буферов индикатора (class="macro">#class="kw">property indicator_buffers)","Number of indicator buffers incorrect(class="macro">#class="kw">property indicator_buffers)"}, {"Достигнуто максимально возможное количество индикаторных буферов","Maximum number of indicator buffers reached"}, {"Нет отрисовки","No drawing"}, class=class="str">"cmt">//+------------------------------------------------------------------+
宏定义与缓冲区枚举的底层约定
在 MT5 自建指标或 EA 库时,先用宏把高频常量固化下来,能省掉大量重复字面量。下面这段预处理指令把错误定位、语言、定时器频率等全部参数化:TIMER_FREQUENCY 设为 16 毫秒,意味着库内最小轮询节拍约 62.5 Hz;TOTAL_TRY 默认 5 次交易尝试,IND_BUFFERS_MAX 直接拉到 512,远超普通指标的 8~32 缓冲上限。 DFUN_ERR_LINE 这个宏值得单独看:它拼接 __FUNCTION__ 与 __LINE__,并依据 TerminalInfoString(TERMINAL_LANGUAGE) 是否为 "Russian" 决定输出 "Page " 还是 "Line "。俄语终端下报错指向页码,其他语言指向行号,本地化调试信息就这么隐式处理了。 缓冲区整数属性被收进 ENUM_BUFFER_PROP_INTEGER 枚举,从 BUFFER_PROP_INDEX_PLOT=0 起,依次覆盖绘图序号、状态、类型、周期、启用标志。写多缓冲指标时,用枚举而非魔法数字去索引属性,后续改绘制逻辑不会牵一发动全身。 开 MT5 随便建个指标模板,把 IND_BUFFERS_MAX 改成 512 试跑,能直观感受到大缓冲数组对内存占用的边际影响,外汇与贵金属品种在高波动时段跑这类重指标需警惕终端卡顿风险。
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" 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_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 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 };
◍ 指标缓冲区整型属性的枚举与计数
在 MT5 自定义指标里,每个绘图缓冲区都有一组整型属性用来控制画法。下面这段枚举把可设置的整型属性列全了:从图形类型 BUFFER_PROP_DRAW_TYPE、箭头代码 BUFFER_PROP_ARROW_CODE,到线型线宽、起始不画柱数、时间轴偏移、颜色索引与数据缓冲数,再到三个带底色标记的基础索引属性(BUFFER_PROP_INDEX_BASE、BUFFER_PROP_INDEX_NEXT 等)。 代码里用两个宏给出了数量边界:BUFFER_PROP_INTEGER_TOTAL 等于 19,代表整型缓冲区属性总数;BUFFER_PROP_INTEGER_SKIP 等于 6,代表排序时不参与使用的属性个数。实际写指标时,如果你要遍历或校验属性,这两个数字就是循环上限和跳过量的硬依据。 带背景高亮的 BUFFER_PROP_INDEX_BASE 与 BUFFER_PROP_INDEX_NEXT 值得单独看:前者是主数据缓冲区的基准索引,后者指向下一个可被分配为空闲数组的缓冲区。搞多缓冲彩色指标时,漏设这两个索引,绘图层可能直接不渲染。
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">color BUFFER_PROP_NUM_DATAS, class=class="str">"cmt">// Number of data buffers BUFFER_PROP_INDEX_BASE, class=class="str">"cmt">// Basic data buffer index BUFFER_PROP_INDEX_COLOR, class=class="str">"cmt">// Color buffer index BUFFER_PROP_INDEX_NEXT, class=class="str">"cmt">// Index of the free array to be assigned as the next indicator buffer }; class="macro">#define BUFFER_PROP_INTEGER_TOTAL(class="num">19) class=class="str">"cmt">// Total number of integer bar properties class="macro">#define BUFFER_PROP_INTEGER_SKIP(class="num">6) class=class="str">"cmt">// Number of buffer properties not used in sorting 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)不是画完线就完了,MT5 用一组 ENUM_BUFFER_PROPERTY 枚举来逐个描述每条缓冲区的脾气。上面列的这一截,就是该枚举靠后的成员,从 BUFFER_PROP_INDEX_PLOT 一直到 BUFFER_PROP_NUM_DATAS,共 19 个属性项。 BUFFER_PROP_INDEX_PLOT 标的是「这条被画的缓冲区排第几」,而 BUFFER_PROP_STATUS、BUFFER_PROP_TYPE 分别取 ENUM_BUFFER_STATUS 与 ENUM_BUFFER_TYPE 的值,决定缓冲区的状态和存储类型。BUFFER_PROP_TIMEFRAME 让同指标可挂不同周期数据,BUFFER_PROP_ACTIVE 则是「这条还用不用」的开关。 画线细节全在 BUFFER_PROP_DRAW_TYPE 到 BUFFER_PROP_LINE_WIDTH:箭头的代码与纵向偏移(DRAW_ARROW 专用)、线型线宽、以及 BUFFER_PROP_DRAW_BEGIN 控制前多少根 bar 不画也不进 DataWindow。BUFFER_PROP_SHIFT 按 bar 数整体平移图形,BUFFER_PROP_SHOW_DATA 管 DataWindow 里显不显示数值。 高亮的两项很关键:BUFFER_PROP_INDEX_BASE 指向基础数据缓冲区的索引,BUFFER_PROP_INDEX_NEXT 给出「下一个可被分配成指标缓冲区的空闲数组索引」——写动态多缓冲指标时靠它链式扩展。最后 BUFFER_PROP_COLOR_INDEXES 与 BUFFER_PROP_COLOR 管配色,BUFFER_PROP_NUM_DATAS 回报实际数据缓冲区总数。外汇与贵金属指标开发属高风险环境,参数误用可能导致图形错乱或信号延迟,建议在 MT5 策略测试器里逐项验证。
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 BUFFER_PROP_COLOR, class=class="str">"cmt">// Drawing class="type">color BUFFER_PROP_INDEX_BASE, class=class="str">"cmt">// Basic data buffer index BUFFER_PROP_INDEX_NEXT, class=class="str">"cmt">// Index of the free array to be assigned as the next indicator buffer BUFFER_PROP_NUM_DATAS class=class="str">"cmt">// Number of data buffers