面向初学者的创建具有多个指标缓冲区的指标(基础篇)
📘

面向初学者的创建具有多个指标缓冲区的指标(基础篇)

第 1/2 篇

「给指标开多个缓冲区并不难」

在 MT5 里写一个自定义指标,最容易被卡住的地方不是画图逻辑,而是搞不清『指标缓冲区(indicator buffer)』到底怎么分配。简单说,一个缓冲区就是一条独立的数据线,你往里写值,终端才认得要画什么。 很多新手只声明一个缓冲区,结果想同时显示快慢两条均线或一个主图线加一个色带就崩了。正确做法是:在 OnInit 里用 SetIndexBuffer 把数组和缓冲区编号绑定,编号从 0 开始连续排,漏一个号终端就可能报『数组越界』或画不出线。 以双缓冲区指标为例,核心声明长这样:

MQL5 / C++
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">2
class="macro">#class="kw">property indicator_plots class="num">2
class=class="str">"cmt">//---  plot Fast
class="macro">#class="kw">property indicator_label1  "Fast"
class="macro">#class="kw">property indicator_type1   DRAW_LINE
class="macro">#class="kw">property indicator_color1  clrRed
class=class="str">"cmt">//---  plot Slow
class="macro">#class="kw">property indicator_label2  "Slow"
class="macro">#class="kw">property indicator_type2   DRAW_LINE
class="macro">#class="kw">property indicator_color2  clrBlue
class=class="str">"cmt">//--- indicator buffers
class="type">class="kw">double FastBuffer[];
class="type">class="kw">double SlowBuffer[];
上面这段里,indicator_buffers 2 告诉终端我要两块缓冲区,indicator_plots 2 表示要画两条线;FastBuffer 和 SlowBuffer 是两个 double 数组,后续在 OnInit 中分别绑定到 0 号和 1 号缓冲区。外汇与贵金属市场波动剧烈、杠杆高风险大,多缓冲区指标只是帮你把信号分层,不代表任何方向判断。 实际验证时,把上面属性块贴进 MQ5 文件头,再在 OnInit 补两句 SetIndexBuffer(0, FastBuffer); SetIndexBuffer(1, SlowBuffer);,编译后拖到 EURUSD 的 M15 图表,终端『导航器—指标』里就能看到红蓝双线占位,证明缓冲区已生效。

MQL5 / C++
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">2
class="macro">#class="kw">property indicator_plots class="num">2
class=class="str">"cmt">//---  plot Fast
class="macro">#class="kw">property indicator_label1  "Fast"
class="macro">#class="kw">property indicator_type1   DRAW_LINE
class="macro">#class="kw">property indicator_color1  clrRed
class=class="str">"cmt">//---  plot Slow
class="macro">#class="kw">property indicator_label2  "Slow"
class="macro">#class="kw">property indicator_type2   DRAW_LINE
class="macro">#class="kw">property indicator_color2  clrBlue
class=class="str">"cmt">//--- indicator buffers
class="type">class="kw">double FastBuffer[];
class="type">class="kw">double SlowBuffer[];

从单缓冲区到更复杂的指标结构

之前两篇分别讲了只带一个指标缓冲区的自定义指标写法,那种结构在入门阶段够用,但真实盘面里价格行为很少能压缩成一条线。 MQL5 本身对缓冲区数量没有硬性上限,限制基本只来自你机器剩下的 RAM。也就是说,想叠加多层滤波或同时画多个状态,技术上完全可行,只是要注意内存占用随缓冲区数量线性增长。 对交易者来说,下一步值得在 MT5 里试着给指标挂两个以上的缓冲区,验证一下多线状态下刷新是否还跟手,而不是停留在单线思维。

◍ 把 Aroon 拆成双缓冲区的实操改法

Aroon 的核心公式分两头:BULLS = (1 - (bar - SHIFT(MAX(HIGH(), AroonPeriod)))/AroonPeriod) * 100,BEARS = (1 - (bar - SHIFT(MIN(LOW(), AroonPeriod)))/AroonPeriod) * 100。SHIFT() 取柱索引,MAX()/MIN() 在 AroonPeriod 周期内搜最高/最低价,输出范围是 0~100,所以必须丢进独立窗口而不是主图叠加。 从 SMA_1.mq5 改最省事:MetaEditor 里另存为 Aroon.mq5,前 11 行只换指标名;第 12 行加 #property indicator_separate_window 切到副图;紧接着把 indicator_buffers 和 indicator_plots 都改成 2,再把原绘图标签复制一份、索引 1 改 2、改名 BullsAroon / BearsAroon。 横线定位用三档:30、50、70,直接在代码里加 indicator_level1/2/3 即可,不需要自己画对象。 OnInit() 里第零缓冲改完,把整段剪贴再贴一次,缓冲区编号 0 改 1、数组名和 label 同步换掉,简称也微调。绘制精度上,值域固定 0~100,用 0 位小数就够了,避免副图上密密麻麻的小数。 OnCalculate() 得换第二种头,因为要拿 high[] 和 low[];原第一种形式没有这两数组。MQL5 没有内建“按递减索引搜极值位置”的函数,偷懒办法是从 MT5 自带的 ZigZag.mq5(MQL5\Indicators\Examples)里抠出极值定位函数,贴到全局层。 另一个思路是用 ArrayMaximum()/ArrayMinimum(),但它们按递增搜,得先用 ArraySetAsSeries() 把缓冲区和价格数组倒序,再把主循环方向反过来、改掉首变量算法。下面这段头文件改动就是副图+双缓冲的落地起点,复制进 MT5 编译就能看到灰绿/红双线跑起来。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                  Aroon.mq5 |
class=class="str">"cmt">//|           Copyright class="num">2010, MetaQuotes Software Corp. |
class=class="str">"cmt">//|                     [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//---- 版权
class="macro">#class="kw">property copyright "class="num">2010, MetaQuotes Software Corp."
class=class="str">"cmt">//---- 作者网站的链接
class="macro">#class="kw">property link      "[MQL5官方文档]
class=class="str">"cmt">//----版本号
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//---- 在独立窗口中绘制指标
class="macro">#class="kw">property indicator_separate_window
class=class="str">"cmt">//---- 使用 class="num">2 个缓存
class="macro">#class="kw">property indicator_buffers class="num">2
class=class="str">"cmt">//---- class="num">2 种图形用于绘制
class="macro">#class="kw">property indicator_plots   class="num">2
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//| 牛市力量指标参数        |
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//----绘制类型 = 线
class="macro">#class="kw">property indicator_type1   DRAW_LINE
class=class="str">"cmt">//---- 绘制颜色 = 灰色
class="macro">#class="kw">property indicator_color1  Lime
class=class="str">"cmt">//----线形 = 实线
class="macro">#class="kw">property indicator_style1  STYLE_SOLID
class=class="str">"cmt">//---- 线宽 = class="num">1
class="macro">#class="kw">property indicator_width1  class="num">1
class=class="str">"cmt">//---- BullsAroon 指标的标签
class="macro">#class="kw">property indicator_label1  "BullsAroon"
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//|  熊市力量指标参数       |
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//----绘制类型 = 线
class="macro">#class="kw">property indicator_type2   DRAW_LINE
class=class="str">"cmt">//---- 绘制颜色 = 红色
class="macro">#class="kw">property indicator_color2  Red
class=class="str">"cmt">//----线形 = 实线
class="macro">#class="kw">property indicator_style2  STYLE_SOLID
class=class="str">"cmt">//---- 线宽 = class="num">1
class="macro">#class="kw">property indicator_width2  class="num">1
class=class="str">"cmt">//----BearsAroon 指标的标签
class="macro">#class="kw">property indicator_label2  "BearsAroon"
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//| 横向水平                           |
class=class="str">"cmt">//+----------------------------------------------+
class="macro">#class="kw">property indicator_level1 class="num">70.0
class="macro">#class="kw">property indicator_level2 class="num">50.0
class="macro">#class="kw">property indicator_level3 class="num">30.0

「把 Aroon 双线塞进自定义指标缓存」

要在 MT5 里手搓一个 Aroon 双线指标,核心是先声明两个动态数组 BullsAroonBuffer 和 BearsAroonBuffer,再用 SetIndexBuffer 把它们分别绑到索引 0 和 1 上,否则图表只会画一根线甚至报错。 输入参数给了 AroonPeriod=9 和 AroonShift=0,意味着指标默认回看 9 根 K 线、不做水平偏移;PlotIndexSetInteger 里的 PLOT_DRAW_BEGIN 也设成 AroonPeriod,所以前 8 根柱形不会出值,这是避免样本不足导致除零或异常线的硬约束。 OnCalculate 开头那句 if(rates_total < AroonPeriod-1) return(0) 直接把总柱数小于 8 的情况挡掉,实盘加载到分钟图早期或历史过短的品种时会立刻生效。外汇与贵金属波动剧烈,这类周期类指标仅作趋势强度参考,信号失效概率不低,须配合仓位控制。 下面这段是初始化与计算骨架的原文,逐行拆解看注释即可照抄验证。

MQL5 / C++
class="macro">#class="kw">property indicator_levelcolor Gray
class="macro">#class="kw">property indicator_levelstyle STYLE_DASHDOTDOT
class=class="str">"cmt">//+----------------------------------------------+
class=class="str">"cmt">//| 指标输入参数                   |
class=class="str">"cmt">//+----------------------------------------------+
input class="type">int AroonPeriod = class="num">9; class=class="str">"cmt">// 周期 
input class="type">int AroonShift = class="num">0;  class=class="str">"cmt">// 指标的水平柱形偏移 
class=class="str">"cmt">//--- 声明用于指标缓存的动态数组
class="type">class="kw">double BullsAroonBuffer[];
class="type">class="kw">double BearsAroonBuffer[];
class=class="str">"cmt">//--- 设置动态数组 BullsAroonBuffer 作为指标缓存
SetIndexBuffer(class="num">0, BullsAroonBuffer, INDICATOR_DATA);
class=class="str">"cmt">//--- 指标 class="num">1(AroonShift) 的水平偏移
PlotIndexSetInteger(class="num">0, PLOT_SHIFT, AroonShift);
class=class="str">"cmt">//---绘制指标 class="num">1(AroonPeriod) 的开始
PlotIndexSetInteger(class="num">0, PLOT_DRAW_BEGIN, AroonPeriod);
class=class="str">"cmt">//--- 数据窗口中显示的标签
PlotIndexSetString(class="num">0, PLOT_LABEL, "BearsAroon");
class=class="str">"cmt">//--- 设置动态数组 BullsAroonBuffer 作为指标缓存
SetIndexBuffer(class="num">1, BearsAroonBuffer, INDICATOR_DATA);
class=class="str">"cmt">//--- 指标 class="num">2(AroonShift) 的水平偏移
PlotIndexSetInteger(class="num">1, PLOT_SHIFT, AroonShift);
class=class="str">"cmt">//--- 绘制指标 class="num">2(AroonPeriod) 的开始
PlotIndexSetInteger(class="num">1, PLOT_DRAW_BEGIN, AroonPeriod);
class=class="str">"cmt">//--- 数据窗口中显示的标签
PlotIndexSetString(class="num">1, PLOT_LABEL, "BullsAroon");  
class=class="str">"cmt">//--- 初始化用于指标简称的变量
class="type">class="kw">string shortname;
StringConcatenate(shortname, "Aroon(", AroonPeriod, ", ", AroonShift, ")");
class=class="str">"cmt">//---确定指标值的绘制精度 
IndicatorSetInteger(INDICATOR_DIGITS, class="num">0);
class="type">int OnCalculate(
                const class="type">int rates_total,      class=class="str">"cmt">// 当前价格变动时的所有柱形
                const class="type">int prev_calculated,  class=class="str">"cmt">// 先前价格变动时的所有柱形
                const class="type">class="kw">datetime& time[],
                const class="type">class="kw">double& open[],      
                const class="type">class="kw">double& high[],      class=class="str">"cmt">// 用于指标计算的最高价格数组
                const class="type">class="kw">double& low[],       class=class="str">"cmt">//用于指标计算的最低价格数组
                const class="type">class="kw">double& close[],
                const class="type">long& tick_volume[],
                const class="type">long& volume[],
                const class="type">int& spread[]
                )
class=class="str">"cmt">//--- 检查柱形的数量
if (rates_total < AroonPeriod - class="num">1) class="kw">return(class="num">0);
 
class=class="str">"cmt">//--- 声明本地变量 
class="type">int first, bar;
class="type">class="kw">double BULLS, BEARS;
class=class="str">"cmt">//--- 主循环的开始位索引

常见问题

单缓冲区只能存一条线,多缓冲区才能同时输出上穿下穿、强弱等多条计算结果,方便在副图直接看关系。
在 OnInit 里用 SetIndexBuffer 多申请一个数组,分别绑定 AroonUp 和 AroonDown,再在 OnCalculate 里分开赋值即可。
可以,小布能读取你贴的指标代码结构,指出缓冲区绑定或越界问题,并给改法建议。
多半是第二个缓冲区没设绘图样式或颜色,补上 #property indicator_color2 并在代码里赋值就行。
用不同颜色和线宽绑定两个缓冲区,并在指标属性里写清名称,图表左侧图例会自动标出。