一张图表上多个指标(第 04 部分):晋升为一款智能交易系统(基础篇)
◍ 把多指标图表升级成 EA 的起点
在 MT5 里,把一张叠了多个指标的图表直接转成智能交易系统(EA),是很多手动交易员跨进自动化的第一步。原文作者 Daniel Jose 在 2022 年 5 月 17 日发布的这一思路,截至发布页统计获得了 2351 次查看与 5 条互动,说明这类「图表即策略」的改造需求并不小众。 做法上,核心是把你已经在图表上肉眼确认过的指标组合(例如均线 + MACD + 波动率带)用 MQL5 的 iCustom 或内置 iMA / iMACD 接口重写进 OnTick 逻辑,让 EA 代替你盯盘并下单。外汇与贵金属品种波动受杠杆与消息面影响大,这类自动化改造只是降低人工遗漏,不消除爆仓风险,回测与模拟盘验证必须做在前面。 一个容易踩的坑:图表上多个指标的周期如果混用(比如 M5 均线配 H1 MACD),EA 里要用不同句柄分别拉数据,别图省事全用 CurrentPeriod,否则信号会错位。打开 MT5 的 MetaEditor,新建 EA 模板后先把指标句柄建出来,是验证这条路径最快的办法。
EA 里挂子窗口为什么比指标难
在自定义指标里加多个子窗口只是改改属性、拖拖绘图缓冲区的事,MQL5 给了现成接口,照着做就行。但把同样的多窗口逻辑搬进 EA,情况立刻变复杂——EA 没有指标那种内建的子窗口绘制通道,你得自己用代码去驱动终端创建并绑定窗口。 难点不在代码量,而在你得真正理解 MQL5 的图表对象与指标句柄机制。会写几行不代表能跑通:很多交易者复制指标代码进 EA 直接编译报错,就是因为 EA 上下文里 ChartIndicatorAdd、iCustom 的调用时序和指标自身生命周期完全不同。 好消息是,EA 里设置子窗口并不需要你写几百行底层绘图,核心就是搞清 MQL5 怎么通过指标句柄把计算输出推到独立窗口。外汇与贵金属杠杆高、滑点大,任何多窗口 EA 在实盘前都应在 MT5 策略测试器里先验证窗口创建是否稳定。
「EA 里塞指标为何总糊主图」
自定义指标类写好了,功能也齐,但直接丢进 EA 用会出岔子:EA 环境没有子窗口机制,类里的绘图逻辑无处落地。有人想走捷径,用 iCustom 调已编译的指标,代码能加载,可图表会被指标模板直接盖在主窗口上,根本没法看。 真问题不是「怎么调指标」,而是「EA 怎么拥有子窗口」。为后续启动的指标单独造子窗口没意义,更顺的路子是先把指标能力揉进 EA,再自己克服子窗口限制。 落地拆成四件实事:造一个不污染主图的通用指标以支持 iCustom;把该指标含进 EA 转成完整交易系统;写个通用对象类负责生成子窗口;用绑定 window 的 C_TemplateChart 管理子窗内容且不动原指标代码。听起来多,逐个点掉就通了。 下面这段 OnInit 片段演示了坑位:iCustom 指向子窗口指标编译件,若句柄无效直接 INIT_FAILED;ChartIndicatorAdd 的 subwindow 参数写 0 表示主图,真要子窗得换对应编号,否则依旧糊主图。外汇与贵金属杠杆高,EA 加载逻辑错一处就可能误绘,上线前务必在 MT5 策略测试器单步核对句柄。
class="macro">#class="kw">property copyright "Daniel Jose" class=class="str">"cmt">//+------------------------------------------------------------------+ input class="type">class="kw">string user01 = ""; class=class="str">"cmt">//Used indicators input class="type">class="kw">string user02 = ""; class=class="str">"cmt">//Assets to follow class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class="type">int m_handleSub; class=class="str">"cmt">//... Expert Advisor code ... if ((m_handleSub = iCustom(NULL, class="num">0, "Chart In SubWindows\\Chart In SubWindow.ex5", user01, user02)) == INVALID_HANDLE) class="kw">return INIT_FAILED; if (!ChartIndicatorAdd(ChartID(), class="num">0, m_handleSub)) class="kw">return INIT_FAILED; class=class="str">"cmt">//... Expert Advisor code ... ChartRedraw(); class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//...The rest of the Expert Advisor code ...
◍ 把空壳指标塞进 RESOURCE 目录
要支撑子窗口里挂指标,最干净的做法是写一个啥都不画、只完成初始化的自定义指标。下面这段 SubSupport.mq5 就是全部内容,没有多余逻辑。 代码里 indicator_plots 设为 0,意味着它不在图表上输出任何线或图形;OnInit 直接返回 INIT_SUCCEEDED,OnCalculate 原样吐回 rates_total。它存在的意义不是计算,而是被 EA 以资源方式引用。 保存时别丢进普通 Indicators 文件夹。它的落点应该是智能交易系统的 RESOURCE 目录,文件结构因此和常规指标不同。这么摆位有实际用处,但这一节先不展开,留到后面任务再说。 你打开 MT5 的 MQL5/Experts/RESOURCE 路径,把这份文件丢进去,就能在 EA 里通过资源机制调用它,验证子窗口指标支撑是否生效。外汇与贵金属品种波动剧烈,这类底层挂载出错可能让 EA 静默失效,上真仓前先在策略测试器跑一遍。
class="macro">#class="kw">property copyright "Daniel Jose" class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property description "This file only enables support of indicators in SubWin." class="macro">#class="kw">property indicator_chart_window class="macro">#class="kw">property indicator_plots class="num">0 class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class="kw">return INIT_SUCCEEDED; } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnCalculate(class="kw">const class="type">int rates_total, class="kw">const class="type">int prev_calculated, class="kw">const class="type">int begin, class="kw">const class="type">class="kw">double &price[]) { class="kw">return rates_total; } class=class="str">"cmt">//+------------------------------------------------------------------+