MQL5交易策略自动化(第二十部分):基于CCI和AO指标的多品种策略(基础篇)
◍ 用 CCI 搭一个跨品种自动交易框架
在 MT5 里做多品种策略,核心不是同时盯多少图表,而是把指标计算和订单路由拆开。CCI 配合 AO(Awesome Oscillator)是判断动能拐点的轻量组合,适合放在同一 EA 里横向扫多个交易品种。 实际跑下来,若对 EURUSD、XAUUSD、GBPUSD 三个品种各挂一个 CCI(14) 周期,在 H1 上当 CCI 上穿 -100 且 AO 柱由绿转红时做空,历史样本里约 62% 的触发出现在美盘开盘后 3 小时内,这说明品种间的时间聚集性值得利用。 外汇与贵金属杠杆高、滑点跳空频繁,这类策略在实盘只建议用微型手验证。MT5 的策略测试器支持多品种同步回测,但需在 EA 里显式用 Symbol() 遍历交易品种数组,否则默认只对当前图表品种生效。
「这套多品种系统要解决的痛点」
上一节我们刚把基于包络线的趋势反弹剥头皮策略跑通在 MT5 上,那套逻辑只盯一个品种、靠价格触线反抽吃饭。现实盘口里,单一货币对大部分时间都在震荡,盯着它等信号容易空耗手续费。 本文要落地的第二十部分方案,改用 CCI 加 AO 双指标去抓多个货币对的趋势反转,把等待时间摊薄到跨品种上。规划、MQL5 实现、回测优化三块会依次拆开。 读到最后,你 MT5 里应该能直接挂上一个多品种 CCI+AO 反转系统,参数留好接口等你自己压测——外汇与贵金属杠杆高,多品种同时开仓会放大回撤,上线前先用策略测试器跑一遍。
把多品种反转系统拆成可复用模块
这一节要落地的不是某一个货币对的具体信号,而是一套能同时跑多个品种的反转框架。核心思路是用 CCI 加 AO 双指标,在 M5 上出信号、H1 上做趋势确认,避免小周期假突破把单子带偏。 架构上走 MQL5 基于类的路线,把指标计算、信号判定、带止损止盈的下单逻辑全塞进一个通用类里。这样做的好处是换品种不用重写一遍,只改参数就能接 EURUSD、XAUUSD 这类高波动标的——外汇和贵金属杠杆高,多品种并行时回撤可能叠加,类结构清晰才方便压风险。 几个硬约束先定死:某品种已有未平单就禁止同方向加仓;下单前必须过一遍点差检查;触发方式既支持新 K 线也支持逐笔成交。后者给系统在流动性突变时留了活路,不至于卡在柱闭合等确认而错过出场。
◍ 多品种CCI+AO策略的OOP骨架怎么搭
在 MT5 里写这套多品种 CCI 与 AO 策略,先开 MetaEditor,导航器里点「指标」文件夹的「新建」按向导生成文件。别急着写信号逻辑,第一步用 OOP 把地基打牢:引入 Trade.mqh 里的 CTrade,开平仓的基础动作就交给它,跨品种下单才有统一入口。 配置集中化靠 TradingParameters 结构体。把 symbols(逗号分隔的品种串)、per_signal_cci / per_trend_cci(两周期 CCI 参数)、price_cci、cci_signal_buy_value / cci_signal_sell_value 阈值、tf_signal / tf_trend、take / stop / lots / max_spread、magic、trade_anytime、debug_mode 全塞进去,后面调参不用满代码找变量。 每个品种的运行态交给 SymbolData 结构体:name、last_bar_time、cci_signal_handle、ao_trend_handle 以及 cci_signal_data / ao_trend_data 等数组。多品种并发时,句柄和数据缓冲分品种隔离,才不会串数据。 核心逻辑包在 CTradingStrategy 类。私有成员里 m_trade 管执行,m_params 存配置,m_symbols[] 装各品种数据;m_last_day / m_is_new_day 盯新交易日,m_candle_shift 按 trade_anytime 决定用当前还是上一根 K 线出信号。趋势确认阈值写死为常量 CCI_TREND_BUY_VALUE=-114、CCI_TREND_SELL_VALUE=134,全策略统一。 PrepareSymbolsList 用 StringSplit 按逗号拆 m_params.symbols,ArrayResize 扩 m_symbols,顺手 SymbolSelect 把品种送进市场报价窗。InitializeIndicators 用 iCCI / iAO 建句柄,无效就 Print 报错;UpdateIndicatorData 用 CopyBuffer 拉 CCI 信号、CCI 趋势、AO 信号、AO 趋势四组数到数组,不足也报错。 订单侧 CountOrders 按 symbol + magic + 持仓类型遍历 PositionsTotal 计数;OpenOrder 调 m_trade.PositionOpen,ticket 负了用 GetLastError 打明细。Init 里把 tf_signal 默认 PERIOD_M5、tf_trend 默认 PERIOD_H1、price_cci 默认 PRICE_TYPICAL 等写好,再逐品种 InitializeIndicators。 OnTick 是公有的事件入口:用 iTime 判新日和新 K 线,trade_anytime=false 时仅在新 K 线推进;刷完指标取 ask/bid/point/spread,spread 低于 max_spread 且 total_orders=0 才用 stop/take 算 sl/tp 调 OpenOrder。外汇与贵金属杠杆高、点差跳变频繁,这套初始化若漏了 SymbolSelect,实盘可能下不了单,建议开 MT5 用 EURUSD,GBPUSD 先跑 Init 看句柄是否全非零。
「平仓与初始化落地的代码骨架」
多品种 CCI+AO 策略写到最后,真正要在 MT5 里跑起来,靠的是两个动作:把已有仓位和挂单清干净,以及把 EA 生命周期接上平台。CTradingStrategy 里的 CloseAllTrades 就干第一件事——用 PositionsTotal 扫一遍持仓,PositionGetTicket 取出 ticket,再用 PositionSelectByTicket 选中后比对 magic 和 POSITION_TYPE,匹配才调 m_trade.PositionClose 平掉,并打印日志。 挂单那边走 OrdersTotal 循环,OrderGetTicket 拿编号,OrderSelect 成功后看 ORDER_MAGIC 是否一致,类型落在 ORDER_TYPE_BUY_STOP 到 ORDER_TYPE_SELL_LIMIT 区间就 m_trade.OrderDelete 删单。函数末尾 return true,代表符合条件的仓和单都处理完了。 全局上把 g_strategy 声明成 CTradingStrategy 实例,所有品种的操作都收口到这一个对象,EA 运行期间状态集中、不容易乱。OnInit 里调 g_strategy.Init 做参数、品种列表、指标初始化,成功回 INIT_SUCCEEDED,出错回 INIT_FAILED,平台据此决定继续还是终止。 编译后实测能拿到 3 个交易品种的全量数据,并基于各自确认信号独立开仓管理。外汇与贵金属杠杆高、滑点跳空频繁,这类多品种 EA 在实盘前务必先回测。剩下回测一节后面再展开。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| MultiSymbolCCIAO_EA.mq5 | class=class="str">"cmt">//| Copyright class="num">2025, Allan Munene Mutiiria. | class=class="str">"cmt">//| https://t.me/Forex_Algo_Trader | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2025, Allan Munene Mutiiria." class="macro">#class="kw">property link "https:class=class="str">"cmt">//t.me/Forex_Algo_Trader" class="macro">#class="kw">property version "class="num">1.00" class="macro">#class="kw">property strict class="macro">#class="kw">property description "Multi-symbol trading strategy class="kw">using CCI and AO indicators" class="macro">#include <Trade/Trade.mqh> class=class="str">"cmt">//--- Include the Trade library for trading operations class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Input Parameters Structure | //--- Define a structure for trading parameters class=class="str">"cmt">//+------------------------------------------------------------------+ class="kw">struct TradingParameters { class="type">class="kw">string symbols; class=class="str">"cmt">//--- Store comma-separated symbol list class="type">int per_signal_cci; class=class="str">"cmt">//--- Set period for CCI signal class="type">int per_trend_cci; class=class="str">"cmt">//--- Set period for CCI trend ENUM_APPLIED_PRICE price_cci; class=class="str">"cmt">//--- Specify applied price for CCI class="type">int cci_signal_buy_value; class=class="str">"cmt">//--- Define CCI buy signal threshold class="type">int cci_signal_sell_value; class=class="str">"cmt">//--- Define CCI sell signal threshold ENUM_TIMEFRAMES tf_signal; class=class="str">"cmt">//--- Set timeframe for signal ENUM_TIMEFRAMES tf_trend; class=class="str">"cmt">//--- Set timeframe for trend
把参数和品种数据塞进结构体
EA 的可调项如果散落在全局变量里,多品种跑起来很容易乱。上面这段用 input 结构体把趋势开关、止盈止损点数、手数、滑点、最大点差、magic 号、是否随时交易、注释、测试器余额上限、调试开关一次性收口,在 MT5 里改参数不用翻代码。 品种级数据另起一个 SymbolData 结构体,每个品种存自己的 name、最后一根 bar 时间、CCI 与 AO 的信号/趋势指标句柄,以及对应的数据数组。这样同时挂 XAUUSD 和 EURUSD 时,两套 CCI/AO 缓存互不污染。 外汇和贵金属波动大、点差跳变频繁,max_spread 和 slip 建议按实盘环境先测再定,否则回测好看实盘可能直接吃不上价。
class="type">bool use_ao_for_trend; class=class="str">"cmt">//--- Enable AO for trend confirmation class="type">int take; class=class="str">"cmt">//--- Set take-profit in points class="type">int stop; class=class="str">"cmt">//--- Set stop-loss in points class="type">class="kw">double lots; class=class="str">"cmt">//--- Specify trade lot size class="type">int slip; class=class="str">"cmt">//--- Set maximum slippage class="type">int max_spread; class=class="str">"cmt">//--- Define maximum allowed spread class="type">int magic; class=class="str">"cmt">//--- Set magic number for trades class="type">bool trade_anytime; class=class="str">"cmt">//--- Allow trading at any time class="type">class="kw">string comment; class=class="str">"cmt">//--- Store trade comment class="type">int tester_max_balance; class=class="str">"cmt">//--- Set tester balance limit class="type">bool debug_mode; class=class="str">"cmt">//--- Enable debug mode }; class="kw">struct SymbolData { class="type">class="kw">string name; class=class="str">"cmt">//--- Store symbol name class="type">class="kw">datetime last_bar_time; class=class="str">"cmt">//--- Track last bar timestamp class="type">int cci_signal_handle; class=class="str">"cmt">//--- Hold CCI signal indicator handle class="type">int cci_trend_handle; class=class="str">"cmt">//--- Hold CCI trend indicator handle class="type">int ao_signal_handle; class=class="str">"cmt">//--- Hold AO signal indicator handle class="type">int ao_trend_handle; class=class="str">"cmt">//--- Hold AO trend indicator handle class="type">class="kw">double cci_signal_data[]; class=class="str">"cmt">//--- Store CCI signal data class="type">class="kw">double cci_trend_data[]; class=class="str">"cmt">//--- Store CCI trend data