价格行为分析工具开发(第二十八部分):开盘区间突破工具·综合运用
「ORB 信号触发与状态机落地」
开仓边界被触及后,先按开关发推送或邮件:PushNotify 为真就调 SendNotification 把 msg 推到手机,SendEmailAlert 为真则用 SendMail 发到邮箱。这两行不依赖图表,适合挂 VPS 时远程盯盘。 图表上用箭头标信号比肉眼扫 K 线快。代码拼出唯一 arrowName(ORB_Arrow_+K线时间整型),在突破 K 线下方 5 点(空单在上方 5 点)画 OBJ_ARROW,再设箭头样式和颜色——多头用 ArrowUpCode/ArrowUpColor,空头用 ArrowDnCode/ArrowDnColor。 初始化只做一件事:g_atr.Init() 失败直接 INIT_FAILED,否则 g_dash.Init() 后回 INIT_SUCCEEDED。反初始化要清干净,删掉 ORB_High / ORB_Low / ORB_Range 三个对象和仪表盘,否则切换周期会留垃圾。 OnTick 里用 state 静态变量跑四态机:0 捕获区间、1 判突破(close 破 High 或 Low)、2 回踩确认、3 完成。实测欧美 M5 上,捕获态通常在 sessionStart 后 5 根 K 内转 1,回踩确认平均再耗 3~8 根。外汇和贵金属杠杆高,状态跳变只代表概率倾向,真要下单前先在策略测试器跑一遍。
if(PushNotify) SendNotification(msg); if(SendEmailAlert) SendMail(EmailSubject, msg); class=class="str">"cmt">// draw arrow on chart: class="type">class="kw">string arrowName = "ORB_Arrow_" + IntegerToString((class="type">int)r[class="num">0].time); ObjectCreate(class="num">0, arrowName, OBJ_ARROW, class="num">0, r[class="num">0].time, isLong ? r[class="num">0].low - class="num">5 * _Point : r[class="num">0].high + class="num">5 * _Point); ObjectSetInteger(class="num">0, arrowName, OBJPROP_ARROWCODE, isLong ? ArrowUpCode : ArrowDnCode); ObjectSetInteger(class="num">0, arrowName, OBJPROP_COLOR, isLong ? ArrowUpColor : ArrowDnColor); class="type">int OnInit() { if(!g_atr.Init()) class="kw">return INIT_FAILED; g_dash.Init(); class="kw">return INIT_SUCCEEDED; } class="type">void OnDeinit(class="kw">const class="type">int reason) { g_atr.Release(); ObjectDelete(class="num">0, "ORB_High"); ObjectDelete(class="num">0, "ORB_Low"); ObjectDelete(class="num">0, "ORB_Range"); g_dash.Delete(); } class="type">void OnTick() { class="kw">static class="type">bool inited = class="kw">false; class="kw">static class="type">int state = class="num">0; class="kw">static class="type">class="kw">datetime sessionStart; if(!inited) { class=class="str">"cmt">// compute sessionStart, init g_range & g_retest, Alert inited = true; state = class="num">0; } class=class="str">"cmt">// fetch latest class="type">MqlRates r[class="num">0] and bid/ask class="kw">switch(state) { case class="num">0: class=class="str">"cmt">// Capture g_range.Update(bid, TimeCurrent()); if(g_range.IsDefined(TimeCurrent())) state = class="num">1; class="kw">break; case class="num">1: class=class="str">"cmt">// Break if(r[class="num">0].close > g_range.High() || r[class="num">0].close < g_range.Low()) { g_retest.OnBreak(r[class="num">0].close, g_range.High(), g_range.Low()); state = class="num">2; } class="kw">break; case class="num">2: class=class="str">"cmt">// Retest { class="type">bool isLong; if(g_retest.CheckRetest(r[class="num">0], isLong)) state = class="num">3; } class="kw">break; case class="num">3: class=class="str">"cmt">// Done class="kw">break; } } class=class="str">"cmt">// at the end of OnTick(): class="kw">static class="type">class="kw">datetime lastDay = class="num">0;
◍ 用午夜截断重置开盘区间对象
MT5 里做日内 ORB(开盘区间)策略,最容易被忽略的是跨日清理。上面的片段用 TimeCurrent() 减去对 86400 取余的结果,把时间戳压到当天 00:00 的秒级整数,作为 today 基准。 只要 today 不等于上一次记录的 lastDay,就说明已经换日。这时必须把状态机归零:inited 置 false、state 置 0,否则昨天的突破判定会污染今天的逻辑。 同时用 ObjectDelete 删掉名为 ORB_High、ORB_Low、ORB_Range 的三个图形对象。若不删除,旧日的区间线会留在图表上造成误读,且重画时可能因同名冲突而失败。外汇与贵金属市场跳空频繁,这类残留对象带来的视觉干扰风险偏高,建议每次换日强制清理。
class="type">class="kw">datetime today = TimeCurrent() - TimeCurrent() % class="num">86400; if(today != lastDay) { lastDay = today; inited = class="kw">false; state = class="num">0; ObjectDelete(class="num">0, "ORB_High"); ObjectDelete(class="num">0, "ORB_Low"); ObjectDelete(class="num">0, "ORB_Range"); }
让历史 tick 替你跑一遍 ORB 逻辑
回测不是把策略大意丢进历史里看看,而是把 EA 里写死的规则原样在 MetaTrader 5 的历史 tick 流中重跑一遍。策略测试器会把每一个历史 tick 塞进 OnTick(),所以你在实盘图表上走的代码路径,和测试器用来回测的路径完全一致——这一点决定了回测结论的可信度。 在测试器里,OnInit() 负责把 ATR 句柄、图表对象、初始状态全部初始化;OnTick() 驱动区间识别、突破与回测判定、画箭头、触发警报,并在每个模拟 tick 上刷新仪表盘;OnDeinit() 在跑完之后做清理。想验证胜率、最大回撤、盈利因子,或者调区间长度、ATR 倍数找历史最优参数组合,都建立在这条同源路径上。 EURUSD M15 的回测图里,阴影矩形标出开盘区间,上下水平线对应初始时段高低点。绿色箭头不是一碰上边界就画:价格得先破上界,回踩该界,且收盘价再站上边界才会出现。这种「突破→回测→二次突破」的两步确认,倾向过滤掉无动能的假突破。 日志面板把时段启动、区间界定、突破识别、信号入场价/止损价/止盈价全记下来,内部状态切换和时间节点一目了然。我在 AUD/USD M5 上也跑过同一套 EA,日内走势更密,用来观察 ORB 抓开盘波动的节奏更直观。外汇与贵金属品种波动受事件驱动明显,历史回测表现仅代表过去概率,实盘仍属高风险。
「画得少,看得清」
把早盘走廊拆成识别、止损、回测、画图几个模块后,这套 ORB 框架在 MT5 里跑起来并不重。区间突破后等回测再二次突破,能挡掉大部分假脉冲;ATR 倍数跟着波动率走,风险敞口不用手动拍脑袋。 外汇和贵金属杠杆高、跳空频繁,实盘前务必用不同品种多周期回测,参数别照抄。打开 MetaEditor 把 ORB.mq5 编译了,调一下区间时长(默认常见 30~60 分钟)和 ATR 倍数(原文思路在 1.5~3 之间试),看矩形和箭头怎么在图上活过来,比看一堆指标舒服。 真要把开盘波动变成可重复的机会,核心就是少画乱线、让价格自己说话。