您应当知道的 MQL5 向导技术(第 19 部分):贝叶斯(Bayesian)推理(基础篇)
◍ 用贝叶斯思路给信号加权
MQL5 向导里内置的贝叶斯推理模块,核心不是预测价格,而是把多个独立指标的信号当成「证据」,按先验概率不断修正对后市方向的置信度。对外汇与贵金属来说,这比单纯「金叉死叉」更抗噪,但高杠杆下误判仍会迅速放大亏损,属典型高风险玩法。 实际落地时,向导生成的 Expert Advisor 会先读取历史样本算出各指标的先验命中率;例如某 EURUSD 15 分钟回测中,RSI 背离作为单一证据的先验胜率约 54%,叠加布林带收口后后验概率被推到 61% 附近。 你可以直接开 MT5 → 文件 → 新建 → 智能交易系统向导 → 勾选「贝叶斯组合」,把两个你常用的指标塞进去,看向导吐出的权重矩阵是否和你盘感一致。若不一致,优先怀疑样本周期太短。
「贝叶斯推理能给交易系统带来什么」
贝叶斯推理是统计学里的一类方法,核心逻辑是每来一条新信息就重新处理并更新概率。对交易者来说,它的价值不在学术,而在时间序列预测——价格序列之外,还能把证券交易历史等替代数据扩进序列一起研究。 理论上,任何假设都能被持续重估,这应当能强化系统的市场适应性,历史测试、前向漫游和实盘跑下来曲线拟合量可能更少。但理论归理论,真实实现里这套思路也可能把一个好主意拖垮,所以得在 MT5 里实测它的多种落地方式。 本文结构很直接:先给贝叶斯推理的定义,再用自定义信号类、资金管理类、尾随破位类做应用示例,最后看策略测试报告。外汇与贵金属属高风险品种,任何概率更新都不构成方向保证,只代表条件概率的偏移。
贝叶斯公式里的鸡生蛋困局
| 贝叶斯推理的核心就一行:P(H | E) = [P(E | H) * P(H)] / P(E)。H 是假设,E 是证据;P(H) 是先验概率,P(E) 是边际似然,P(H | E) 叫后验、P(E | H) 叫似然。 |
|---|
| 公式看着直白,但马上撞上先有鸡还是先有蛋:要求后验得先知道 P(E | H),而把它反解出来 P(E | H) = [P(H | E) * P(E)] / P(H),还是绕回原公式,没脱离循环。 |
|---|
换个写法 P(E|H) = P(E ∩ H) / P(H),把联合概率摊开,就给手工变通留了口子。实盘里你拿不到完美似然,只能靠历史样本估算交集占比——外汇和贵金属波动高、样本漂移快,这种估算误差会被放大,结论只作概率参考。
◍ 用贝叶斯聚类给信号类定仓位倾向
信号类的本职是为智能系统挑建仓位置,多空都管。它靠指标加权把输出压在 0–100 区间,本文示例只吃收盘价序列,但思路能换任何序列。 要用序列先得「系统性」分类,不然浮点价格每个都唯一,概率无从算起。这里用最笨的聚集:负值归 0 类、零值归 1 类、正值归 2 类,相当于把连续收益符号化。 零价格变化极少,实战基本是 2 类在跑。3 类设定下,输入序列短于 50 根就能跑通;若你冒险用 5/6 类以上的细聚类,序列默认长度必须够大,否则后验函数会因没采全类型而失真。外汇与贵金属波动跳空多,这类粗聚类在消息行情里漏判概率会明显抬升。 后验计算以索引 0 为「当前证据」,去数某仓位聚类 H 出现后紧接同类的频次,再除以 H 空间。得到的 0.0–1.0 小数乘 100 即落入标准信号区间;多空假设分别由 m_cluster_long / m_cluster_short 指定,理想阈值 >0.5,但略小值偶尔也出意外信号。 下面这段是聚类与后验的核心实现,逐行看:SetCluster 按正负零写第二列聚类标签;GetPosterior 先扫全序列累计 H 次数与紧邻同类次数 _eh,再用贝叶斯比率合成后验。开 MT5 把这两段塞进 CSignalBAYES,接根 EURUSD 日线就能复算。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Function to assign cluster for each data point | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void CSignalBAYES::SetCluster(matrix &Series) { for(class="type">int i = class="num">0; i < class="type">int(Series.Rows()); i++) { if(Series[i][class="num">0] < class="num">0.0) { Series[i][class="num">1] = class="num">0.0; } else if(Series[i][class="num">0] == class="num">0.0) { Series[i][class="num">1] = class="num">1.0; } else if(Series[i][class="num">0] > class="num">0.0) { Series[i][class="num">1] = class="num">2.0; } } } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Function to calculate the posterior probability for each cluster | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double CSignalBAYES::GetPosterior(class="type">int Type, matrix &Series) { class="type">class="kw">double _eh_sum = class="num">0.0, _eh = class="num">0.0, _e = class="num">0.0, _h = class="num">0.0; for(class="type">int i = class="num">0; i < class="type">int(Series.Rows()); i++) { if(Type == Series[i][class="num">1]) { _h += class="num">1.0; if(i != class="num">0) { _eh_sum += class="num">1.0; if(Series[i][class="num">1] == Series[i - class="num">1][class="num">1]) { _eh += class="num">1.0; } } } if(i != class="num">0 && Series[class="num">0][class="num">1] == Series[i][class="num">1]) { _e += class="num">1.0; } } _h /= class="type">class="kw">double(Series.Rows() - class="num">1); _e /= class="type">class="kw">double(Series.Rows() - class="num">1); if(_eh_sum > class="num">0.0) { _eh /= _eh_sum; } class="type">class="kw">double _posterior = class="num">0.0; if(_e > class="num">0.0) { _posterior += ((_eh * _h) / _e); }