在MetaTrader 5中集成隐马尔可夫模型(基础篇)
📘

在MetaTrader 5中集成隐马尔可夫模型(基础篇)

第 1/3 篇

在 MT5 里跑通隐马尔可夫模型

隐马尔可夫模型(HMM)把价格序列看成由若干隐藏状态生成,状态之间按概率跳转,观测值(如收益率)服从各状态自己的分布。在 MT5 里接这套东西,核心不是预测点位,而是给当前行情贴一个『状态标签』——震荡、趋势、过渡,三种机制的概率分布会随新 tick 滚动更新。 外汇与贵金属杠杆高、跳空频繁,HMM 给出的状态只是概率倾向,不能当确定性信号;实盘前务必在策略测试器用 2020—2023 年 EURUSD M15 跑一遍滤波效果。 下面这段代码在 OnTick 里维护一个两状态 HMM 的转移矩阵,并用简单对数收益更新发射概率。可直接拷进 EA 模板验证:状态 0 倾向低波动,状态 1 倾向趋势延展,转移概率初值设 0.95 对角,意味着状态有惯性。

MQL5 / C++
class="type">class="kw">double TransMat[class="num">2][class="num">2] = {{class="num">0.95,class="num">0.05},{class="num">0.05,class="num">0.95}}; class=class="str">"cmt">// 状态转移矩阵初值
class="type">class="kw">double EmitProb[class="num">2][class="num">2] = {{class="num">0.6,class="num">0.4},{class="num">0.4,class="num">0.6}}; class=class="str">"cmt">// 观测发射概率
class="type">int curState = class="num">0; class=class="str">"cmt">// 当前隐藏状态
class="type">void OnTick(){
   class="type">class="kw">double ret = MathLog(iClose(_Symbol,_Period,class="num">0)/iClose(_Symbol,_Period,class="num">1)); class=class="str">"cmt">// 对数收益
   class="type">int obs = (ret > class="num">0) ? class="num">1 : class="num">0; class=class="str">"cmt">// 观测值二值化
   class="type">class="kw">double p0 = TransMat[curState][class="num">0]*EmitProb[class="num">0][obs]; class=class="str">"cmt">// 留原状态似然
   class="type">class="kw">double p1 = TransMat[curState][class="num">1]*EmitProb[class="num">1][obs]; class=class="str">"cmt">// 跳状态似然
   curState = (p1 > p0) ? class="num">1 : class="num">0; class=class="str">"cmt">// 最大似然状态更新
}

◍ 金融序列的记忆与隐马尔可夫建模

金融时间序列最麻烦也最有用的地方,是它内部存在依赖结构:过去的价格状态会渗透进当前和未来的波动里,这种特性在时序分析里叫记忆性。搞清一段行情属于短记忆还是长记忆,直接决定你后面该套 ARMA 还是该上状态切换类模型。 本文换了一个角度谈记忆——不是线性自回归那种显式依赖,而是以隐马尔可夫模型(HMM)承载的『隐藏状态记忆』。市场在某个不可观测的 regimes(如趋势/震荡)里跳转,能观测到的报价只是这些隐藏状态的投影。 我们会拆 HMM 的基本假设,并用 Python 的 hmmlearn 先跑通训练,再把学到的模型参数导出,交给 MT5 里的 MQL5 程序做实时推断。外汇与贵金属杠杆高、跳空频繁,隐藏状态切换模型只降低不确定性,不消除爆仓风险,参数要自己回测。

「Hidden Markov Model 怎么吃进价格序列」

隐马尔可夫模型(HMM)给时间序列建模时,核心假设是系统运行在肉眼不可见的隐藏状态里,而当前时刻落在某状态的概率只跟上一时刻的状态有关——这条链式依赖就是它的记忆。放到外汇或贵金属的分钟线里,隐藏状态可以对应上涨、下跌或区间震荡三种倾向,用来压住均线类指标常被噪声带出的锯齿假信号。 建模前你要先拍定状态总数 S,把状态从 0 编到 S-1,再准备一组能描述过程的观测特征。以 XAUUSD 收盘价为例,单丢收盘价不够,得把与之相关的波动率、动量类辅助量一起塞进观测向量,才容易让隐藏状态分得开。 HMM 完整由四件东西钉死:假设状态数、首根 K 线落各状态的初始概率、状态间跳转的转移矩阵、以及每个状态自己的概率密度函数。转移矩阵里每个元素就是“从状态 i 滑到状态 j”的概率,直接决定趋势切换的黏性。 参数不是手填的,是用最大似然估计从样本里反推出来的:正向算法按时间往前扫、反向算法从尾往回扫,两者合起来算每根样本在特定时刻处于某状态的可能性,逼出最贴合当前数据的那组模型属性。MT5 里拿历史数据跑一遍前向—后向递推,就能看见转移矩阵随品种波动率的明显差异。

从初始概率到转移矩阵的前向递归

做隐马尔可夫建模时,第一个样本的似然不能直接套用后续规则。若对过程毫无先验,把初始状态概率统一设成 1/S(S 为假设状态总数)是可接受的做法,再用贝叶斯定理把“处于状态 i 的似然”和“已知前序样本时处于 i 的概率”区分开。 第一个样本按条件概率 P(A)=P(A|B)P(B) 算:保持状态 i 的似然 = 该状态初始概率 × 第一个样本的概率密度函数(文献里叫发射概率,现阶段只当试验参数)。因为我们不确定到底在哪个状态,初始似然必须是所有可能状态似然之和。 后续观测要叠一层状态间跳转可能。转移矩阵是 S×S 结构,每行概率和为 1、列不要求;行索引是“从哪状态转出”,列索引是“转到哪状态”,对角线就是状态不变的概率。下一个特定状态的概率 = 当前已知状态概率 × 对应转移概率,再把所有可能来源加总。 把每个样本个体似然连乘,得到整段数据的似然。这套按时间向前递归的计算就是正向算法,外汇与贵金属序列用它估状态转移时,样本不足易过拟合,属高风险建模。

◍ 把似然度倒着算一遍

正向算法是从第一个样本往后推状态概率,反向算法反过来:从最后一个数据点起步,先把所有状态的似然度初始化为 1,再向前逐个样本回推。每一步都站在「当前若处于某状态」的假设上,去算后续样本集合的似然度,同时把状态间可转移的可能性一并摊进去。 具体做法是拿每个状态的似然度做加权和——权重由「处于该状态的概率」乘「样本落在该状态的概率密度」构成,再用当前状态跳去下一状态的概率当调节系数。公式里这一层加权把转移结构反向织进了似然估计,和正向版本对称但方向相逆。 在 MT5 里验证这类递推,最直接的是写个小脚本把最后一帧 alpha 置 1,循环到 t=0 打印每帧似然,看是否和正向乘出来的一致。外汇与贵金属价格序列用隐状态建模本身高风险,回测吻合不等于实盘可用。

「发射概率背后藏着的分布假设」

聊到 HMM 的正向、返向算法,绕不开概率密度函数(pdf)——它在模型里就是发射概率。离散或分类数据下,这部分直接叫概率;一旦处理连续变量,就得换成概率密度函数来描述。 本文建模用的是多元正态分布的连续数据集,但分布本身不是锁死的,后续 Python 模块里就带了给其他分布写的 HMM 实现。 所以你选了什么分布,它的参数就自动变成 HMM 的参数。拿多元正态来说,落地的就是均值向量和协方差矩阵这两组数,调模型本质就是在调它们。

常见问题

用来推断价格背后无法直接看到的趋势状态(如震荡、单边),通过观测价格序列反推隐状态概率,辅助识别当前所处市况。
先对价格做收益率转换并标准化,再离散化为有限观测符号,否则连续值无法直接套用离散发射概率假设。
可以,小布盯盘的 AIGC 已内置该类状态推断,打开对应品种页即可看到隐状态诊断,不用自己写前向递归。
不一定,似然度低可能只是初始参数粗糙或序列太长导致下溢,建议对数化并多跑几组初始矩阵对比。
会,贵金属高风险且常出现肥尾跳空,纯正态假设易低估极端移动,可换用 t 分布或混合分布更稳。