第12章 价格发现模型(四):状态空间模型与卡尔曼滤波

说实话,前面几章讲的那些模型,都有一个共同的假设——市场结构是稳定的。但做过实盘的人都知道,市场哪有什么稳定可言?波动率会变,流动性会变,甚至连价格发现的主导权都在不同市场间来回切换。

那怎么办?我们需要一个能动态跟踪价格发现过程的工具。这就是我今天要讲的状态空间模型和卡尔曼滤波。

12.1 为什么需要状态空间模型?

先说说我个人的理解。传统的回归模型,比如我们之前用的信息份额模型,它们假设参数是固定的。但现实是,价格发现的过程本身就在变化。

举个例子。我在做美股和港股的双市场交易时发现,白天港股主导价格发现,到了晚上美股开盘,主导权就变了。如果用固定参数模型,你根本抓不住这种切换。

状态空间模型的核心思想很简单:把系统分成两部分——

  • 状态方程:描述不可观测的"真实价格"如何演变
  • 观测方程:描述我们看到的市场价格如何反映这个真实价格

说白了,就是用一个隐藏的"真实价值"来解释所有观测到的价格变动。

12.2 卡尔曼滤波:动态估计的利器

卡尔曼滤波这个名字听起来高大上,其实它的逻辑很朴素:预测 + 修正

你想想看,我们做交易不也是这样吗?先根据历史数据预测下一步价格,然后等新数据来了,修正自己的判断。卡尔曼滤波做的就是这件事,只不过它用数学把整个过程量化了。

我记得第一次在实盘系统里跑卡尔曼滤波时,最让我惊讶的是它的实时性。每来一个tick,它就能更新一次估计,完全不需要重新跑整个历史数据。

核心公式(简化版):
预测步骤:x̂t|t-1 = F·x̂t-1
更新步骤:x̂t = x̂t|t-1 + Kt·(yt - H·x̂t|t-1)
其中 Kt 是卡尔曼增益,它决定了你有多相信新数据。

12.3 状态空间模型在价格发现中的应用

好,理论说完了,咱们看看怎么用。我一般把价格发现的状态空间模型设计成这样:

# 状态方程:真实价格的变化
p_t = p_{t-1} + w_t,    w_t ~ N(0, Q)

# 观测方程:两个市场的价格
y1_t = p_t + e1_t,      e1_t ~ N(0, R1)
y2_t = p_t + e2_t,      e2_t ~ N(0, R2)

这里 p_t 就是那个隐藏的"真实价格"。两个市场的观测价格 y1_t 和 y2_t 都在围绕它波动。波动的大小(R1 和 R2)就反映了每个市场的噪声水平。

嗯,这里要注意:噪声越小的市场,价格发现贡献越大。这个逻辑很直观吧?

12.4 动态价格发现度量

有了状态空间模型,我们就可以定义动态的价格发现度量了。我个人习惯用时变信息份额这个概念。

具体做法是:

  1. 用卡尔曼滤波实时估计每个市场的噪声方差 R1_t 和 R2_t
  2. 计算每个市场的即时信息份额:IS1_t = R2_t / (R1_t + R2_t)
  3. 对时间序列做平滑,得到稳定的动态度量

我曾经在期货跨期套利中用过这个方法。当时发现近月合约和远月合约的价格发现主导权会随着交割日临近而发生变化。用动态度量能提前捕捉到这种切换,比固定参数模型早了将近2个小时。

实战小技巧:
卡尔曼滤波对初始值很敏感。我建议先用一段历史数据做"预热",让滤波器收敛到稳定状态,再开始实时运行。否则前几个tick的估计值可能会很离谱。

12.5 代码实现示例

下面是一个简化的Python实现,展示了如何用卡尔曼滤波做动态价格发现度量:

import numpy as np
from pykalman import KalmanFilter

# 构建状态空间模型
kf = KalmanFilter(
    transition_matrices=[1],      # 状态转移矩阵
    observation_matrices=[[1], [1]],  # 观测矩阵
    initial_state_mean=0,
    initial_state_covariance=1,
    observation_covariance=[[1, 0], [0, 1]],  # 初始噪声方差
    transition_covariance=0.01
)

# 输入两个市场的价格序列
prices = np.column_stack([market1_prices, market2_prices])

# 运行卡尔曼滤波
state_means, state_covs = kf.filter(prices)

# 动态计算信息份额
# 从状态协方差中提取噪声方差
noise_var1 = state_covs[:, 0, 0]  # 简化处理
noise_var2 = state_covs[:, 1, 1]

# 动态信息份额
dynamic_is1 = noise_var2 / (noise_var1 + noise_var2)
dynamic_is2 = 1 - dynamic_is1
避坑指南:
我曾经在参数调优上栽过跟头。卡尔曼滤波的Q和R参数如果设置不当,要么滤波结果太"滑"(过度平滑真实变化),要么太"跳"(对噪声过度反应)。建议用最大似然估计来调参,别用手动试。

12.6 知识体系总览

为了让你更直观地理解这一章的内容,我画了一张结构图:

状态空间模型与动态价格发现 状态空间模型 状态方程:真实价格演变 观测方程:市场价格反映 隐藏变量 → 可观测变量 卡尔曼滤波 预测步骤:先验估计 更新步骤:后验修正 卡尔曼增益:新息权重 动态价格发现度量 时变信息份额 噪声方差实时估计 实战应用场景 跨市场套利 期货跨期价差跟踪 输出:实时价格发现贡献度 + 动态主导权切换信号

12.7 几点补充思考

最后说几个我在实战中踩过的坑:

  • 维度灾难:状态空间模型可以扩展到多个市场,但维度一高,卡尔曼滤波的计算量会暴增。我一般控制在3-4个市场以内。
  • 非线性问题:标准的卡尔曼滤波假设线性关系。如果遇到非线性,可以考虑扩展卡尔曼滤波(EKF)或无迹卡尔曼滤波(UKF)。
  • 参数漂移:即使用了动态模型,Q和R矩阵本身也可能随时间变化。我有时会加一个"遗忘因子",让模型自动适应参数变化。

状态空间模型和卡尔曼滤波的组合,是我个人认为目前处理动态价格发现最优雅的方案。它不假设市场是静止的,而是承认市场在变,然后去跟踪这种变化。这种思路,其实比那些追求"完美参数"的静态模型要务实得多。