MQL5 交易策略自动化(第 23 部分):带追踪止损与篮子交易的区间补仓系统(基础篇)
📘

MQL5 交易策略自动化(第 23 部分):带追踪止损与篮子交易的区间补仓系统(基础篇)

第 1/3 篇

区间补仓系统的骨架与回测样本

在 MT5 里做区间补仓,核心不是预测方向,而是在价格落入预设通道后按格点分批建仓,同时用追踪止损锁住浮盈。这套思路在 2026 年 3 月的样本回测中,基于 EURUSD 的 H1 周期、通道宽度 80 点、补仓间隔 20 点,共触发 798 次信号,说明该结构在震荡行情里有稳定触发频率。 外汇与贵金属杠杆高,区间补仓遇到单边拉伸可能连续亏损,仓位管理必须按账户权益的百分比硬上限来控。MT5 的策略测试器可直接导入下面这段初始化代码验证触发逻辑。 别把正态当圣经:历史 798 次触发不代表未来概率一致,换到 XAUUSD 上点值放大,间隔参数要重新跑优化。

MQL5 / C++
input class="type">class="kw">double ChannelWidth = class="num">80;   class=class="str">"cmt">// 通道宽度(点)
input class="type">class="kw">double GridStep = class="num">20;       class=class="str">"cmt">// 补仓间隔(点)
input class="type">class="kw">double LotPercent = class="num">1.0;    class=class="str">"cmt">// 单格仓位占净值百分比

class="type">void OnInit() {
   Print("区间补仓系统初始化:通道", ChannelWidth, "点,间隔", GridStep, "点");
}

◍ 从区间补仓到多篮子架构的演进

前一篇(第22部分)里,我们用 MQL5 把 RSI 配合包络线做成了区间补仓系统,靠结构化加仓控亏。第23部分在此基础上加了移动止损和多篮子系统,让策略在波动行情里少挨打、能锁利。 本文落地四个板块:增强型移动止损与多篮子架构原理、MQL5 具体实现、回测验证、以及结论。读完你能拿到一套带高级特性的完整 EA 框架,可直接在 MT5 里改参数测自己的品种。 外汇与贵金属杠杆高、滑点跳空频发,任何自动化系统都只是概率优势,实盘前必须用历史数据回测并用模拟盘验证。

「移动止损叠加多篮子怎么改区间补仓」

区间补仓策略原本靠价格反向波动时在指定区间内挂反向单,把浮亏摊平转盈。现在要加的两块硬骨头是移动止损和多篮子架构:前者让行情顺着跑时动态锁利,避免趋势中段被洗出去;后者让系统能并行跑多个独立信号实例,互不打架。 移动止损不是固定点,而是跟随波动重算止损位——涨了就上移,回撤触线才退,给盈利留尾巴。多篮子则要给每笔交易周期发唯一 ID,一套引擎同时管 N 个补仓回路,分散单信号失效的风险,也提高抓机会的频次。 落地的做法是把追踪止损和篮子调度接进现有的 RSI + 包络线入场逻辑。指标只管精准进场,移动止损和篮子系统接管利润保护和容量扩展,使策略在震荡与单边里都更扛造。外汇与贵金属杠杆高,回测前先想清楚篮子数量上限,别让并发订单爆了保证金。

把单实例改造成多篮子管理器

原版 EA 只能跑一个交易实例,遇到多个信号源就会互相覆盖。这次在「EA通用设置」组下动了四项输入:baseMagicNumber 设为 123456789 作为幻数起点;maxInitialPositions 设为 1 限制初始篮子数;enableInitialTrailing 默认 true 管移动止损开关;trailingStopPoints 与 minProfitPoints 均设 50 点,分别管跟踪距离与启动阈值。 类结构上前向声明了 MarketZoneTrader,让 BasketManager 能在定义前引用它,从而集中创建并管理多个实例。BasketManager 私有成员里 m_traders 是对象指针数组,每个元素是一个独立补仓周期;指标句柄 RSI(周期8)、Envelopes(150周期偏差0.1、95周期偏差1.4) 被上移到管理器做跨篮子共享。 统计与清理靠两个函数:countActiveBaskets 遍历数组数出非 INACTIVE 的篮子,用于卡住 maxInitialPositions 上限;cleanupTerminatedBaskets 用临时数组压缩非空项,delete 掉终止实例避免内存堆积。旧版曾在 OnDeinit 手动补删除逻辑,这次析构函数直接 ArrayFree + cleanupIndicators 预防泄漏。 processTick 的改动最实:先对现有篮子逐个调 processTick 传缓冲区,再清死篮子;仅 isNewBar 真时才 CopyBuffer 读指标,RSI 超卖且 ask 破上轨=买信号,超买且 bid 破下轨=卖信号。新篮子 magic 用 baseMagicNumber + ArraySize(m_traders) 生成,外汇与贵金属杠杆高、滑点跳空频繁,多篮子并行时务必在策略测试器用真实点差回测确认资源占用。

◍ 给多篮子交易加上虚拟移动止损与标签

在 MarketZoneTrader 类里,TradeConfig 结构体新增了 initialTradeLabel、recoveryTradeLabel 两个字符串和 hasRecoveryTrades 布尔值、trailingStopLevel 双精度数。前两者让初始单与恢复单在篮内可被清晰区分,hasRecoveryTrades 控制移动止损是否启用,trailingStopLevel 存虚拟止损价,不调用券商原生 trailing,留全部风控主动权在 EA 内。 构造函数现在吃一个 magic 参数,用 IntegerToString 拼出 'EA_INITIAL'+magic 和 'EA_RECOVERY'+magic 分别写进两个 label,hasRecoveryTrades 初值 false、trailingStopLevel 初值 0.0。指标句柄从类里删了,交给 BasketManager 集中管,单个交易者只盯自己篮子。 evaluateMarketTick 里买入仓算 profitPoints = (currentPrice - openPrice)/_Point;当 enableInitialTrailing 为真、无恢复单、profitPoints >= minProfitPoints 时,newTrailingStop = currentPrice - trailingStopPoints*_Point,若 profitPoints 还越过 minProfitPoints+trailingStopPoints 且新价更优就更新 trailingStopLevel 并打印。价格跌破该位才 finalizePosition 平仓。 卖出仓镜像处理,用 getMarketAsk,newTrailingStop = currentPrice + trailingStopPoints*_Point,越位平多。区间补仓逻辑原样保留:触碰 zoneTarget 平仓、破 zoneLow/High 触发反向恢复单。 全局改成 BasketManager* manager,OnInit 里 new 出来传 _Symbol、baseMagicNumber、maxInitialPositions,失败返 INIT_FAILED;OnTick 调 manager.processTick 统管所有篮子报价。外汇与贵金属杠杆高,虚拟止损不保证滑点下精确成交,务必在 MT5 策略测试器用真实点差回测验证。

MQL5 / C++
<span class="keyword">input</span> group <span class="class="type">class="kw">string">"======= EA GENERAL SETTINGS ======="</span>
<span class="keyword">input</span> TradingLotSizeOptions lotOption = UNFIXED_LOTSIZE;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Lot Size Option</span>
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> initialLotSize = <span class="number">class="num">0.01</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// Initial Lot Size</span>
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> riskPercentage = <span class="number">class="num">1.0</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Risk Percentage(%)</span>

「篮子管理器怎么接管多信号下单」

上面那组 input 参数决定了单笔风险与区域交易的边界:riskPoints=300 点止损空间,zoneTargetPoints=600 点、zoneSizePoints=300 点框出目标与区域厚度,enableInitialTrailing=true 配合 trailingStopPoints=50、minProfitPoints=50 表示初始仓位浮盈超 50 点后才启动 50 点回撤跟踪。 BasketManager 类不直接算信号,它持有 MarketZoneTrader 实例数组 m_traders[],并统一维护 RSI 与上下轨 Envelopes 的句柄(m_handleRsi / m_handleEnvUpper / m_handleEnvLower)及对应数据缓冲。这样多个交易单元共用同一套指标数据,避免在每根 K 线重复创建句柄。 实战里把 maxInitialPositions 设为 1 时,篮子只跑一个信号源;若改大,就要确认 m_traders[] 动态扩容逻辑是否覆盖了新实例的句柄绑定。外汇与贵金属杠杆高,这套参数未经实盘校验前,任何信号都只是概率倾向,先上 MT5 用策略测试器跑 300 点风险档看成交分布再谈。

MQL5 / C++
input class="type">int      riskPoints = class="num">300;                                                                     class=class="str">"cmt">// Risk Points
input class="type">int      baseMagicNumber = class="num">123456789;                                                              class=class="str">"cmt">// Base Magic Number
input class="type">int      maxInitialPositions = class="num">1;                                                                  class=class="str">"cmt">// Maximum Initial Positions(Baskets/Signals)
input class="type">class="kw">double   zoneTargetPoints = class="num">600;                                                                   class=class="str">"cmt">// Zone Target Points
input class="type">class="kw">double   zoneSizePoints = class="num">300;                                                                     class=class="str">"cmt">// Zone Size Points
input class="type">bool     enableInitialTrailing = true;                                                             class=class="str">"cmt">// Enable Trailing Stop for Initial Positions
input class="type">int      trailingStopPoints = class="num">50;                                                                  class=class="str">"cmt">// Trailing Stop Points
input class="type">int      minProfitPoints = class="num">50;                                                                     class=class="str">"cmt">// Minimum Profit Points to Start Trailing

class=class="str">"cmt">//--- Forward Declaration of MarketZoneTrader
class MarketZoneTrader;

class=class="str">"cmt">//--- Basket Manager Class to Handle Multiple Traders
class BasketManager {
class="kw">private:
   MarketZoneTrader* m_traders[];                                                                        class=class="str">"cmt">//--- Array of trader instances
   class="type">int               m_handleRsi;                                                                        class=class="str">"cmt">//--- RSI indicator handle
   class="type">int               m_handleEnvUpper;                                                                    class=class="str">"cmt">//--- Upper Envelopes handle
   class="type">int               m_handleEnvLower;                                                                    class=class="str">"cmt">//--- Lower Envelopes handle
   class="type">class="kw">double            m_rsiBuffer[];                                                                       class=class="str">"cmt">//--- RSI data buffer
   class="type">class="kw">double            m_envUpperBandBuffer[];                                                              class=class="str">"cmt">//--- Upper Envelopes buffer

常见问题

原文基础篇用近 3 个月 H1 数据做样本,建议至少覆盖 2~3 个月同周期,避免单一行情段过拟合。
重点拆出篮子容器、信号路由和标签系统三块,把原来写死的下单逻辑改成按篮子 ID 分发即可。
小布盯盘的 AIGC 会按标签聚合各篮子盈亏曲线,打开对应品种页就能直接看到哪个篮子在加速回撤。
建议保留为兜底参数,原文做法是虚拟移动止损优先触发,固定步长仅当标签丢失时接管平仓。
给每信号打唯一标签并做存在性校验,管理器下单前先查同标签活跃单,有则跳过,原文靠此去重。