MQL5 交易策略自动化(第24篇):集成风险管理与移动止损的伦敦时段突破系统(基础篇)
◍ 伦敦时段突破系统的风险与移动止损骨架
在 MT5 上做伦敦时段突破,核心不是预测方向,而是用固定风险预算卡住单笔最大亏损,再用移动止损把浮盈锁住。原文给出的系统把风险管理与移动止损做成内建模块,而不是事后手动干预。 该系统针对外汇与贵金属品种,这类品种在伦敦开盘前后波动放大,杠杆带来的高风险需要被显式约束;未加风控的突破单在滑点扩大时可能直接击穿账户容忍线。 关键参数层面,原文设定单笔风险占净值比例、突破通道周期、移动止损激活阈值三项为可调输入。交易者在 MT5 策略测试器里改这三个数,就能看到净值曲线形态明显分化,概率上更稳的未必是参数最激进的那组。
伦敦时段突破系统的开发起点
上一篇我们给包络线趋势的区间修复系统补上了移动止损和多篮子管理,这一节转入第 24 篇的主线:做一套伦敦时段突破交易系统。它要能圈出盘前震荡区、自动挂单,并把盈亏比、回撤上限和实时监控面板都打包进去。 外汇与贵金属市场高波动、高杠杆,伦敦盘前的假突破概率不低,任何自动挂单逻辑都必须先限定单笔风险再谈收益。 学完这一章,你会拿到一套自带高级风控的 MQL5 突破策略程序,能直接丢进 MT5 回测和改参数,不用从零搭框架。
「伦敦盘前区间突破的挂单逻辑」
伦敦开盘前后波动率显著放大,盘前 1~2 小时形成的高低点区间,常被用作突破交易的参照边界。在 MT5 上可先取伦敦盘前(例如 06:00–07:00 GMT)的 High/Low,再向外加几个点偏移挂 Buy Stop / Sell Stop,赌流动性涌入后的方向选择。 这种打法的优势是伦敦时段深度好、波动足,假突破虽多但幅度往往够止盈;弱点也明显,亚盘窄幅后若遇数据扰动,扫单后反向的概率不低,必须靠仓位与回撤上限兜底。 实操上建议限制同时持仓数(如 ≤2 单)并设单日最大回撤阈值(如 3%),浮盈后用移动止损锁部分利润。配合一个简易面板看盘前区间与挂单位置,只在规定边界内触发,能减少环境错配。外汇与贵金属杠杆高,这类突破策略回撤可能很快,先用模拟盘验证再上实盘。
◍ MT5里搭伦敦突破系统的骨架
打开 MetaEditor,在 Navigator 的 Indicators 下点 New 建文件,这一步只是入口。真正决定策略弹性的是开头那批输入参数和结构体:把交易方向、手数、止损、时段边界全做成 extern 输入,后面不用改代码就能换品种换周期。 先引 <Trade\Trade.mqh> 用 CTrade 类下单改仓。枚举 ENUM_TRADE_TYPE 给三种模式:TRADE_ALL 双向、TRADE_BUY_ONLY 只多、TRADE_SELL_ONLY 只空,默认 TRADE_ALL。EA 通用组里手数 inpTradeLotsize 默认 0.01,MagicNumber 12345,止损 StopLossPoints 默认 500 点,盈亏比 RRRatio 1.0;伦敦组里 LondonStartHour 9、LondonEndHour 8(跨日框),盘前有效区间限定 MinRangePoints 100 到 MaxRangePoints 300 点;风控组 MaxOpenTrades 2、MaxDailyDrawdownPercent 5.0 超了停交易。 全局变量里 obj_Trade 管交易,PreLondonHigh/Low 记区间,positionList 用 PositionInfo 结构体存 ticket、openPrice、londonRange、sessionID、trailingActive。常量 PreLondonStartHour 3 点开始采盘前高低。 面板用 OBJ_RECTANGLE_LABEL 做底、OBJ_LABEL 写字。createRecLabel 建深蓝底框,createLabel 写金标题“London Breakout Control Center”和白色 10 号字显示区间/买卖价/余额/净值/回撤。隐藏键用 Wingdings 字符 251 做红块,OBJPROP_SELECTABLE 设 true。UpdatePanel 里回撤超 MaxDailyDrawdownPercent/2 就变黄字提醒。 OnInit 里 CreatePanel 建界面,OnDeinit 用 ObjectsDeleteAll 按前缀清对象。OnChartEvent 捕获隐藏键点击就删面板。IsNewDay 用 TimeToStruct 比 lastCheckedDay 做每日重置;UpdateDailyDrawdown 用静态 maxEquity 算回撤,触 5% 就 noTradeToday=true 锁当日。 GetRange 用 iBarShift 框 K 线,iHighest/iLowest 抓高低,返回 (highVal-lowVal)/_Point。外汇贵金属波动大,5% 日回撤线只是保护壳,真跑起来仍可能连损,开 MT5 把这段代码编译后先盯三天模拟盘再谈真金。
挂单触发后怎么清场与跟损
买入止损与卖出止损双双挂出后,真正麻烦的是其中一张成交、另一张还悬着。CheckAndDeleteOppositeOrder 的逻辑很直接:若 DeleteOppositeOrder 为 false 或模式不是双向 TRADE_ALL,直接退出;否则用 OrdersTotal 反向遍历,按 MagicNumber 和 _Symbol 匹配 buyOrderTicket / sellOrderTicket,谁不在了就删掉另一张。这样盘前突破系统里只会留一个方向的敞口,避免自相打架。 持仓一旦进来就要登记。AddPositionToList 先判 londonRange 是否大于 0,再用 ArrayResize 把 positionList 撑大一格,写入 ticket、openPrice、londonRange、sessionID 和 trailingActive=false。OnTick 里用 PositionsTotal 扫一遍,内层比对 ticket 是否已存在,未跟踪的才补录,杜绝重复添加。 移动止损放在 ManagePositions:PositionsTotal 为 0 或 UseTrailing=false 就退;多空分别取 currentBid / currentAsk,盈利点数 profitPoints 达到 MinProfitPoints + TrailingPoints 后,新止损按 currentPrice ± TrailingPoints*point 重算,比原止损优化至少一个点值才用 PositionModify 改。改完置 trailingActive=true,利润锁住、尾巴留着跑。 原文示例里盘前区间实测为 100 点,落在 MinRangePoints 与 MaxRangePoints 之间,挂单与矩形绘制均正常;该数值仅作当时运行现象,外汇与贵金属杠杆品种跳空频繁,实盘触发概率与滑点风险偏高,参数须先在 MT5 策略测试器内验证。
「挂单猎杀伦敦盘前区间的代码骨架」
下面这段 EA 头部把「伦敦盘前突破」的策略壳子直接写死在输入参数里。核心约束是:Pre-London 区间必须落在 100~300 点之间(MinRangePoints / MaxRangePoints),否则当天不挂单;伦敦时段窗口被设成 09:00 开盘、08:00 收尾(注意 EndHour=8 是跨日写法,实际覆盖到次日 08:00)。 风控端给了两道硬闸:MaxOpenTrades=2 限制同屏最多两张单,MaxDailyDrawdownPercent=5.0 意味着账户日回撤触 5% 就停手。外汇与贵金属杠杆高,这种日内止损闸比盈利参数更该先调。 枚举 TRADE_TYPE 让你切 Buy/Sell/All 三种猎杀模式;RRRatio=1.0 配 StopLossPoints=500,意味着止盈默认等同 500 点止损。想验证逻辑,先把代码贴进 MT5 的 EA 编辑器,编译后看输入页是否如实暴露这些字段。 别把 500 点止损当默认圣杯 黄金 5 位数报价下 500 点=50 美元/0.01 手,但美日只需 5 位数里的 50 点。跨品种跑同一 EA 前,先手动改 StopLossPoints 再测。
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">#include <Trade\Trade.mqh> enum ENUM_TRADE_TYPE { TRADE_ALL, TRADE_BUY_ONLY, TRADE_SELL_ONLY }; input class="type">class="kw">double inpTradeLotsize = class="num">0.01; input ENUM_TRADE_TYPE TradeType = TRADE_ALL; input class="type">int MagicNumber = class="num">12345; input class="type">class="kw">double RRRatio = class="num">1.0; input class="type">int StopLossPoints = class="num">500; input class="type">int OrderOffsetPoints = class="num">10; input class="type">bool DeleteOppositeOrder = true; input class="type">bool UseTrailing = false; input class="type">int TrailingPoints = class="num">50; input class="type">int MinProfitPoints = class="num">100; input class="type">int LondonStartHour = class="num">9; input class="type">int LondonStartMinute = class="num">0; input class="type">int LondonEndHour = class="num">8; input class="type">int LondonEndMinute = class="num">0; input class="type">int MinRangePoints = class="num">100; input class="type">int MaxRangePoints = class="num">300; input class="type">int MaxOpenTrades = class="num">2; input class="type">class="kw">double MaxDailyDrawdownPercent = class="num">5.0; class="kw">struct PositionInfo { class="type">ulong ticket; }