@RuujSs: https://x.com/RuujSs/status/2069430225801490602
摘要
一本全面指南,介绍卡尔曼滤波器及其在构建更智能交易系统中的应用,包括数学基础和可用于生产环境的示例。
查看缓存全文
缓存时间: 2026/06/24 12:23
如何利用卡尔曼滤波器构建更智能的交易系统(完整框架)
NASA用它导航登月。量化基金用它导航市场。下面详解其工作原理及构建方法。
问题描述简单,解决起来却很难:你要追踪一个会移动的东西——航天器、信号、动态系统中的隐藏状态。你对那个事物的测量是带噪声的,每次观测都含有随机误差。如何从一连串有噪观测中实时提取真实状态,并在每个新数据点到来时立即利用它?
NASA读了那篇论文后立刻将其投入实践。卡尔曼滤波器为阿波罗任务导航到月球。它处理噪声雷达读数,估计航天器的真实位置和速度,并在新传感器数据到达时持续更新这些估计。无需批处理,无需历史回看窗口。纯粹递归更新——每次新观测都使估计更加精确。
市场面临完全一样的问题。
两个资产之间的真实对冲比率是隐藏的。价格噪声之下的真实趋势是隐藏的。两个协整资产之间的关系随时间缓慢演变,无法直接测量。你观察到的是每个时间点上带有噪声的市场价格。卡尔曼滤波器是从有噪观测中估计隐藏状态的数学最优工具,并且它会随着新数据不断更新。
https://x.com/RuujSs/status/2066545926467174765?s=20
如果你还没有读过配对交易那篇文章,建议你先读一读,因为本文直接建立在其基础之上。卡尔曼滤波器正是把这个框架从“不错”提升到“生产级”的关键。建议先理解配对交易。
《投资组合优化》一书(剑桥大学出版社,2025年出版)在真实配对数据上测试了多种估计方法后,得出了一个明确的结论:“卡尔曼滤波在配对交易中是必需的。” 滚动OLS在同一对资产上产生的对冲比率估计值在0.6到1.2之间波动,而卡尔曼滤波器稳定在0.55到0.65之间。这个差异不是装饰性的——它决定了价差是平稳可交易的,还是带噪且不可靠的。
注意:本文构建了完整框架。包括滤波器的实际工作原理、全部数学推导,以及三个具体的生产级应用。请按顺序阅读——每一章都与下一章紧密相连。
第一章:在数学公式之前,先理解思想
在数学公式之前,先理解思想。因为思想比公式更重要,而大多数解释都本末倒置了。
你想知道一个系统的真实状态,但无法直接测量。你只能观测到与真实状态相关的测量值,而这些测量值含有噪声。每个时刻,你都有两个信息源:
你的模型: 根据系统演化规律对状态做出的预测。这个预测带有不确定性,因为系统的变化你无法完全预知。
你的测量: 传感器告诉你的当前状态值。这也带有不确定性,因为测量有噪声。
问题是:给定这两个不完美的信息源,对真实状态的最佳可能估计是什么?
卡尔曼滤波器给出了最优答案。它将预测和测量结合起来,根据各自的相对可靠性进行加权。当测量噪声大(高测量方差 R)时,更信任模型预测;当模型不确定性高(高过程方差 Q)时,更信任新测量值。赋予新测量值的权重——卡尔曼增益 K——会根据当前不确定性水平在每个步骤自动更新。
这不是近似。对于线性系统和高斯噪声,它是可证明的最优估计器。没有其他方法能从现有数据中提取更多信息。
在交易中,你关心的隐藏状态包括:此刻两个资产之间的真实对冲比率,噪声日价格之下的真实趋势,两个相关工具之间随时间变化的关系。测量值则是你观察到的市场价格。
每个时间点执行两个步骤:
预测: 使用模型将当前状态估计向前推进一步。不确定性增加,因为自上次观测以来状态可能已经改变。
更新: 结合新测量来修正预测。不确定性减少,因为你获得了新信息。
预测、更新、重复。K决定新测量的可信程度。
预测、更新、重复。K决定新测量的可信程度。
预测、更新。预测、更新。
这个循环就是整个算法。它递归运行,实时进行,不需要历史批处理。
第二章:从零构建的数学原理
滤波器工作在一个状态空间模型中。两个方程定义了完整系统。
状态转移方程:
x_t = F × x_{t-1} + w_t
隐藏状态 x_t 通过转移矩阵 F 从前一状态演化而来。w_t 是过程噪声——模型无法预料的真实状态随机变化。过程噪声的协方差矩阵为 Q。
观测方程:
y_t = H_t × x_t + v_t
可观测的测量值 y_t 通过观测矩阵 H_t 与隐藏状态关联。v_t 是测量噪声——真实状态与你观测值之间的差异。测量噪声的方差为 R。
对于配对交易,这些抽象量直接映射到具体变量:
y_t : 时间 t 时资产 P1 的观测价格。
x_t : 隐藏状态向量 [β_t, μ_t]:你试图估计的对冲比率和截距。
H_t : 行向量 [P2_t, 1]:第二资产的价格和一个常数项。
F = I : 单位矩阵,因为对冲比率遵循随机游走。
Q : 过程噪声协方差,控制 β 允许变化的速度。
R : 测量噪声方差,控制你对每次价格观测的信任程度。
在每一步执行的七个滤波器方程:
预测步骤:
x_{t|t-1} = F × x_{t-1|t-1} (状态预测)
P_{t|t-1} = F × P_{t-1|t-1} × F’ + Q (不确定性预测)
新息(新测量值告诉你的信息):
e_t = y_t − H_t × x_{t|t-1} (预测误差)
S_t = H_t × P_{t|t-1} × H_t’ + R (新息方差)
卡尔曼增益(新测量值的最优权重):
K_t = P_{t|t-1} × H_t’ / S_t
更新步骤:
x_{t|t} = x_{t|t-1} + K_t × e_t (状态更新)
P_{t|t} = (I − K_t × H_t) × P_{t|t-1} (不确定性更新)
对交易直接重要的三个输出:
x_{t|t} :更新后的对冲比率和截距估计。这是你对两个资产之间真实关系的最佳当前估计。
e_t :预测误差。P1 实际价格与你根据当前对冲比率估计预测值之间的差距。这就是你的价差信号。
S_t :新息方差。用 √S_t 标准化 e_t 可得到 Z 分数,它会自动根据对冲比率的当前不确定性进行调整。当滤波器不确定时,阈值扩大;当它确信时,阈值收紧。
卡尔曼增益 K_t 是值得直观理解的机制。当 S_t 很大(新息高度可变,测量相对于模型不可靠)时,K_t 很小,滤波器保守更新,更信任先验状态估计。当 S_t 很小(测量相对于模型不确定性更精确)时,K_t 很大,滤波器积极向新观测接近。这种自动平衡正是滤波器最优性的来源。
第三章:动态对冲比率——核心应用
交易中的第一个也是最重要的应用是配对策略中的动态对冲比率估计。在我之前发表的配对交易文章中,滚动 OLS 是基线方法,但它有已知的缺点:回看窗口是一个任意的自由参数,窗口滚动时估计值会跳跃式变化,对冲比率可能在没有实际关系变化的情况下摆动 50% 或更多。卡尔曼滤波器同时解决了所有三个问题:没有回看窗口,没有不连续过渡,不确定性连续适应。
import numpy as np
import pandas as pd
def kalman_hedge_ratio(p1, p2, delta=1e-4, R_noise=1.0):
orig_index = p1.index if isinstance(p1, pd.Series) else pd.RangeIndex(len(p1))
p1 = np.array(p1, dtype=float)
p2 = np.array(p2, dtype=float)
n = len(p1)
state = np.array([1.0, 0.0])
P = np.eye(2)
Q = (delta / (1 - delta)) * np.eye(2)
R = float(R_noise)
beta = np.zeros(n)
intercept = np.zeros(n)
e = np.zeros(n)
S = np.zeros(n)
P_trace = np.zeros(n)
for t in range(n):
H = np.array([p2[t], 1.0])
P = P + Q
e[t] = p1[t] - float(H @ state)
S[t] = float(H @ P @ H) + R
K = (P @ H) / S[t]
state = state + K * e[t]
P = (np.eye(2) - np.outer(K, H)) @ P
beta[t] = state[0]
intercept[t] = state[1]
P_trace[t] = float(np.trace(P))
spread = p1 - beta * p2 - intercept
return (
pd.Series(beta, index=orig_index),
pd.Series(intercept, index=orig_index),
pd.Series(spread, index=orig_index),
pd.Series(e, index=orig_index),
pd.Series(S, index=orig_index),
pd.Series(P_trace, index=orig_index),
)
正确设置 delta
Delta 控制滤波器中最重要的行为:对冲比率允许变化的速度。过程噪声协方差 Q = δ/(1-δ) × I 直接设定这一点。对于股票对(KO-PEP, EWA-EWC),其基本面关系稳定但缓慢演变,delta 范围在 1e-5 到 1e-4 之间效果很好——滤波器缓慢平滑地更新对冲比率。对于加密货币对,关系变化更快,delta 在 1e-3 到 1e-2 左右更合适。关键洞察:与滚动 OLS 的回看窗口(没有直接解释)不同,delta 具有物理意义——它是你对真实对冲比率每日方差的先验信念。
使用滤波器输出作为交易信号
预测误差 e_t 和新息方差 S_t 不仅仅是诊断指标。它们就是信号。用 √S_t 标准化可得到等效的 Z 分数:
def kalman_zscore(e, S):
e = pd.Series(e)
S = pd.Series(S)
return e / np.sqrt(S)
相对于简单滚动 Z 分数的优势:标准化是自适应的。当 P 很大(滤波器对当前对冲比率不确定)时,S_t 较大,Z 分数阈值有效放宽。你需要更大的实际偏差才能在不确定性高时产生信号。当 P 很小(滤波器确信)时,S_t 较小,Z 分数更敏感。滤波器自身的不确定性自动校准了信号的灵敏度。
生成和回测交易
def kalman_pairs_backtest(p1, p2, delta=1e-4, entry_z=1.0, exit_z=0.0, cost_bps=10):
p1 = pd.Series(p1)
p2 = pd.Series(p2)
beta, intercept, spread, e, S, P_trace = kalman_hedge_ratio(p1, p2, delta)
zscore = kalman_zscore(e, S)
position_vals = [0.0] * len(zscore)
current = 0.0
for i in range(1, len(zscore)):
z = zscore.iloc[i]
if current == 0.0:
if z > entry_z:
current = -1.0
elif z < -entry_z:
current = 1.0
elif current == -1.0:
if z < exit_z:
current = 0.0
elif current == 1.0:
if z > -exit_z:
current = 0.0
position_vals[i] = current
position = pd.Series(position_vals, index=zscore.index)
spread_vol = spread.rolling(63).std().bfill()
ret = position.shift(1) * spread.diff() / spread_vol
cost = position.diff().abs() * (cost_bps / 10000)
ret_net = ret - cost
std = ret_net.std()
sharpe = ret_net.mean() / std * np.sqrt(252) if std > 0 else 0.0
cum = (1 + ret_net).cumprod()
max_dd = ((cum - cum.cummax()) / cum.cummax()).min()
print(f"年化夏普比率 : {sharpe:.4f}")
print(f"最大回撤 : {max_dd:.4f}")
print(f"年化收益 : {ret_net.mean() * 252:.4f}")
print(f"平均价差标准差 : {np.sqrt(S).mean():.4f}")
return ret_net, position, zscore, beta, spread
这就是 2020 年 3 月两只真实 ETF 实际发生的情况
这就是 2020 年 3 月两只真实 ETF 实际发生的情况
关于入场阈值的说明:直接使用卡尔曼 Z 分数时,阈值自然低于使用滚动 OLS 时典型的 z=2.0。在生产级的基于卡尔曼的配对实现中,入场 z=1.0 很常见,因为用 √S_t 标准化已经考虑了不确定性——当不确定性升高时,原始价差单位的有效阈值实际上更高。这在 QuantConnect 的生产实现(为 300 多家对冲基金提供支持)中有文档说明。
第四章:价格趋势滤波——将信号与噪声分离
第二个应用是趋势滤波。每个价格序列都是真实趋势信息与短期噪声的混合体。移动平均试图通过对近期观测加权来分离它们。卡尔曼滤波器则从根本上有所不同——它显式地建模噪声并估计真实底层状态。
将状态设置为两个分量:当前价格水平及其速度(变化率)。转移模型说下一个水平等于当前水平加上当前速度。这就是物理学中的恒速模型。
def kalman_trend_filter(prices, Q_level=1e-4, Q_velocity=1e-5, R_obs=1e-2):
orig_index = prices.index if isinstance(prices, pd.Series) else pd.RangeIndex(len(prices))
prices = np.array(prices, dtype=float)
n = len(prices)
state = np.array([prices[0], 0.0])
P = np.eye(2)
F = np.array([[1.0, 1.0], [0.0, 1.0]])
H = np.array([1.0, 0.0])
Q = np.diag([Q_level, Q_velocity])
R = float(R_obs)
level = np.zeros(n)
velocity = np.zeros(n)
for t in range(n):
state = F @ state
P = F @ P @ F.T + Q
e = prices[t] - float(H @ state)
S = float(H @ P @ H) + R
K = (P @ H) / S
state = state + K * e
P = (np.eye(2) - np.outer(K, H)) @ P
level[t] = state[0]
velocity[t] = state[1]
return (
pd.Series(level, index=orig_index),
pd.Series(velocity, index=orig_index),
)
价格告诉你它去过哪里。速度告诉滤波器认为它要去哪里。
价格告诉你它去过哪里。速度告诉滤波器认为它要去哪里。
速度分量可以直接用于交易。正速度意味着滤波器认为价格正在上涨。负速度意味着下跌。速度从负到正或从正到负的零交叉表示滤波器对平滑后价格序列趋势反转的判断。
一份 2025 年的生产系统分析将速度交叉列为 ML 集成信号的八个输入之一,与动量、波动率和体制指标共同作用,而不是作为独立触发信号。这才是正确的使用方式。卡尔曼速度确实提供了额外信息——它分离了真实趋势的变化率与噪声——但像所有信号一样,它最好作为更广泛框架中的一个组成部分,而非独立规则。
自适应版本
固定参数的滤波器在稳定市场条件下表现良好。在波动市场中,它变得过于平滑,无法跟上快速的真实价格变动。在平静市场中,它可能反应过度,追踪噪声而非信号。解决方案:根据已实现波动率动态调整 Q。当近期波动率较高时,增大 Q 使滤波器更灵敏。当波动率较低时,减小 Q 以实现更平滑的跟踪。
def adaptive_kalman_trend(prices, realized_vol, base_Q=1e-4, R_obs=1e-2, vol_scale=1.0):
orig_index = prices.index if isinstance(prices, pd.Series) else pd.RangeIndex(len(prices))
prices = np.array(prices, dtype=float)
realized_vol = np.array(realized_vol, dtype=float)
n = len(prices)
state = np.array([prices[0], 0.0])
P = np.eye(2)
F = np.array([[1.0, 1.0], [0.0, 1.0]])
H = np.array([1.0, 0.0])
R = float(R_obs)
level = n
相似文章
@Rossst_03: https://x.com/Rossst_03/status/2071171182548636067
一条教育性长帖,解释量化交易公司(如Renaissance Technologies)所用的数学基础,涵盖从伯努利到布朗运动的概念。
@RohOnChain: https://x.com/RohOnChain/status/2069056530960490835
作者解释了如何使用AI循环工程构建一个自我改进的量化交易系统,其中AI运行循环以自主提示、验证和行动,与手动提示形成对比。
@KKaWSB: https://x.com/KKaWSB/status/2074289438474330306
本文详细介绍了如何利用免费的AI开源工具(如OpenBB、Qlib、TradingAgents等)搭建个人量化交易系统,涵盖数据、研究、回测、风控和执行五大模块,并指出了常见陷阱与纪律。
@shmidtqq: https://x.com/shmidtqq/status/2074177517150224402
一份关于使用 Claude AI 通过 Interactive Brokers API 自动进行股票交易的指南,每30分钟循环运行一次。内容涵盖设置、安装和用于模拟交易的策略执行。
@RohOnChain: 这堂关于马尔可夫决策过程的斯坦福一小时讲座将让你更深入地了解系统化交易背后的数学原理……
文章推荐斯坦福大学关于马尔可夫决策过程的讲座作为理解系统化交易数学基础的宝贵资源,声称其提供的洞察力胜过在主要金融机构进行的短期实习。