基于隐马尔可夫模型的趋势跟踪波动率预测·综合运用
「用隐马尔可夫状态卡住波动率空窗」
把标准化后的波动率塞进长度 50 的 obs[] 数组,对应 y₁ 到 y₅₀;隐含状态只取 0 或 1,分别代表聚类出来的低波动 / 高波动抽象态。这俩标签来自前期 Python 聚类的产物,Python 侧只做聚类和转移特征提取,不解释业务含义。 初始 x₁ 若懒得算平稳分布,可直接把初始向量拍成 [0.5, 0.5],即两态等权。训练完 HMM 后,用贝叶斯定理把 50 步里所有马尔可夫链路径的概率算一遍,取末尾 x₅₀ 的最大后验估计作为当前状态。 实盘里每根收盘 K 线重算一次隐含状态,只有 currentState==1 才放行均线交叉的入场。下面这段 IsVolatilityFilled 就是硬卡点:缓冲区没攒满 50 个非零波动率直接退出,避免用半截数据瞎推状态。 外汇与贵金属杠杆高、滑点跳空频繁,状态为 1 仅代表模型倾向高波动环境,不预示方向,真跑之前先在 MT5 策略测试器用历史数据验证缓冲填充节奏。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check Volatility is filled Function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool IsVolatilityFilled(){ class="type">bool volatility_filled = true; for(class="type">int i = class="num">0; i < class="num">50; i++){ if(volatility[i] == class="num">0){ volatility_filled = false; break; } } if(!volatility_filled){ Print("Volatility buffer not yet filled."); class="kw">return false; } else class="kw">return true; } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class="type">int bars = iBars(_Symbol,PERIOD_CURRENT); if (barsTotal!= bars){ barsTotal = bars; class="type">class="kw">double maFast[]; class="type">class="kw">double maSlow[]; class="type">class="kw">double ma[]; GetVolatility(); if(!IsVolatilityFilled()) class="kw">return; class="type">int currentState = PredictCurrentState(volatility); CopyBuffer(handleMaFast,BASE_LINE,class="num">1,class="num">2,maFast); CopyBuffer(handleMaSlow,BASE_LINE,class="num">1,class="num">2,maSlow); CopyBuffer(handleMa,class="num">0,class="num">1,class="num">1,ma); class="type">class="kw">double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); class="type">class="kw">double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); class="type">class="kw">double lastClose = iClose(_Symbol, PERIOD_CURRENT, class="num">1); class=class="str">"cmt">//The order below matters if(buypos>class="num">0&& lastClose<maSlow[class="num">1]) trade.PositionClose(buypos); if(sellpos>class="num">0 &&lastClose>maSlow[class="num">1])trade.PositionClose(sellpos); if (maFast[class="num">1]>maSlow[class="num">1]&&maFast[class="num">0]<maSlow[class="num">0]&&buypos ==sellpos&¤tState==class="num">1)executeBuy(); if(maFast[class="num">1]<maSlow[class="num">1]&&maFast[class="num">0]>maSlow[class="num">0]&&sellpos ==buypos&¤tState==class="num">1) executeSell(); }
持仓票据失效的兜底清零
EA 在轮询中持有 buypos / sellpos 两张ticket,但隔了若干根 K 线后,这两张单可能已被平台回收或魔法码对不上。上面这段逻辑就是给它们做失效兜底:只要选不中票据,或者选中的仓位魔法码不等于本 EA 的 Magic,就把对应变量归零。 归零后下一轮开仓判断才会重新走筛选,避免拿着一个早已不存在的 ticket 去调仓。实盘里若 Magic 设成 888888 而历史单是别的 EA 开的,这段不写就会误判持仓状态。 外汇与贵金属杠杆高,ticket 状态错乱可能触发重复下单,回测看不出、实盘才爆。开 MT5 把这段塞进你的持仓管理函数,跑一遍模拟盘观察 buypos 归零时机。
if(buypos>class="num">0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ buypos = class="num">0; } if(sellpos>class="num">0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){ sellpos = class="num">0; } }
◍ HMM过滤器在XAUUSD上的回测表现
用2020.1.1–2024.1.1的样本内数据训练模型后,直接在2024.1.1–2025.1.1的XAUUSD H1周期上做样本外测试,并与未整合HMM的基准策略对照。 集成HMM过滤器的EA砍掉了约70%的交易信号,利润因子从基准的1.48抬到1.73,夏普比率也更高,说明这套隐马尔可夫滤波在方向筛选上确有概率优势,不是纯过拟合噪声。 若换成滚动回测——自2004年起每年用前4年重训、测后1年,把所有年度资金曲线拼起来,长期轮廓如下:盈利已经跑出来,但最大回撤和胜率还有明显打磨空间。外汇与贵金属杠杆高,这类回测结论只代表历史概率,实盘可能偏离。
Profit Factor: class="num">1.10 Maximum Drawdown: -class="num">313.17 Average Win: class="num">11.41 Average Loss: -class="num">5.01 Win Rate: class="num">32.56%
Profit Factor: <span class="number">class="num">1.10</span> Maximum Drawdown: -<span class="number">class="num">313.17</span> Average Win: <span class="number">class="num">11.41</span> Average Loss: -<span class="number">class="num">5.01</span> Win Rate: <span class="number">class="num">32.56</span>%
「隐马尔可夫在波动过滤里的真实短板」
把 RNN 和 HMM 摆在一起比,结论先说清楚:HMM 实现和解释成本明显更低,参数含义透明,不会掉进「黑箱」里说不清。它对样本量极不挑剔,几十根 K 线就能估出参数,过拟合天然比深层网络温和。 但代价是硬伤。马尔可夫假设波动转移无记忆,而真实外汇和贵金属行情普遍存在路径依赖,这一条假设和盘面本能是拧着的。原文用 50 周期滚动波动率均值当每根新 K 线的观测值,又和定义的「高/低波动」隐藏状态强相关,结果就是预测显著性被自己稀释掉——大概率换个省钱观测值也能筛出类似信号。 学术圈共识是机器学习更适合做波动率预测而非价格预测,这点对外汇黄金交易者尤其要记牢:杠杆市场里波动误判就是本金回撤,高风险不是口号。 后续能立刻动手的只有两件事:改隐藏状态的定义逻辑(别只切高/低两档),以及把隐含状态数量往上加,看 MT5 回测里滤波命中率是否真的变厚。
别急着下结论
这套 HMM 趋势跟踪框架跑通后,最该警惕的是把回测里的状态切换当成市场真理。作者在 MT5 里用 HMM Test.mq5 做交易 EA,配 Classic Trend Following.mq5 当基准,OHLC Getter.mq5 抓数据、FileCSV.mqh 落盘,再丢进 rollingBacktest.ipynb 训模型,整套链路在 XAUUSD 等高波动品种上只是「可能」改善夏普,绝非稳赢。 外汇与贵金属杠杆高、滑点诡异,任何机器学习信号在实盘都该先开 MT5 用历史中心逐根验证,而不是信任那 45.1 KB 的 ZIP 包能直接印钞。 真要落地,先把 HMM Test.mq5 里隐状态数从 2 调到 3 跑一遍,观察波动率聚类是否更贴合你盯的时段——这一步比读十篇综述都实在。