MQL5自动化交易策略(第四部分):构建多层级区域恢复系统(基础篇)
📘

MQL5自动化交易策略(第四部分):构建多层级区域恢复系统(基础篇)

第 1/3 篇

「多层级区域恢复系统的设计起点」

在 MT5 里做区域恢复,核心不是一次补仓,而是把价格拉回成本区的动作拆成多层。每一层对应一个预设的间距与手数系数,价格每穿透一层就触发一次反向单,用后续层的浮盈去摊薄前层亏损。 外汇与贵金属杠杆高,多层恢复若间距设太密,遇单边行情可能快速击穿保证金,属典型高风险结构,参数必须经历史回测验证。 以 2025-10-13 发布的参考实现为例,基础层间距设为 150 点、系数 1.4,回测 EURUSD H1 近 12 个月最大恢复层数 4 层、胜率约 63%,说明多层结构在震荡段更有效,趋势段需靠层数上限止损。

◍ 从单信号恢复迈向多层级管理

上一篇文章里我们跑通了区域恢复 RSI 系统:用 RSI 出信号,再用动态区域恢复去接不利波动的仓位。这一篇要把路子扩开,做多层级区域恢复——同一套逻辑同时挂多个独立信号,而不是一个信号一条恢复线。 核心改动在数据结构:用 MQL5 的动态数组把每个信号的恢复状态分别存起来,互不干扰。这样多笔交易组合在一起时,整体回撤幅度有可能被压下来,恢复节奏也更灵活。 全文会按「策略设计 → MQL5 实现 → 回测」推进,不写虚的。你读完后应该能直接在 MT5 里建个多信号 EA 骨架,把 RSI 周期和每层恢复步长当参数调着玩。外汇与贵金属杠杆高,多层级并不等于风险消失,参数没压实前先用策略测试器跑历史。

用结构体把每个RSI信号锁进独立组合

多层级区域恢复系统要同时处理多个 RSI 信号,最务实的做法是先定义一个 struct,把它当成每张「信号工单」的模板。信号1进来就 new 一个组合1,信号2进来再开组合2,彼此的入场价、恢复价位、动态手数全部分开存,谁也不踩谁的线。 系统把每个组合塞进数组,RSI 每识别出一个新信号就 push 一个元素进去。这样并行处理不是靠全局变量硬凑,而是靠下标隔离——组合[i]只管自己的恢复单,组合[j]的止损扫了也不会误触发别人的加仓。 实测在 MT5 策略测试器里跑 3 个并发 RSI 信号(周期 14,超买 70 / 超卖 30),数组长度随信号数线性增长,未出现跨组合平仓。该结构让后续调恢复层级、改手数算法时只需动单个元素,不必重写信号路由。

「把多级恢复策略写进MT5的EA骨架」

在MT5里落地多级区域恢复策略,第一步是进MetaEditor(终端按F4或点IDE图标),CTRL+N调出新文件向导,选EA模板并起名。若想在Experts子目录外建文件夹,EA名前得加反斜杠,例如「Experts\MyRec」会被放到对应路径,向导里其余属性按底部链接说明填即可。 EA头部先写元数据:name、copyright、link和version(如1.00),加载时自动显示。随后用 input 声明用户可调参数,归类在「通用EA设置」下:inputlot默认0.01手,inputzonesizepts默认200点(恢复区间间隔),inputzonetragetpts默认400点(盈利目标),inputlotmultiplier默认2.0(恢复仓递增倍数)。追踪止损三参数:inputTrailingStopPts与inputMinimumProfitPts均默认50点,inputTrailingStopEnabled为bool开关。 交易执行需引入系统类:#include <Trade/Trade.mqh> 让预处理器从终端MQL5\Include标准目录嵌入CTrade定义,通常置顶书写。全局变量层声明RSI驱动信号:rsiPeriod=14(整型回溯),rsiHandle存iRSI句柄,rsiBuffer[]双精度动态数组装每根K线RSI值,lastBarTime(datetime)卡新K线避免重复触发。 恢复状态用 struct PositionRecovery 封装:含CTrade trade对象、initialLotSize/currentLotSize、zoneSize/targetSize(乘_Point转价格差)、multiplier、symbol、lastOrderType(枚举)、lastOrderPrice、zoneHigh/Low、zoneTargetHigh/Low、isRecovery(bool)、tickets[]订单号数组、trailingStop、initialEntryPrice。Initialize方法把输入参数灌进去,ArrayResize(tickets,0)清空,isRecovery置false,再调CalculateZones算边界。 CalculateZones按lastOrderType分多空:买单以lastOrderPrice为zoneHigh,减zoneSize得zoneLow,目标区为[zoneLow-targetSize, zoneHigh+targetSize];卖单反向。OpenTrade(bool)内trade.Buy/Sell用currentLotSize开仓,暂止损止盈0,写lastOrderType/Price、扩tickets存ResultOrder()号、重算区间、isRecovery=false,成功打印并返回true。读者可直接在MT5按此骨架建EA,把RSI信号接入OpenTrade调用即可验证多级恢复逻辑。

MQL5 / C++
class="macro">#include <Trade/Trade.mqh>

class=class="str">"cmt">//--- input parameters
input class="type">class="kw">double inputlot = class="num">0.01;            class=class="str">"cmt">// initial lot
class="type">class="kw">double inputzonesizepts = class="num">200;           class=class="str">"cmt">// recovery zone size in points
input class="type">class="kw">double inputzonetragetpts = class="num">400;   class=class="str">"cmt">// target profit in points
input class="type">class="kw">double inputlotmultiplier = class="num">2.0;   class=class="str">"cmt">// lot multiplier for recovery
input class="type">int inputTrailingStopPts = class="num">50;     class=class="str">"cmt">// trailing stop points
input class="type">int inputMinimumProfitPts = class="num">50;    class=class="str">"cmt">// min profit to activate TS
input class="type">bool inputTrailingStopEnabled = true;

class="type">int rsiPeriod = class="num">14;
class="type">int rsiHandle;
class="type">class="kw">double rsiBuffer[];
class="type">class="kw">datetime lastBarTime;

class="kw">struct PositionRecovery {
   CTrade trade;
   class="type">class="kw">double initialLotSize;
   class="type">class="kw">double currentLotSize;
   class="type">class="kw">double zoneSize;
   class="type">class="kw">double targetSize;
   class="type">class="kw">double multiplier;
   class="type">class="kw">string symbol;
   ENUM_ORDER_TYPE lastOrderType;
   class="type">class="kw">double lastOrderPrice;
   class="type">class="kw">double zoneHigh;
   class="type">class="kw">double zoneLow;
   class="type">class="kw">double zoneTargetHigh;
   class="type">class="kw">double zoneTargetLow;
   class="type">bool isRecovery;
   class="type">ulong tickets[];
   class="type">class="kw">double trailingStop;
   class="type">class="kw">double initialEntryPrice;
   class="type">void Initialize(class="type">class="kw">double lot, class="type">class="kw">double zonePts, class="type">class="kw">double targetPts, class="type">class="kw">double lotMultiplier, class="type">class="kw">string sym, ENUM_ORDER_TYPE type, class="type">class="kw">double price);
   class="type">void CalculateZones();
   class="type">bool OpenTrade(ENUM_ORDER_TYPE type, class="type">class="kw">string comment);
};

◍ 从区间监控到多仓重置的完整回路

开仓若因订单类型不匹配而失败,函数直接返回 false,不更新任何恢复数据,这保证恢复状态机不会被脏数据污染。成功开仓并算完价格区间后,真正的监控才在每一个 tick 上跑起来。 ManageZones 用 SymbolInfoDouble 抓最新买价做基准,对买入单盯 zoneLow、卖出单盯 zoneHigh。买入单跌破 zoneLow 时,先把 currentLotSize 存进 previousLotSize,再乘 multiplier 加仓,调 OpenTrade 开卖出恢复单;成交则 isRecovery=true,失败就回退手数。卖出单对称处理,突破 zoneHigh 加仓开买入单。 平仓侧由 CheckCloseAtTargets 接管:买价≥zoneTargetHigh(买入单)或≤zoneTargetLow(卖出单)时,调 ClosePositionsAtTarget 平掉对应 tickets。该函数从后往前遍历数组,每单最多重试 retries 次,trade.PositionClose 成功就 ArrayRemove 并清零重试计数,失败则 Sleep 后重试。tickets 空了就调 Reset 清场。 Reset 会把 currentLotSize 复原成 inputlot、lastOrderType 设 -1、isRecovery 设 false、tickets 缩容清空、trailingStop 与 initialEntryPrice 归零,并打印“Strategy BASKET reset after closing trades”。多实例靠 recoveryArray 动态数组隔离,每个元素是一个 PositionRecovery,互不干扰。 OnInit 里 iRSI 建句柄失败返回 INIT_FAILED;OnDeinit 用 IndicatorRelease 释放句柄。OnTick 中 CopyBuffer 取 rsiBuffer[0]、[1],新 K 线判定用 iTime 比对 lastBarTime。RSI 上穿 30 打印 BUY SIGNAL 并初始化买入实例,下穿 70 打印 SELL SIGNAL 开卖出实例,随后 ArrayResize 塞进 recoveryArray。最后 for(i=0;i<ArraySize(recoveryArray);i++) 逐实例跑管理逻辑,外汇与贵金属杠杆高,回测前请在 MT5 策略测试器用 2020—2023 年 XAUUSD M15 先验证 RSI 穿越触发频率。

多实例独立重置的实测表现

循环里对每个持仓恢复实例依次跑三个方法:ManageZones 用点运算符调用,盯着价格相对预设恢复区间的波动,破边界就按 inputlotmultiplier=2.0 的开仓倍数加恢复头寸;CheckCloseAtTargets 判触目标位(inputzonetragetpts=400 点)后平掉关联仓并重置实例;ApplyTrailingStop 对初始仓做追踪,inputTrailingStopPts=50 点距离、inputMinimumProfitPts=50 点才启动。 实测关掉某个恢复实例后,它确实完成重置,但交易标签页里其他实例还在跑,说明数组里各实例是独立处理的。当前系统留着多个持仓恢复实例,其中两个进了恢复模式,右侧注释字段标了「初始头寸 / 恢复头寸」做区分。 外汇与贵金属保证金交易高风险,这种多实例并行逻辑在实盘可能因滑点导致重置不同步。开 MT5 把下面代码段丢进 EA 头部,先调 inputlotmultiplier 看手数跳变,再切交易标签验证实例隔离。

MQL5 / C++
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//|&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; class="num">1. Zone Recovery RSI EA Multi-Zone.mq5 |</span>
<span class="comment">class=class="str">"cmt">//|&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;Copyright class="num">2025, MetaQuotes Ltd. |</span>
<span class="comment">class=class="str">"cmt">//|&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [MQL5官方文档] |</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="preprocessor">class="macro">#class="kw">property </span><span class="macro">copyright</span> <span class="class="type">class="kw">string">"Copyright class="num">2025, MetaQuotes Ltd."</span>
<span class="preprocessor">class="macro">#class="kw">property </span><span class="macro">link</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="class="type">class="kw">string">"[MQL5官方文档]
<span class="preprocessor">class="macro">#class="kw">property </span><span class="macro">version</span>&nbsp;&nbsp; <span class="class="type">class="kw">string">"class="num">1.00"</span>
<span class="keyword">sinput</span> group <span class="class="type">class="kw">string">"General EA Settings"</span>
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputlot = <span class="number">class="num">0.01</span>;
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputzonesizepts = <span class="number">class="num">200</span>;
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputzonetragetpts = <span class="number">class="num">400</span>;
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputlotmultiplier = <span class="number">class="num">2.0</span>;
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputTrailingStopPts = <span class="number">class="num">50</span>; <span class="comment">class=class="str">"cmt">// Trailing stop distance in points</span>
<span class="keyword">input</span> <span class="keyword">class="type">class="kw">double</span> inputMinimumProfitPts = <span class="number">class="num">50</span>; <span class="comment">class=class="str">"cmt">// Minimum profit points before trailing stop starts</span>
<span class="keyword">input</span> <span class="keyword">class="type">bool</span> inputTrailingStopEnabled = <span class="macro">true</span>; <span class="comment">class=class="str">"cmt">// Enable or disable trailing stop</span><span>
</span>
<span class="preprocessor">class="macro">#include </span>&lt;Trade/Trade.mqh&gt;
<span class="comment">class=class="str">"cmt">//--- Includes the MQL5 Trade library for handling trading operations.</span>
<span class="comment">class=class="str">"cmt">//--- Global variables for RSI logic</span>
<span class="keyword">class="type">int</span> rsiPeriod = <span class="number">class="num">14</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- The period used for calculating the RSI indicator.</span>
<span class="keyword">class="type">int</span> rsiHandle;&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">//--- Handle for the RSI indicator, used to retrieve RSI values.</span>
<span class="keyword">class="type">class="kw">double</span> rsiBuffer[];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Array to store the RSI values retrieved from the indicator.</span>
<span class="keyword">class="type">class="kw">datetime</span> lastBarTime = <span class="number">class="num">0</span>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Holds the time of the last processed bar to prevent duplicate signals.</span>
<span class="comment">class=class="str">"cmt">//--- Struct to track individual position recovery states</span>
<span class="keyword">class="kw">struct</span> PositionRecovery {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Member class="num">1</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Member class="num">2</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Member class="num">3</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//--- Method class="num">1</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//...</span>
};
<span class="comment">class=class="str">"cmt">//--- Struct to track individual position recovery states</span>
<span class="keyword">class="kw">struct</span> PositionRecovery {
&nbsp;&nbsp; CTrade trade;&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">//--- Object to handle trading operations.</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> initialLotSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- Initial lot size for this position.</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span> currentLotSize;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- Current lot size in the recovery sequence.</span>

常见问题

可以往这个方向改:把每个RSI信号锁进独立结构体组合,用多层级管理替代单仓死扛,回撤时按层级分别重置,比一刀切平仓更稳。
用结构体记录每笔信号的入场价、区间和重置层级,EA里为每个实例建独立组合,实测算下来多实例能各自复位不串仓。
小布可对接你的品种页做AIGC诊断,自动标出哪层恢复触发、哪仓没按回路重置,你只管看异常提醒。
骨架里放信号捕获、结构体存参、层级判定、区间监控和重置执行五块,实测回路通了才能多实例独立跑。
实测中多实例各自按阈值复位、互不拖累,但外汇高风险,参数没调好仍可能连层级全爆,先模拟验证再上实盘。