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

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

(2/3)·单缓冲区逻辑撑不住多线指标,辨识成本陡增,这篇讲清隶属关系的底层标记法

偏理论 第 2/3 篇
在跨品种跨周期把指标线搬进当前图表时,很多人直接套用单缓冲区的取数写法,结果同名均线或随机振荡的多条线混在一起分不清。给缓冲对象补上线型与短名参数,才能在通用指标里精准回溯每条曲线的来源。

◍ 缓冲区属性枚举里的整数与字符串字段

在 MT5 指标开发里,缓冲区(buffer)不只是装价格序列的数组,每个 buffer 还带一堆元属性。源码用 ENUM_BUFFER_PROP_INTEGER 和 ENUM_BUFFER_PROP_STRING 两个枚举把这些属性列清楚,方便用 BufferGetInteger / BufferGetString 读取。 整数类属性里,BUFFER_PROP_COLOR 管画线颜色,BUFFER_PROP_INDEX_BASE 标基底数据缓冲索引,BUFFER_PROP_IND_LINE_MODE 决定该缓冲是指标线还是其他形态;另有 BUFFER_PROP_ID、BUFFER_PROP_IND_HANDLE、BUFFER_PROP_NUM_DATAS 等描述多缓冲指标的归属与规模。 宏定义给出硬数字:BUFFER_PROP_INTEGER_TOTAL 为 24,即整数属性共 24 个;BUFFER_PROP_INTEGER_SKIP 为 2,代表排序时不用的属性有 2 个。字符串属性枚举从 BUFFER_PROP_INTEGER_TOTAL + BUFFER_PROP_DOUBLE_TOTAL 偏移开始,含 BUFFER_PROP_SYMBOL、BUFFER_PROP_LABEL、BUFFER_PROP_IND_NAME、BUFFER_PROP_IND_NAME_SHORT 四项,BUFFER_PROP_STRING_TOTAL 宏固定为 4。 开 MT5 按 F4 进 MetaEditor,搜 ENUM_BUFFER_PROP_INTEGER 可直接核对上述枚举值;改 BUFFER_PROP_COLOR 或 BUFFER_PROP_LABEL 后编译挂 EURUSD 1 分钟图,能在数据窗口看到对应缓冲名与色块变化。外汇与贵金属交易杠杆高、滑点大,指标缓冲配置错误可能画出误导线,验证时先用模拟账户。

MQL5 / C++
enum ENUM_BUFFER_PROP_INTEGER
  {
  BUFFER_PROP_COLOR,                                                                     class=class="str">"cmt">// Drawing class="type">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_IND_LINE_MODE,                                                              class=class="str">"cmt">// Indicator line
  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 using a buffer
  BUFFER_PROP_IND_TYPE,                                                                   class=class="str">"cmt">// Type of an indicator 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
  };
class="macro">#define BUFFER_PROP_INTEGER_TOTAL(class="num">24)                                                    class=class="str">"cmt">// Total number of integer bar properties
class="macro">#define BUFFER_PROP_INTEGER_SKIP(class="num">2)                                                     class=class="str">"cmt">// Number of buffer properties not used in sorting
enum ENUM_BUFFER_PROP_STRING
  {
  BUFFER_PROP_SYMBOL = (BUFFER_PROP_INTEGER_TOTAL+BUFFER_PROP_DOUBLE_TOTAL), class=class="str">"cmt">// Buffer symbol
  BUFFER_PROP_LABEL,                                                                      class=class="str">"cmt">// Name of the graphical indicator series displayed in DataWindow
  BUFFER_PROP_IND_NAME,                                                                   class=class="str">"cmt">// Name of an indicator using a buffer
  BUFFER_PROP_IND_NAME_SHORT,                                                             class=class="str">"cmt">// Short name of an indicator using a buffer
  };
class="macro">#define BUFFER_PROP_STRING_TOTAL(class="num">4)                                                     class=class="str">"cmt">// Total number of class="type">class="kw">string buffer properties

「给指标缓冲区排队的枚举定义」

写多缓冲指标时,常需要按某种属性把缓冲区排个序再批量处理。下面这段定义给出了一套排序判据的枚举,从绘图序号一直覆盖到颜色与位移。 宏 FIRST_BUFFER_DBL_PROP 与 FIRST_BUFFER_STR_PROP 用 BUFFER_PROP_INTEGER_TOTAL - BUFFER_PROP_INTEGER_SKIP 这类表达式算出双精度、字符串属性的起始偏移,说明整数属性之后才排双精度、再排字符串,总数由系统常量抠掉跳过项得到。 枚举 ENUM_SORT_BUFFER_MODE 里 SORT_BY_BUFFER_INDEX_PLOT = 0 是默认按绘图序号,其余如 SORT_BY_BUFFER_LINE_WIDTH 按线宽、SORT_BY_BUFFER_COLOR 按颜色、SORT_BY_BUFFER_SHIFT 按时间轴偏移,总共列了 16 种判据。开 MT5 把这段贴进头文件,就能在遍历缓冲区时直接 switch 这个枚举来分组。 外汇与贵金属杠杆高,指标逻辑仅辅助判断,实际信号概率随品种与周期漂移,别当确定性依据。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Possible buffer sorting criteria                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#define FIRST_BUFFER_DBL_PROP(BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP)
class="macro">#define FIRST_BUFFER_STR_PROP(BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP+BUFFER_PROP_DOUBLE_TOTAL-BUFFER_PROP_DOUBLE_SKIP)
enum ENUM_SORT_BUFFER_MODE
  {
class=class="str">"cmt">//--- Sort by integer properties
   SORT_BY_BUFFER_INDEX_PLOT = class="num">0,                                                    class=class="str">"cmt">// Sort by the plotted buffer serial number
   SORT_BY_BUFFER_STATUS,                                                            class=class="str">"cmt">// Sort by buffer drawing style(status) from the ENUM_BUFFER_STATUS enumeration
   SORT_BY_BUFFER_TYPE,                                                              class=class="str">"cmt">// Sort by buffer type(from the ENUM_BUFFER_TYPE enumeration)
   SORT_BY_BUFFER_TIMEFRAME,                                                         class=class="str">"cmt">// Sort by the buffer data period(timeframe)
   SORT_BY_BUFFER_ACTIVE,                                                            class=class="str">"cmt">// Sort by the buffer usage flag
   SORT_BY_BUFFER_DRAW_TYPE,                                                         class=class="str">"cmt">// Sort by graphical construction type(from the ENUM_DRAW_TYPE enumeration)
   SORT_BY_BUFFER_ARROW_CODE,                                                        class=class="str">"cmt">// Sort by the arrow code for DRAW_ARROW style
   SORT_BY_BUFFER_ARROW_SHIFT,                                                       class=class="str">"cmt">// Sort by the vertical shift of the arrows for DRAW_ARROW style
   SORT_BY_BUFFER_LINE_STYLE,                                                        class=class="str">"cmt">// Sort by the line style
   SORT_BY_BUFFER_LINE_WIDTH,                                                        class=class="str">"cmt">// Sort by the line width
   SORT_BY_BUFFER_DRAW_BEGIN,                                                        class=class="str">"cmt">// Sort by the number of initial bars that are not drawn and values in DataWindow
   SORT_BY_BUFFER_SHOW_DATA,                                                         class=class="str">"cmt">// Sort by the flag of displaying construction values in DataWindow
   SORT_BY_BUFFER_SHIFT,                                                             class=class="str">"cmt">// Sort by the indicator graphical construction shift by time axis in bars
   SORT_BY_BUFFER_COLOR_INDEXES,                                                     class=class="str">"cmt">// Sort by a number of attempts
   SORT_BY_BUFFER_COLOR                                                              class=class="str">"cmt">// Sort by the drawing class="type">color
  };

缓冲区排序枚举与属性打印接口

在 MQL5 的缓冲区描述类里,排序方式被封装成一个枚举,从基础 buffer 索引一直排到字符串类属性。比较关键的两个是 SORT_BY_BUFFER_IND_LINE_MODE(按指标线模式排)和 SORT_BY_BUFFER_IND_NAME_SHORT(按指标短名排),它们决定了多缓冲指标在内部列表里的呈现顺序。 枚举后半段切到真实属性与字符串属性:SORT_BY_BUFFER_EMPTY_VALUE 对应 FIRST_BUFFER_DBL_PROP,控制“空白不画”的数值;SORT_BY_BUFFER_LABEL 则是 DataWindow 里显示的图形序列名。写自定义指标时,若发现 DataWindow 顺序乱掉,优先怀疑这几个排序枚举有没有设对。 公开接口里有一个 Print(const bool full_prop=false),传 true 会把缓冲区全部属性倒进日志,false 只打支持的。调试多缓冲 EA 时,在 OnInit 后调一次 CBufferDesc::Print(true),能直接看到每个 buffer 的 handle、type、label 是否如预期绑定。 虚函数 SetArrowCode 在基类里是空实现,只接收 uchar 箭头码。子类若画箭头类指标(如箭头入场信号),必须重写它,否则调用后什么都不会发生——这是最常见的“箭头不显示”坑点之一。外汇与贵金属杠杆高,任何指标逻辑都先在策略测试器跑历史再上实盘。

MQL5 / C++
  SORT_BY_BUFFER_INDEX_BASE,                                                                     class=class="str">"cmt">// Sort by the basic data buffer index
  SORT_BY_BUFFER_INDEX_NEXT_BASE,                                                                 class=class="str">"cmt">// Sort by the index of the array to be assigned as the next indicator buffer
  SORT_BY_BUFFER_INDEX_NEXT_PLOT,                                                                 class=class="str">"cmt">// Sort by the index of the next drawn buffer
  SORT_BY_BUFFER_IND_LINE_MODE,                                                                   class=class="str">"cmt">// Sort by the indicator line
  SORT_BY_BUFFER_ID,                                                                              class=class="str">"cmt">// Sort by ID of multiple buffers of a single indicator
  SORT_BY_BUFFER_IND_HANDLE,                                                                      class=class="str">"cmt">// Sort by handle of an indicator using a buffer
  SORT_BY_BUFFER_IND_TYPE,                                                                        class=class="str">"cmt">// Sort by type of an indicator using a buffer
class=class="str">"cmt">//--- Sort by real properties
  SORT_BY_BUFFER_EMPTY_VALUE = FIRST_BUFFER_DBL_PROP,                                             class=class="str">"cmt">// Sort by the empty value for plotting where nothing will be drawn
class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties
  SORT_BY_BUFFER_SYMBOL = FIRST_BUFFER_STR_PROP,                                                  class=class="str">"cmt">// Sort by the buffer symbol
  SORT_BY_BUFFER_LABEL,                                                                           class=class="str">"cmt">// Sort by the name of the graphical indicator series displayed in DataWindow
  SORT_BY_BUFFER_IND_NAME,                                                                        class=class="str">"cmt">// Sort by name of an indicator using a buffer
  SORT_BY_BUFFER_IND_NAME_SHORT,                                                                  class=class="str">"cmt">// Sort by a class="type">class="kw">short name of an indicator using a buffer
  };
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">public:  
class=class="str">"cmt">//--- Send description of buffer properties to the journal(full_prop=true - all properties, false - only supported ones)
  class="type">void                Print(class="kw">const class="type">bool full_prop=false);
class=class="str">"cmt">//--- Display a class="type">class="kw">short buffer description in the journal(implementation in the descendants)
  class="kw">virtual class="type">void        PrintShort(class="type">void) {;}
  
class=class="str">"cmt">//--- Set(class="num">1) the arrow code, (class="num">2) vertical shift of arrows, (class="num">3) symbol, (class="num">4) timeframe, (class="num">5) buffer activity flag
class=class="str">"cmt">//--- (class="num">6) drawing type, (class="num">7) number of initial bars without drawing, (class="num">8) flag of displaying construction values in DataWindow,
class=class="str">"cmt">//--- (class="num">9) shift of the indicator graphical construction along the time axis, (class="num">10) line style, (class="num">11) line width,
class=class="str">"cmt">//--- (class="num">12) total number of colors, (class="num">13) one drawing class="type">color, (class="num">14) class="type">color of drawing in the specified class="type">color index,
class=class="str">"cmt">//--- (class="num">15) drawing colors from the class="type">color array, (class="num">16) empty value, (class="num">17) name of the graphical series displayed in DataWindow
  class="kw">virtual class="type">void        SetArrowCode(class="kw">const class="type">uchar code)                                              { class="kw">return;                                                                                                       }

◍ 指标缓冲区的属性 setter 接口

在 MT5 自定义指标里,每一个绘图缓冲区(buffer)都暴露了一组 setter 方法,用来在 OnInit 或运行时动态配置它的绑定品种、周期、线型与颜色等。上面这段代码节选自一个缓冲区封装类的声明,能直接看到 SetSymbol、SetTimeframe、SetActive 等接口把参数写进了 BUFFER_PROP_* 属性。 其中 SetArrowShift 被声明为 virtual 且函数体直接 return,说明箭头类缓冲区的偏移逻辑在基类里是空实现,子类若需要按 K 线序号 shift 摆放箭头,必须自己重写。SetDrawType、SetStyle、SetWidth 等只给了声明没给实现,意味着具体绘制类型(如 DRAW_LINE / DRAW_HISTOGRAM)要等到 cpp 里才绑定。 实盘里最容易被忽略的是 SetTimeframe:给缓冲区单独挂一个非当前图周期(例如主图 M5 但缓冲区读 M15),可以让指标做多周期共振参考,但外汇与贵金属杠杆高、滑点随机,跨周期信号只代表概率倾向,不代表方向确定。 开 MT5 新建指标时,把这段 setter 列表抄进你的 CBuffer 类头文件,先只接 SetSymbol + SetTimeframe + SetColor 三个,跑通后再补 SetStyle 和 SetWidth,能少踩一半编译坑。

MQL5 / C++
  class="kw">virtual class="type">void      SetArrowShift(class="kw">const class="type">int shift)                                              { class="kw">return;                                                                                      }
  class="type">void              SetSymbol(class="kw">const class="type">class="kw">string symbol)                                              { this.SetProperty(BUFFER_PROP_SYMBOL,symbol);                                                }
  class="type">void              SetTimeframe(class="kw">const ENUM_TIMEFRAMES timeframe)                               { this.SetProperty(BUFFER_PROP_TIMEFRAME,timeframe);                                          }
  class="type">void              SetActive(class="kw">const class="type">bool flag)                                                 { this.SetProperty(BUFFER_PROP_ACTIVE,flag);                                                  }
  class="type">void              SetDrawType(class="kw">const ENUM_DRAW_TYPE draw_type);
  class="type">void              SetDrawBegin(class="kw">const class="type">int value);
  class="type">void              SetShowData(class="kw">const class="type">bool flag);
  class="type">void              SetShift(class="kw">const class="type">int shift);
  class="type">void              SetStyle(class="kw">const ENUM_LINE_STYLE style);
  class="type">void              SetWidth(class="kw">const class="type">int width);
  class="type">void              SetColorNumbers(class="kw">const class="type">int number);
  class="type">void              SetColor(class="kw">const class="type">color colour);
  class="type">void              SetColor(class="kw">const class="type">color colour,class="kw">const class="type">uchar index);
  class="type">void              SetColors(class="kw">const class="type">color &array_colors[]);
  class="type">void              SetEmptyValue(class="kw">const class="type">class="kw">double value);
  class="kw">virtual class="type">void      SetLabel(class="kw">const class="type">class="kw">string label);
  class="type">void              SetID(class="kw">const class="type">int id)                                                        { this.SetProperty(BUFFER_PROP_ID,id);                                                        }

「把指标句柄绑进绘图缓冲区」

在 MT5 自定义指标里,绘图缓冲区(plot buffer)不是光靠数组就能上图的,得先把外部指标的句柄、类型、名称写进缓冲区属性。下面这组 setter 就是干这个的:把 iMACD 之类指标的 handle 通过 BUFFER_PROP_IND_HANDLE 塞进去,图表才认得这条线归谁管。 SetIndicatorShortName 和 SetIndicatorName 容易混:前者是 DataWindow 里显示的短名,后者是全名,短名超 11 字符会被 MT5 截断。线型用 SetLineMode 控制,比如 ENUM_INDICATOR_LINE_MODE 里的实心或虚线,改完即时影响渲染。 [CODE]void SetIndicatorHandle(const int handle) { this.SetProperty(BUFFER_PROP_IND_HANDLE,handle); } void SetIndicatorType(const ENUM_INDICATOR type) { this.SetProperty(BUFFER_PROP_IND_TYPE,type); } void SetIndicatorName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME,name); } void SetIndicatorShortName(const string name) { this.SetProperty(BUFFER_PROP_IND_NAME_SHORT,name); } void SetLineMode(const ENUM_INDICATOR_LINE_MODE mode){ this.SetProperty(BUFFER_PROP_IND_LINE_MODE,mode); }[/CODE] 逐行拆解:第 1 行定义 SetIndicatorHandle,入参为指标句柄整数,调用基类 SetProperty 写入 BUFFER_PROP_IND_HANDLE;第 2 行 SetIndicatorType 把标准指标枚举类型(如 IND_MACD)绑到 BUFFER_PROP_IND_TYPE;第 3 行 SetIndicatorName 存全名到 BUFFER_PROP_IND_NAME;第 4 行 SetIndicatorShortName 存短名到 BUFFER_PROP_IND_NAME_SHORT,DataWindow 优先读它;第 5 行 SetLineMode 接收线模式枚举并写入 BUFFER_PROP_IND_LINE_MODE,决定绘制样式。 取回属性时对称使用 GetProperty:IndexPlot 返回绘图序号(BUFFER_PROP_INDEX_PLOT),IndexBase 返回绑定数组下标(BUFFER_PROP_INDEX_BASE),IndexColor 返回颜色缓冲下标(BUFFER_PROP_INDEX_COLOR),三者都做了 int 强转。外汇与贵金属杠杆高,指标绑定错句柄会导致图形错位,实盘前务必在策略测试器用 2023 年 EURUSD 1 分钟数据跑一遍校验。

MQL5 / C++
class="type">void SetIndicatorHandle(class="kw">const class="type">int handle) { this.SetProperty(BUFFER_PROP_IND_HANDLE,handle); }
class="type">void SetIndicatorType(class="kw">const ENUM_INDICATOR type) { this.SetProperty(BUFFER_PROP_IND_TYPE,type); }
class="type">void SetIndicatorName(class="kw">const class="type">class="kw">string name) { this.SetProperty(BUFFER_PROP_IND_NAME,name); }
class="type">void SetIndicatorShortName(class="kw">const class="type">class="kw">string name) { this.SetProperty(BUFFER_PROP_IND_NAME_SHORT,name); }
class="type">void SetLineMode(class="kw">const ENUM_INDICATOR_LINE_MODE mode){ this.SetProperty(BUFFER_PROP_IND_LINE_MODE,mode); }

指标缓冲区的属性读取接口

在 MT5 自定义指标里,缓冲区(buffer)不是只存数据就完事,它的绘制行为、状态、关联周期都靠一组属性控制。下面这组方法封装在缓冲区访问类里,全部是 const 成员函数,通过 GetProperty 拿到对应枚举属性再强转返回。 IndexNextBaseBuffer 返回 BUFFER_PROP_INDEX_NEXT_BASE 转为 int,指向下一个基础缓冲序号;IndexNextPlotBuffer 同理取 BUFFER_PROP_INDEX_NEXT_PLOT,控制绘图序列的衔接。Timeframe 取 BUFFER_PROP_TIMEFRAME 转 ENUM_TIMEFRAMES,意味着单个缓冲可绑定非当前图表周期。 Status 返回 ENUM_BUFFER_STATUS,用来判断缓冲是就绪还是异常;TypeBuffer 取 BUFFER_PROP_TYPE 标明是线、柱还是箭头类。IsActive 读 BUFFER_PROP_ACTIVE 的布尔值,未激活的缓冲不会参与终端渲染。 ArrowCode 和 ArrowShift 只在箭头型缓冲有意义,分别取箭头符号码和像素偏移;DrawBegin 返回 BUFFER_PROP_DRAW_BEGIN 的 int 值,设定前面多少根 K 线不画——比如设成 10,则前 10 根不显示,避免历史重构导致的重绘错觉。外汇与贵金属杠杆交易高风险,参数验证请在策略测试器用历史数据跑过再上实盘。

MQL5 / C++
class="type">int IndexNextBaseBuffer(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_BASE); }
class="type">int IndexNextPlotBuffer(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_INDEX_NEXT_PLOT); }
ENUM_TIMEFRAMES Timeframe(class="type">void) class="kw">const { class="kw">return (ENUM_TIMEFRAMES)this.GetProperty(BUFFER_PROP_TIMEFRAME); }
ENUM_BUFFER_STATUS Status(class="type">void) class="kw">const { class="kw">return (ENUM_BUFFER_STATUS)this.GetProperty(BUFFER_PROP_STATUS); }
ENUM_BUFFER_TYPE TypeBuffer(class="type">void) class="kw">const { class="kw">return (ENUM_BUFFER_TYPE)this.GetProperty(BUFFER_PROP_TYPE); }
class="type">bool IsActive(class="type">void) class="kw">const { class="kw">return (class="type">bool)this.GetProperty(BUFFER_PROP_ACTIVE); }
class="type">uchar ArrowCode(class="type">void) class="kw">const { class="kw">return (class="type">uchar)this.GetProperty(BUFFER_PROP_ARROW_CODE); }
class="type">int ArrowShift(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_ARROW_SHIFT); }
class="type">int DrawBegin(class="type">void) class="kw">const { class="kw">return (class="type">int)this.GetProperty(BUFFER_PROP_DRAW_BEGIN); }
ENUM_DRAW_TYPE DrawType(class="type">void) class="kw">const { class="kw">return (ENUM_DRAW_TYPE)this.GetProperty(BUFFER_PROP_DRAW_TYPE); }
把跨周期取数交给小布
这些多品种多周期指标线的归属诊断,小布盯盘的 AIGC 已内置,打开对应品种页即可看到线型与源周期标注,你只需判断信号冲突。

常见问题

单缓冲区只需类型和标识符就能定位,多缓冲区必须再加线型参数,否则多条指标线无法区分隶属关系。
类型相同只能说明都是 IND_MA,identifier 用来标记是第几个实例,避免缓冲对象写到同一个源上。
可以,小布盯盘的对应品种页已内置多周期指标线溯源,省去手动在代码里核对短名的步骤。
它匹配标准指标在子窗口显示的正式名称,让缓冲对象和目标指标在界面与逻辑上对齐,减少误绑。
按顶、底、中间等主线角色设置 Indicator line,再结合类型和 identifier 就能单独抽取某条线。