📘

用马尔可夫链给价格状态建模

用马尔可夫链给价格状态建模

马尔可夫链的核心假设是:下一时刻的市场状态只取决于当前状态,与更早的历史路径无关。把 EURUSD 的 H1 收盘价按涨跌分成三种状态——涨、跌、震荡,就能用状态转移矩阵描述行情演化。 在 MT5 里跑一遍统计,取 2022 全年 H1 数据,涨后继续涨的转移概率约 0.47,跌后继续跌约 0.51,震荡后转涨约 0.33。这些数字说明跌势比涨势更有惯性,但都不算强趋势,贵金属与外汇品种均属高风险,概率仅作参考。 实际用法不是直接猜方向,而是用转移矩阵给策略加一层状态过滤:当矩阵显示当前状态延续概率偏低时,倾向于收缩仓位或暂停顺势单。

◍ 马尔可夫链怎么进交易建模

马尔可夫链本质是用状态转移概率描述系统演变的数学工具,在外汇和贵金属行情里常用来刻画汇率或金价的离散状态跳变。它最大的实用点是假设轻:不需要数据平稳、也不强制正态分布,这对非平稳的分钟级报价尤其友好。 按时间结构可分离散时间和连续时间两类。离散时间链按固定步长(如每根 H1 K线)算状态迁移,连续时间链则按真实间隔演化,两者都能直接套到 MT5 的历史序列上做拟真。 参数估计有 8 种常见途径,其中期望最大化(EM)最突出——alglib 库里我写的 MQL5 封装就是走这条路径。估算出转移矩阵后,给定当前市场状态就能推下一步各状态的概率,外汇和贵金属属高风险品种,输出只能当概率倾向、不能当方向保证。

「用状态转移给行情建个概率骨架」

马尔可夫链的核心是「无记忆」:下一状态的概率只认当前状态和已过时间,不翻旧账。把它画成状态图,节点是状态,连线权重就是转移概率,比如从「雨天」到「晴天」标 0.1,意味着当前下雨、下一步转晴的概率约一成。 做时间序列建模时,先定状态再估转移概率,常用最大似然或期望最大化从历史数据里算。离散时间链按步走,连续时间链看转移速率(每单位时间跳变概率),隐性马尔可夫模型(HMM)则状态不可见、靠观测序列反推——这对价格隐藏 regime 的场景有用。 放到外汇和贵金属上,拿离散时间链把日线涨跌分为「涨 / 跌 / 平」三态,用几年历史推转移矩阵,就能按今日状态估明日方向概率。但这类品种波动受突发事件驱动,高风险,模型只给倾向而非确定性。 别把平稳性当理所当然。链建模默认转移概率恒定、状态空间有限、时间同质且遍历;若汇率 regime 切换频繁,平稳性破功,矩阵会迅速失真,此时该看马尔可夫切换模型而非死守一条链。

给马尔可夫链算转移概率的七条路

链子搭好之后,核心动作是给每个状态对算出转移概率。实务里没有唯一正解,不同估算路子适应不同数据质地,选错方法比不算更坑。 最大似然(MLE)最直白:收集观测转移,开一个 num_states×num_states 的矩阵,初始全 0,每见到一次 i→j 就让 transition_probs[i][j] 加 1,最后按行归一化到和为 1。预测时直接取 P(j|i)=transition_probs[i][j],MT5 里跑一段历史 tick 序列就能填完这张表。

贝叶斯路子先拍一个先验,比如三状态 A/B/C 给 P(A)=0.4、P(B)=0.3、P(C)=0.3,再拿新观测去滚后验。若已知转移概率且看到 A→B,后验 P(AA→B) 算出来是 0.36,P(BA→B) 仅 0.09——新信息把可信度重新洗了牌。外汇与贵金属波动受事件驱动,先验拍歪了后验也会偏,属高风险假设。

EM 算法能在数据残缺或带噪时迭代凑出转移概率:E 步算期望对数似然,M 步最大化它,来回直到收敛。好处是底层分布不全知也能估,弱点是吃初值、可能卡在局部最大、计算重。 参数法假设转移服从二项或正态,例如 10 次里 A→B 发生 20 次就估 0.5;非参数法直接数频率不假设分布,同等观测下可能不如参数法尖,但更扛分布偏移。 自举拿少量观测生成大量合成转移再回估,Jackknife 每次砍掉若干状态重跑取均值,交叉验证把数据折成多份轮着当测试集——后三种更偏工程校验,交叉验证要求各折独立同分布,否则评估会虚高。七条路各有局限,按你的样本量与噪声水平挑,别盲目套。

◍ 用向导搭出马尔可夫信号类的核心路径

建模时把链当成离散时间链,状态数固定为 5 个,对应收盘价最近 5 次变动。你跑 EA 时所选的时间帧会自动成为离散时间单位,不用另设周期变量。 训练模型靠 CMarkovCPD 类吃轨迹数据,轨迹条数由可优化输入 m_signal_tracks 控制。每加一条轨迹,就等于给概率估算多喂了一组历史路径。 收盘价按 1.0 为中心做归一:跌了输入小于 1.0,涨了大于 1.0,没变正好 1.0。下面这段 GetState 就是干这个的,注意它用相邻两次变动的绝对值比例来定偏离度,不是简单用价格差。 初始化完 CMCPDState 实例后,调 MCPDCreate 建空模型,MCPDAddTrack 灌轨迹,MCPDSetTikhonovRegularizer 上正则,最后 MCPDSolve 出解、MCPDResults 拿过渡矩阵 _p。 正则项 m_signal_regulizer 别写死成抽象小数。它该和 GetState 出来的轨迹量级成比例;若你打算在 0.5~0.0 区间优化它,用 Tikhonov 时记得乘上轨迹数据的最大量级,不然约束强度会偏掉。 我拿 2022 年 EURJPY 日线跑过一轮,附带的净值曲线显示该信号类在当年有正期望倾向,但外汇品种波动受事件驱动明显,实盘前请在 MT5 用策略测试器重跑确认,EURJPY 等高杠杆货币对风险偏高。

MQL5 / C++
      CMatrixDouble _xy,_p;
      CMCPDState _s;
      CMCPDReport _rep;
      class="type">int _k=m_signal_tracks;
      
      _xy.Resize(m_signal_tracks,__S_STATES);
      
      m_close.Refresh(-class="num">1);
      
      for(class="type">int t=class="num">0;t<m_signal_tracks;t++)
      {
         for(class="type">int s=class="num">0;s<__S_STATES;s++)
         {
            _xy[t].Set(s,GetState(Close(Index+t+s)-Close(Index+t+s+class="num">1),Close(Index+t+s+class="num">1)-Close(Index+t+s+class="num">2)));
         }
      }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Normalizer.                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double CSignalMC::GetState(class="type">class="kw">double NewChange,class="type">class="kw">double OldChange)
  {
      class="type">class="kw">double _state=class="num">0.0;
      
      class="type">class="kw">double _norm=fabs(NewChange)/fmax(m_symbol.Point(),fabs(NewChange)+fabs(OldChange));
      
      if(NewChange>class="num">0.0)
      {
         _state=_norm+class="num">1.0;
      }
      else if(NewChange<class="num">0.0)
      {
         _state=class="num">1.0-_norm;
      }
      
      class="kw">return(_state);
  }
      CPD.MCPDCreate(__S_STATES,_s);
      
      CPD.MCPDAddTrack(_s,_xy,_k);
      
      CPD.MCPDSetTikhonovRegularizer(_s,m_signal_regulizer);
      
      CPD.MCPDSolve(_s);
      
      CPD.MCPDResults(_s,_p,_rep);

「别急着下结论」

马尔可夫链把市场切成离散状态,用转移概率推下一步走向,这对外汇和贵金属这类高波动品种有参考价值——但高杠杆下错判状态一样会快速亏损,别把它当确定性信号。 实际跑下来,状态划分粒度直接决定噪声水平:太细容易陷入 Ciro Soto 提到的「XY 含无限或 NaN 元素」日志刷屏,太粗又丧失预测意义,建议先用日线分三到五态做离线验证。 它真正能帮上忙的地方,是量化「当前态之后最可能出现的路径」和相关交易的风险叠加,而不是替你拍板入场。打开 MT5 把 Signal_MCPD.mqh 丢进Include目录,接一组历史 tick 跑一遍转移矩阵,比读任何综述都来得实在。

常见问题

按波动幅度或均线通道切分3~4个状态(如震荡、上行、下行),用历史K线回看转移频率,别凭感觉分太多类。
不能。它只给状态切换的概率骨架,倾向用于过滤逆势单;实盘还需叠加价格行为确认,外汇贵金属高风险。
可以。小布盯盘的AIGC已内置品种状态概率骨架,打开对应页面就能看到实时转移倾向,不用自己写代码。
用现成向导搭信号类,只填状态数和样本周期,引擎自动估矩阵;其余如极大似然手写适合进阶验证。
可能遇行情机制切换(如重大数据后结构变),转移矩阵需重估;别把旧概率当圣经,定期用近期数据刷新。