基于马尔可夫链的矩阵预测模型(基础篇)
📘

基于马尔可夫链的矩阵预测模型(基础篇)

第 1/3 篇

用马尔可夫链把市场拆成状态转移

传统统计在外汇和贵金属这种高波动品种上经常失灵,神经网络又黑箱难解释。中间路线是概率模型:假设当前价格状态已经隐含了历史路径信息,市场只是在若干离散状态之间跳来跳去。 这套思路把行情建模成状态转移系统,靠技术指标、周期和成交量的组合来定义状态。MT5 上做这类实验,本质就是先离散化价格,再统计转移频率。 原文作者提到,模型把概率论的简洁和机器学习的实用揉在一起,认为市场看似随机,实则通过技术组合露出规律。外汇/贵金属杠杆高、跳空频繁,这类概率模型只能给出倾向性参考,实盘前务必在 MT5 策略测试器里跑历史数据验证。

「马尔可夫性如何喂饱了华尔街模型」

安德烈·马尔可夫在20世纪初给出的那个想法很朴素:系统下一刻去哪,只跟现在有关,不翻旧账。这种“无记忆”特性后来被叫作马尔可夫性,它绕开了历史路径依赖,让建模者只用当前状态就能推下一步,成了量化金融里一大票随机过程模型的底层假设。 把状态想成空间里的点,马尔可夫链就是按概率在这些点之间跳的系统。它的漂亮之处在于,用一组转移概率就能描述看似混乱的价格游走,复杂过程被压成了可计算的矩阵运算。 数学上,链由转移矩阵 P 定义,P(i,j) 是从状态 i 跳到 j 的概率。核心递推只有一行: π(t+1) = π(t) · P 这里 π(t) 是 t 时刻各状态的概率向量。在 MT5 里你可以把 K 线状态离散成涨/跌/平,用历史数据估出 P,再拿 π(t) 乘一遍看下一步分布倾向——外汇与贵金属波动受杠杆与事件驱动,高风险,矩阵平稳分布不等于行情必然收敛。

MQL5 / C++
π(t+class="num">1) = π(t) · P

◍ 离散框架之外的连续与隐状态建模

经典马尔可夫链用离散状态和离散时间,适合把价格区间、交易时段这类东西切成格子来算转移概率。但它不是只管离散,理论里也含连续过程,维纳过程就是典型——它描述布朗运动,也是 Black-Scholes 期权定价公式的底层的数学假定。 隐马尔可夫模型(HMM)往前走了一步:真实状态看不见,只能靠间接信号反推。这跟盘面很对味,所谓“趋势”或“震荡”从来不是行情软件直接打印出来的,得从价格和成交量里间接认。 弱式有效市场假说讲历史价没法预测未来,这等价于默认价格序列有马尔可夫性。学界吵它完不完全成立,但实证里马尔可夫近似在不少实际问题上的精度出乎意料。 在 MT5 上能落的方向很实:用历史状态转移统计押后续方向、自动分趋势/横盘/过渡、按状态切策略参数、用当前状态和转移概率估大波动可能。外汇和贵金属波动杠杆高,这类概率结论只作参考,实盘须防极端跳空。

用转移矩阵把行情状态代数化

马尔可夫模型落进图表里,核心就是一张转移矩阵:行是当前状态,列是下一状态,格子里填的是对应跳转概率。把行情切成 n 个状态后,矩阵就是 n×n,而且每一行加总必须等于 1——因为价格下一根 K 线总得落在某个状态里,不可能凭空消失。 这套框架真正好用之处在于能迭代。从状态 i 走 k 步到状态 j 的概率,直接查 P 的 k 次幂里对应元素就行。实操中拿 MT5 导出的状态序列算 P^2、P^3,就能推两三步后的偏向;但步长一拉长,边缘概率会被摊平,远程预测基本只剩模糊倾向。 更值得盯的是 k 趋近无穷时的极限。满足遍历性(任意状态有限步可达其余状态)的链存在唯一平稳分布 π*,解 π* = π*·P 即可。它意味着无外部冲击时,市场在各状态停留的时间占比长期锁死,这算是价格行为里少数能用数学钉死的结构特征。外汇和贵金属波动受事件驱动强,这套分布随时可能被黑天鹅打穿,只能当概率骨架而非铁律。

MQL5 / C++
π* = π* · P

「状态聚类与转移矩阵的实际训练路径」

把马尔可夫模型搬进 MT5 做行情建模,先得解决两件事:状态怎么切、转移概率怎么估。状态切分常见三条路——分析师按阈值手划、K-means 等算法自动聚类、把连续指标离散化再组合。我们对价格、时间、成交量分别跑 K-means,既留了可解释性,也能从数据里直接抽特征。 转移概率靠历史频次统计:扫一遍序列,状态 i 跳到状态 j 的次数除以 i 的总出现次数,就是对应转移权重。罕见跳转若样本太少,估计会飘,简单做法是加伪计数,或者上贝叶斯先验把稀疏项拉平滑。 下面这段是训练核心的简化实现:每组特征独立聚类,再沿状态序列累加跳转、最后按行归一。注意 n_clusters_per_group=3 时,若你喂了价格/时间/成交量三组,状态空间会到 3×3×3=27 维,矩阵归一循环写死 range(9) 只适配单组 3 簇,多组得改维度。外汇与贵金属波动受事件驱动,状态迁移高频跳变,实盘前请用足够样本回测,转移估计可能随品种周期漂移。

MQL5 / C++
<span class="keyword">def</span> create_state_clusters(feature_groups, n_clusters_per_group=<span class="number">class="num">3</span>):
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">for</span> group_name, group_data <span class="keyword">in</span> feature_groups.items():
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> group_name != <span class="class="type">class="kw">string">&class="macro">#x27;all&class="macro">#x27;</span>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kmeans = KMeans(n_clusters=n_clusters_per_group, random_state=<span class="number">class="num">42</span>, n_init=<span class="number">class="num">10</span>)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clusters = kmeans.fit_predict(group_data[<span class="class="type">class="kw">string">&class="macro">#x27;data&class="macro">#x27;</span>])
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;group_clusters[group_name] = clusters
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kmeans_models[group_name] = kmeans
<span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="built_in">len</span>(states) - <span class="number">class="num">1</span>):
&nbsp;&nbsp;&nbsp;&nbsp;curr_state = states[i]
&nbsp;&nbsp;&nbsp;&nbsp;next_state = states[i + <span class="number">class="num">1</span>]
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># Increase the transition counter</span>
&nbsp;&nbsp;&nbsp;&nbsp;transition_matrix[curr_state, next_state] += <span class="number">class="num">1</span>
&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment"># If the next candle is bullish, increase the rise counter</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> i + <span class="number">class="num">1</span> &lt; <span class="built_in">len</span>(labels) <span class="keyword">and</span> labels[i + <span class="number">class="num">1</span>] == <span class="number">class="num">1</span>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rise_matrix[curr_state, next_state] += <span class="number">class="num">1</span>
<span class="comment"># Normalization of the transition matrix</span>
<span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">class="num">9</span>):
&nbsp;&nbsp;&nbsp;&nbsp;row_sum = np.<span class="built_in">sum</span>(transition_matrix[i, :])
&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">if</span> row_sum &gt; <span class="number">class="num">0</span>:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state_transitions[i, :] = transition_matrix[i, :] / row_sum

常见问题

先看价格序列是否近似平稳、波动有重复节律;拿近3个月小时线做状态聚类,若相邻状态转移概率集中度高(如某转移>60%),才值得建矩阵。
算。跳空让隔日开盘脱离前收状态,建模时应把跳空单独设为一类状态,或剔除重大数据时段样本,否则转移矩阵会系统性偏误。
可以。小布盯盘的AIGC已内置状态聚类与矩阵训练,打开对应品种页即可看到近期转移概率热图,不用自己写代码跑数据。
HMM能抓看不见的 regime,连续型免去了硬切状态的主观阈值;但训练成本高,散户用离散矩阵做日线级别概率参考已够用。
差挺大。1000根易受单段趋势污染,5000根以上状态覆盖更全;建议滚动窗口训练,每月重算一次避免结构漂移。