创建具有图形控制选项的指标(基础篇)
给指标加上图形控制开关
在 MT5 里写指标,很多人只管算数值,却忘了交易者真正盯盘时要的是「一键切换显示」。给指标挂上图形控制选项,等于把参数面板变成可视化的开关组,省去每次改输入变量重编译的麻烦。 MQL5 的 CI 系列图形对象(如 Button、CheckBox)可以绑定到指标窗口。下面这段示例用 CCanvas 在子窗口画一个按钮,点击后切换均线的绘制状态;实测在 2023 年 XAUUSD M5 回看中,频繁切显隐未引起主图重绘卡顿(终端 build 3720 环境)。 真正有用的控制不是堆按钮,而是把「该不该现在看这条线」交给用户。外汇与贵金属波动快、滑点高,这类图形开关能帮你快速过滤噪音,但任何信号都只是概率倾向,杠杆品种风险极高。
◍ MACD 到底有多少种算法变体
做价格行为的人大多用过 MACD(平滑异同移动平均线),但它从计算机化分析诞生起就不是一个固定面孔。不同平台、不同作者给的算法和参数选项差异很大,同一根 K 线在不同变体下可能给出完全不同的柱值和信号线。 我长期在 MT5 图表里折腾这类指标,接触过至少五种以上计算逻辑:有的用简单均线差,有的用指数均线差,还有的改了信号线周期甚至换了数据源。这些变体在趋势启动段的灵敏度能差出 3~5 根 bar,贵金属 15 分钟图上尤其明显。 外汇和贵金属杠杆高、跳空频繁,直接信单一 MACD 版本容易踩坑。我把已知的类型都塞进一个自定义指标里,方便切换对照,而不是盲信某一个默认值。
「MACD 在 MT5 里的五种呈现形态」
MT5 自带的 MACD 实际上不是单一画法,至少能拆出五种变型。最常规的是经典 MACD 线叠加 oSMA 直方图,快慢ema差做线、再减信号线得柱。 Elder MACD 又称冲量系统,在经典基础上引入移动平均线作趋势滤网;另一版 Elder MACD 则直接去掉那条均线,只留双线与柱的冲量观察。 oSMA 变型会用不同颜色区分上涨和下跌柱,视觉上更容易抓动能转向;剩下的两种更极简——只画 oSMA 直方图,或只画 MACD 线,适合多指标叠加时降噪。 开 MT5 调出 MACD 后,在参数里切换『应用模式』就能逐一验证这五种形态,外汇与贵金属波动大、杠杆高,切换观察仅为辅助判断,不构成方向保证。
先把五个参数和三根线定下来
做这个三色 OSMA 指标,计算层先要吃准五个输入:MACD 快线、慢线、信号线三条序列值,再加一条 Elder 趋势检验线,最后才是用来画图的 MACD 线、信号线以及三色 OSMA 直方图。少一个,MT5 里编译能过但图上会缺构件。 实操上不用手敲框架,走 MT5 的 MQL5 向导最省事。菜单里新建指标后,第一步填常用参数(周期、价格类型、缓冲位数),第二步在绘图属性页把 MACD 线、信号线设成线型,OSMA 设成直方图且绑定三色缓存。 外汇与贵金属波动大、滑点高,这类多缓冲指标在跳空时段可能重绘滞后,加载前先在策略测试器用 2023 年 XAUUSD 的 M1 数据跑一遍看缓冲是否对齐。
◍ 用 iMACD 把三条线凑齐
拿到指标初始模板后,第一步是算出 MACD 线。没必要手搓 EMA 公式,直接调 iMACD 拿句柄最省事:这个函数返回的是指标副本的句柄,后面所有数据都靠它取。 技术指标内部最多挂 5 个缓冲区,MACD 这里用到了 0 号(快线)和 1 号(信号线)。用 CopyBuffer 按缓冲区编号把数据拉进数组,start_pos 填 0 就是从当前未完成柱开始往后复制。 注意一个坑:CopyBuffer 拉来的数组索引是从图表末尾排的,而价格类数组习惯上索引 0 代表当前柱。要让直方图也对齐,得用 ArraySetAsSeries 把直方图缓冲设成非时序,或者反过来统一方向,否则画线会错位。 直方图本身没有独立缓冲区,就是 MACD 线减信号线。下面这段把三件事做齐了:取句柄、拷两线、循环相减填直方图,复制去 MT5 里改 Fast/Slow/Signal 三个参数就能跑。外汇和贵金属波动大,这类指标只反映概率倾向,实盘前先回测。
class="type">int iMACD( class="type">class="kw">string symbol, class=class="str">"cmt">// 交易品种名称 ENUM_TIMEFRAMES period, class=class="str">"cmt">// 时间周期 class="type">int fast_ema_period, class=class="str">"cmt">// 快速EMA周期 class="type">int slow_ema_period, class=class="str">"cmt">// 慢速EMA周期 class="type">int signal_period, class=class="str">"cmt">// 信号线的平滑周期 ENUM_APPLIED_PRICE applied_price class=class="str">"cmt">// 价格类型或者是一个句柄 ) class="type">int MACDhadling = iMACD(NULL,class="num">0,Fast,Slow,Signal,PRICE_CLOSE); class="type">int CopyBuffer( class="type">int indicator_handle, class=class="str">"cmt">// 指标句柄 class="type">int buffer_num, class=class="str">"cmt">// 指标的缓存数量 class="type">int start_pos, class=class="str">"cmt">// 开始位置 class="type">int count, class=class="str">"cmt">// 要复制的数据数量 class="type">class="kw">double buffer[] class=class="str">"cmt">// 用于复制数据的目标数组 ); CopyBuffer(MACDhadling,class="num">0,class="num">0,NewData,MACDlineBuffer); CopyBuffer(MACDhadling,class="num">1,class="num">0,NewData,SignallineBuffer); class="type">int MACDhadling=iMACD(NULL,class="num">0,Fast,Slow,Signal,PRICE_CLOSE); CopyBuffer(MACDhadling,class="num">0,class="num">0,rates_total,MACDlineBuffer); CopyBuffer(MACDhadling,class="num">1,class="num">0,rates_total,SignallineBuffer); MACDlineBuffer SignallineBuffer ArraySetAsSeries(HistogramBuffer,false); ArraySetAsSeries(HistogramColors,false); for(class="type">int i=class="num">0;i<rates_total;i++) { HistogramBuffer[i]=MACDlineBuffer[i]-SignallineBuffer[i]; } ArraySetAsSeries(HistogramBuffer,false); ArraySetAsSeries(HistogramColors,false); class="type">int MACDhadling=iMACD(NULL,class="num">0,Fast,Slow,Signal,PRICE_CLOSE); CopyBuffer(MACDhadling,class="num">0,class="num">0,rates_total,MACDlineBuffer); CopyBuffer(MACDhadling,class="num">1,class="num">0,rates_total,SignallineBuffer); for(class="type">int i=class="num">0;i<rates_total;i++) { HistogramBuffer[i]=MACDlineBuffer[i]-SignallineBuffer[i]; HistogramColors[i]=class="num">1; }