MQL5 交易策略自动化(第十部分):开发趋势盘整动量策略(基础篇)
◍ 用 MQL5 把趋势盘整动量策略跑起来
MQL5 做策略自动化,第十部分聚焦的是趋势盘整动量策略:在 MT5 里把「趋势方向 + 盘整过滤 + 动量确认」三层逻辑压进一个 EA,而不是单看一根均线交叉。 原文发布于 2025 年 11 月 5 日,截至统计显示该文阅读量 1 356,作者 Allan Munene Mutiiria,说明这类复合条件策略在实盘社群里仍有稳定关注度。 打开 MT5 的 MetaEditor,新建 EA 后先别写下单逻辑,先把趋势段和盘整段的判定写成独立函数,后面接动量阈值,回测时才好单独调参。外汇与贵金属杠杆品种波动剧烈,任何策略都存在滑点与连亏风险,先用策略测试器跑历史再上模拟。
从亚洲突破切到趋势动量
上一部分我们用 MQL5 写好了亚洲突破 EA,靠关键时段水平和动态风控跑自动化。这一节起思路换轨:不再只赌突破,而是用双均线交叉搭趋势骨架,再叠 RSI 和 CCI 做动量过滤,把盘整里的假信号刮掉。 具体落地会拆成三块走:策略逻辑怎么定、MQL5 里怎么写、回测和优化怎么调。读完你能直接在 MT5 里新建一个 EA 工程,把均线周期和 RSI 阈值先填上跑一版。 外汇和贵金属杠杆高、滑点跳空频繁,这套组合信号也只是提高概率,不等于每次都对。建议先开策略测试器用 2023 年 XAUUSD 日线回测,看双均线+CCI 在震荡段的过滤效果再上实盘。
「均线交叉加三重动量过滤的落地参数」
这套趋势盘整动量策略的骨架是双均线交叉:11周期平滑均线盯中位价作快线,25周期平滑均线同样盯中位价作慢线。快线上穿慢线且动量确认,才给多头信号;反向交叉配合动量确认,才给空头信号。 动量确认用了三个指标叠加:36周期CCI与55周期CCI都基于收盘价,另加一条27周期慢速RSI(同样收盘价)。三重过滤的用意是挤掉单纯均线交叉里那些无动量配合的假突破。 出场规则很直白:多单止损放在前一个波段低点,空单止损放前一个波段高点;止盈统一锁在距入场价300点处。外汇与贵金属波动剧烈,300点止盈在高杠杆下仍可能触发连环止损,实盘前务必在MT5用历史数据回测该参数组合。
◍ MT5里搭一套趋势动量EA的骨架
在 MetaEditor 里新建指标类文件后,先 #include <Trade\Trade.mqh> 并实例化 CTrade,交易下单和撤单都走这个对象。策略输入参数直接决定信号质量:CCI 双周期设 36 与 55,RSI 周期 27,快/慢平滑均线周期分别 11 和 25,再配一个 RSI 阈值、固定止盈点数和手数。 OnInit 里用 iCCI / iRSI / iMA 拿到五个指标句柄,任一返回 INVALID_HANDLE 就打印错误并 INIT_FAILED;ArraySetAsSeries 把缓冲区转成时间序列。OnDeinit 用 IndicatorRelease 逐个释放句柄,避免 EA 移除后内存泄漏。 OnTick 只做一件事:用 iTime 取当前 K 线时间,和 lastBarTime 比对,新 K 线才更新并调 OnNewBar,保证每根 K 线最多交易一次。OnNewBar 中 ArrayResize 留两根已收盘 K 线空间,CopyBuffer 拉取 MA、RSI、双 CCI 数值,失败即退出。 多头逻辑看 ma11 上穿 ma25、RSI 高于阈值、双 CCI 均正;空头晕厥反过来。止损用 GetPivotLow / GetPivotHigh 扫最近 100 根 K 线找波段点,找不到就退回到市价。外汇与贵金属杠杆高,这套条件仅过滤信号,实盘仍可能连续止损。 下面这段是输入参数声明原文,逐行拆: #include <Trade\Trade.mqh> // 引入交易库 CTrade obj_Trade; // 交易操作实例 input int InpCCI36Period = 36; // CCI周期1 input int InpCCI55Period = 55; // CCI周期2 input int InpRSIPeriod = 27; // RSI周期 剩下慢线、手数等在原文后续行补充,复制进 MT5 编译即可看到完整输入面板。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Copyright class="num">2025, Forex Algo-Trader, Allan. | class=class="str">"cmt">//| "https://t.me/Forex_Algo_Trader" | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Forex Algo-Trader, Allan" 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 description "This EA trades based on Trend Flat Momentum Strategy" class="macro">#class="kw">property strict class="macro">#include <Trade\Trade.mqh> class=class="str">"cmt">//--- Include the Trade library for order management. CTrade obj_Trade; class=class="str">"cmt">//--- Create an instance of the CTrade class to handle trading operations. class=class="str">"cmt">// Input parameters input class="type">int InpCCI36Period = class="num">36; class=class="str">"cmt">//--- CCI period class="num">1 input class="type">int InpCCI55Period = class="num">55; class=class="str">"cmt">//--- CCI period class="num">2 input class="type">int InpRSIPeriod = class="num">27; class=class="str">"cmt">//--- RSI period
把多指标句柄一次性挂到图表上
这套 EA 在初始化阶段就把后续逻辑要用的所有指标句柄建好,避免在每根 K 线里反复申请资源。CCI 用了 36 和 55 两个周期,RSI 与双均线(11/25)也各自独立建柄,属于典型的「先备料、后炒菜」写法。 下面这段是 OnInit 里 CCI36 与 CCI55 的创建与校验,任何一处拿不到句柄就直接 INIT_FAILED,EA 不会偷偷带病运行。外汇与贵金属杠杆高,指标句柄失败若被忽略,可能让策略在错误状态下下单,风险偏大。
…
input class="type">int InpMAFastPeriod = class="num">11; class=class="str">"cmt">//--- Fast MA period input class="type">int InpMASlowPeriod = class="num">25; class=class="str">"cmt">//--- Slow MA period input class="type">class="kw">double InpRSIThreshold = class="num">58.0; class=class="str">"cmt">//--- RSI threshold for Buy signal(Sell uses class="num">100 - Threshold) input class="type">int InpTakeProfitPoints = class="num">300; class=class="str">"cmt">//--- Take profit in points input class="type">class="kw">double InpLotSize = class="num">0.1; class=class="str">"cmt">//--- Trade lot size class=class="str">"cmt">// Pivot parameters for detecting swing highs/lows input class="type">int PivotLeft = class="num">2; class=class="str">"cmt">//--- Number of bars to the left for pivot detection input class="type">int PivotRight = class="num">2; class=class="str">"cmt">//--- Number of bars to the right for pivot detection class=class="str">"cmt">// Global indicator handles class="type">int handleCCI36; class=class="str">"cmt">//--- Handle for the CCI indicator with period InpCCI36Period class="type">int handleCCI55; class=class="str">"cmt">//--- Handle for the CCI indicator with period InpCCI55Period class="type">int handleRSI; class=class="str">"cmt">//--- Handle for the RSI indicator with period InpRSIPeriod class="type">int handleMA11; class=class="str">"cmt">//--- Handle for the fast moving average(MA) with period InpMAFastPeriod class="type">int handleMA25; class=class="str">"cmt">//--- Handle for the slow moving average(MA) with period InpMASlowPeriod class=class="str">"cmt">// Global dynamic storage buffers class="type">class="kw">double ma11_buffer[]; class=class="str">"cmt">//--- Dynamic array to store fast MA values class="type">class="kw">double ma25_buffer[]; class=class="str">"cmt">//--- Dynamic array to store slow MA values class="type">class="kw">double rsi_buffer[]; class=class="str">"cmt">//--- Dynamic array to store RSI values class="type">class="kw">double cci36_buffer[]; class=class="str">"cmt">//--- Dynamic array to store CCI values(period class="num">36) class="type">class="kw">double cci55_buffer[]; class=class="str">"cmt">//--- Dynamic array to store CCI values(period class="num">55) class=class="str">"cmt">// To detect a new bar class="type">class="kw">datetime lastBarTime = class="num">0; class=class="str">"cmt">//--- Variable to store the time of the last processed bar class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- Create CCI handle for period InpCCI36Period class="kw">using the close price. handleCCI36 = iCCI(_Symbol, _Period, InpCCI36Period, PRICE_CLOSE); class=class="str">"cmt">//--- Create the CCI36 indicator handle. if (handleCCI36 == INVALID_HANDLE) { class=class="str">"cmt">//--- Check if the CCI36 handle is valid. Print("Error creating CCI36 handle"); class=class="str">"cmt">//--- Print an error message if invalid. class="kw">return (INIT_FAILED); class=class="str">"cmt">//--- Return failure if handle creation failed. } class=class="str">"cmt">//--- Create CCI handle for period InpCCI55Period class="kw">using the close price. handleCCI55 = iCCI(_Symbol, _Period, InpCCI55Period, PRICE_CLOSE); class=class="str">"cmt">//--- Create the CCI55 indicator handle. if (handleCCI55 == INVALID_HANDLE) { class=class="str">"cmt">//--- Check if the CCI55 handle is valid.