将概率论应用于缺口交易·综合运用
📊

将概率论应用于缺口交易·综合运用

(3/3)·从思路验证到风险测算,把概率框架真正跑通在单一资产 EA 上

进阶 第 3/3 篇
很多交易者把缺口当成孤立信号,忽略了背后价格是否仍服从零漂移随机漫游。若没有统计层面的反证,盈利交易在数学上本就不可能。先验证偏差,再谈策略,否则只是在噪声里找图案。

◍ 缺口对象的破位判定与容器维护

这段 MQL5 实现把「价格缺口」封装成 SGap 类,再用 CGaps 管理一组活跃缺口。核心破位函数 brkn() 用三根参考价 p0、p1、p2 判定:当 p0 在 p1 上方且 p2 回落至 p1 或以下,或 p0 在 p1 下方且 p2 升破 p1 或以上,返回 1 表示缺口被回填;若进度函数 Q() 达到阈值 q0 则返回 -1,否则 0 表示仍在挂单区。 Q() 的计算式为 (p2-p0)/(p2-p1),当 p2 等于 p1 时直接返回 0.0,避免除零。a() 则用 gap() 绝对值和滑点 s 推导挂单比例,k0 固定为 q0/(1-q0),这套映射决定了每跳价格对应的仓位权重。 CGaps::add() 在新增缺口时按 p+(p-p_1)*q0/(1-q0) 推演出参考挂单价 ps,并调用 pp2v() 换算成手数;容器用 ArrayResize 以 ND 为步长动态扩容。change() 遍历活跃缺口,根据多空方向用 bid 或 ask 更新 p2,一旦 brkn() 非 0 就把索引置 -1 标记失效。 实盘里外汇与贵金属跳空后回填概率随品种波动率变化,建议把这段代码挂到 MT5 策略测试器,用不同 q0(如 0.5 / 0.618)跑 EURUSD 与 XAUUSD 的 tick 数据,观察 ng0 失效节奏再调参。

MQL5 / C++
else
      { request.volume=-vi*dv;
        request.type=ORDER_TYPE_SELL;
      }
   if(!OrderSend(request,result)) PrintFormat("OrderSend error %d",GetLastError());
  }
class="type">int SGap :: brkn()
  { if(((p0>p1)&&(p2<=p1))||((p0<p1)&&(p2>=p1))) class="kw">return class="num">1;
    if(Q()>=q0) class="kw">return -class="num">1;
    class="kw">return class="num">0;
  }
class="type">bool SGap :: up()
  { class="kw">return p0>p1;
  }
class="type">void SGap :: change(class="type">class="kw">double p)
  { if(brkn()==class="num">0) p2=p;
  }
class="type">class="kw">double SGap :: gap()
  { class="kw">return MathAbs(p0-p1);
  }
class="type">class="kw">double SGap :: Q()
  { if(p2==p1) class="kw">return class="num">0.0;
    class="kw">return (p2-p0)/(p2-p1);
  }
class="type">class="kw">double SGap :: a()
  { class="type">class="kw">double g=gap(), k0=q0/(class="num">1-q0);
    class="kw">return (g-s)/(k0*g+s);
  }
class="type">void CGaps :: init()
  { ngs=ngo=class="num">0;
  }
class="type">void CGaps :: add(class="type">class="kw">double p_1,class="type">class="kw">double p)
  { ++ngs;
    if(ArraySize(gs)<ngs) ArrayResize(gs,ngs,ND);
    gs[ngs-class="num">1].p0=gs[ngs-class="num">1].p2=p;
    gs[ngs-class="num">1].p1=p_1;
    class="type">class="kw">double ps=p+(p-p_1)*q0/(class="num">1-q0);
    gs[ngs-class="num">1].v=pp2v(ps,p);
    class="type">int i=class="num">0;
    for(; i<ngo; ++i) if(go[i]<class="num">0) class="kw">break;
    if(i==ngo)
      {
        ++ngo;
        if(ArraySize(go)<ngo) ArrayResize(go,ngo,ND);
      }
    go[i]=ngs-class="num">1;
  }
class="type">bool CGaps :: change(class="type">class="kw">double pbid,class="type">class="kw">double pask)
  { class="type">bool ch=class="kw">false;
    for(class="type">int i=class="num">0; i<ngo; ++i)
      { if(go[i]<class="num">0) class="kw">continue;
        if(gs[go[i]].up()) gs[go[i]].change(pbid); else gs[go[i]].change(pask);
        if(gs[go[i]].brkn()!=class="num">0) {go[i]=-class="num">1; ch=true;}
      }
    class="kw">return ch;
  }
class="type">class="kw">double CGaps :: v(class="type">void)
  { class="type">class="kw">double v=class="num">0;
    for(class="type">int i=class="num">0; i<ngo; ++i) if(go[i]>=class="num">0) v+=gs[go[i]].v;
    class="kw">return v;
  }
class="type">void CGaps :: gs2f(class="type">class="kw">string fn)
  { class="type">int f=FileOpen(fn, FILE_WRITE|FILE_COMMON|FILE_ANSI|FILE_TXT);
    class="type">int na=class="num">0, np=class="num">0, bk;
    class="type">class="kw">double kt=class="num">0.0, pk=class="num">0.0;
    for(class="type">int i=class="num">0;i<ngs;++i)
      { bk=gs[i].brkn();
        if(bk==class="num">0) class="kw">continue;

「把回测统计量写进文件再喂给优化器」

上面这段逻辑干了两件事:先按样本数 na 求平均触发价 kt,再算盈利交易占比 pk,最后用 FileWriteString 把 na、kt、pk 三个量落盘。注意 kt 只有在 na>0 时才做除法,避免空样本除零;pk 是 np/na 的 double 强转,直接反映胜率倾向。 落盘之后,代码用 input 把上一次统计结果硬编码成新轮优化的起点:na=26 表示取 26 笔交易做样本,kt=1.1627 是止盈/止损比,pk=0.5769 即约 57.7% 的盈利概率。外汇与贵金属波动剧烈,这组数只是某段历史样本,换周期可能漂移。 G0、D0、dlt 三个常量是下一轮筛选门槛:G0=0 表示不卡最低平均盈利,D0=0.9 要求增量至少 0.9,dlt=0.17 是显著性阈值。你开 MT5 把这段贴进 EA 的收尾模块,改 na 或 kt 初始值,就能看输出文件里的 pk 是否随样本放大而收敛。

MQL5 / C++
    ++na; if(bk>class="num">0) ++np;
    kt+=gs[i].a();
   }
  if(na>class="num">0)
   { kt/=na;
     pk=((class="type">class="kw">double)np)/na;
   }
   FileWriteString(f,"na = "+(class="type">class="kw">string)na+"\n");
   FileWriteString(f,"kt = "+(class="type">class="kw">string)kt+"\n");
   FileWriteString(f,"pk = "+(class="type">class="kw">string)pk);
   FileClose(f);
}
input class="type">uint na=class="num">26;                class=class="str">"cmt">// 该系列中的交易数量
input class="type">class="kw">double kt=class="num">1.162698185452029 class=class="str">"cmt">// 止盈/止损比率
input class="type">class="kw">double pk=class="num">0.5769230769230769class=class="str">"cmt">// 盈利能力
class="type">class="kw">double G0=class="num">0.0;                   class=class="str">"cmt">// 最低平均盈利能力
class="type">class="kw">double D0=class="num">0.9;                   class=class="str">"cmt">// 最小增量
class="type">class="kw">double dlt=class="num">0.17;                 class=class="str">"cmt">// 显著级别

概率思路能补你的现有策略

概率方法很适合用来开发和配置 EA,但它不排他。 实际中它往往能补上你已有的技术路线,或逼你重新想一遍进出场逻辑。 本文没碰常规 EA 参数优化,只顺带提了一句。 这块和概率方法(统计方案理论)其实绑得很紧,后续有机会再拆。 外汇和贵金属波动大、杠杆高,任何统计结论都只是概率倾向,上 MT5 跑一遍自己的品种再定参数。

◍ 别急着下结论

随文附带三个 EA 源码:gaps_reg_stat.mq5(2.47 KB)抓连续逐笔报价间的缺口分布,gaps_ses_stat.mq5(3.16 KB)按交易时段收口统计缺口,gaps_ses_test.mq5(4.93 KB)直接拿时段缺口跑回测。把它们丢进 MT5 的 MQL5/Experts 目录编译,先跑 stat 两个收集样本,再换 test 验信号,比对着看才有意义。 外汇和贵金属缺口本身低频,俄文原帖评论里也提到周间隙之外还能叠新闻间隙,但罕见不代表能裸做。用这几只 EA 把你自己品种的缺口频率跑出来之前,别预设它「够用」或「没用」——样本量不到几千次跳动,统计结论都只是倾向。 下载包里文件版权归原作者,部分复制转载被禁;MT5 里实跑验证时,注意实盘外汇/贵金属杠杆风险,回测漂亮不等于活盘能复现。

把重复劳动交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到缺口分布与漂移检验的实时面板,你只需判断信号是否越过阈值。

常见问题

当价格无方向趋势且步长随机,任意时刻买卖的期望收益为零,扣除点差后为负,系统交易无法长期为正。
这是为隔离思路本身有效性所做的简化,避免执行噪声掩盖概率结构的真实表现,后续再逐步放归市场现实。
越是系统且频繁地应用论证过的概率手段,样本均值越逼近期望,结果在大样本下更明显稳定。
可以,小布盯盘内置了品种页的缺口统计与漂移检测模块,省去手动跑脚本,你专注决策即可。
它保证每个最小步长时刻至多一个变量跳变,令资金函数可分段递推,简化 EA 结果的数学定义与回测。