卡尔曼滤波期货套利:把“会过期的均值“换成递推估计的四层拆解
2026/9/13 18:02:56 网站建设 项目流程

卡尔曼滤波期货套利:把"会过期的均值"换成递推估计的四层拆解

【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant

均值回归策略最常见的死法,不是价差没有回归,而是你用来量回归的那把尺子已经过期了。基于 gs-quant 量化金融工具包,本文用卡尔曼滤波做期货套利:把固定窗口的价差均值与标准差,换成逐期递推的动态估计,并把整个系统拆成数据、滤波、信号、回测四层,每层只保留最小可运行的部分。

上图取自仓库内权益交易事件的流水线图:输入→评估→优化→输出的分层方式,与本文要搭的四层系统同构,仅作结构示意。


📊 先看最终效果:四层系统各自管什么

本节先回答"这套系统长什么样":给出对比效果,再列出四层的输入输出,后续各节按层展开细节。

示例回测对比(示例数据)

指标卡尔曼动态阈值固定 60 日窗口 ±2σ
年化收益率19.4%11.2%
夏普比率1.50.8
最大回撤9.6%14.1%
年交易次数62118

示例回测结果,非真实业绩。合约、对冲比例与窗口参数均见下文各层。

一句话结论:把"均值"从常量改成逐期更新的估计,是这套系统相对静态方法唯一的结构性差异,其余都是工程细节。

四层输入输出一览

输入输出代码位置(仓库内)
数据层合约定义、日期区间对齐后的价差序列spread_rawgs_quant/markets/、gs_quant/instrument/
滤波层价差序列、Q/R 参数每期中心估计x_t与协方差P_t本文代码(约 20 行)
信号层x_tP_t、原始价差+1 / 0 / −1 三态信号本文代码
回测层信号、初始资金绩效指标gs_quant/backtests/、gs_quant/risk/

数据层:合约与价差序列怎么准备

本节解决入口问题:选哪两个标的、如何在 gs-quant 里定义合约、如何把它们对齐成一条价差序列。

合约定义与行情拉取

以螺纹钢 2309 与铁矿石 2309 为例,1 小时频率、约半年区间(示例):

import numpy as np from gs_quant.markets import get_history from gs_quant.instrument import Future # 定义合约(对冲比例 1 : 5,经验系数) rb = Future('RB', '2309', 'CFFEX') i = Future('I', '2309', 'DCE') rb_price = get_history(rb, 'price', start_date='2023-01-01', end_date='2023-06-30', frequency='1h') i_price = get_history(i, 'price', start_date='2023-01-01', end_date='2023-06-30', frequency='1h') # 价差 = 螺纹钢 - 5 × 铁矿石 spread_raw = rb_price - 5 * i_price

对冲比例这个系数从哪来

两条路子:对历史价格水平跑一次 OLS 回归,取斜率作经验系数;或直接用合约规格推导。关键是系数一旦确定,回测期间不再改——否则价差序列本身就在漂移,后面滤波层追的对象是错的。完整的拉数与清洗脚本可参考仓库 gs_quant/documentation/04_backtesting/ 下的示例 notebook,本文只保留上面三件事:合约定义、行情获取、价差计算。

🧮 滤波层:卡尔曼滤波最小实现,Q/R 参数从哪来

本节回答核心数学问题:如何用状态空间模型表达"均值自己会动",以及简化后的最小公式和代码。

状态空间模型与两处简化

状态方程 spread_t = a + b·spread_{t-1} + w_t , w ~ N(0, Q) 观测方程 z_t = spread_t + v_t , v ~ N(0, R)

其中a为漂移项,b为持续性系数。两个噪声参数各给一句直觉解释:

  • 过程噪声 Q:真实中心自己漂移的速度,Q 越大允许中心动得越快
  • 观测噪声 R:报价里混入的随机杂质,R 越大越不信任当根 K 线
  • 协方差 P:估计有多不确定的刻度,收敛后决定信号阈值宽窄

两处简化,理由如下:

  1. 状态取单个标量(只关心价差水平),状态转移矩阵F=[1]——用上一期中心作为当期中心的最优预测,把均值回复交给 Q/R 的比值去体现;
  2. 观测矩阵H=[1]——观测就是"状态 + 噪声",矩阵乘法与求逆全部退化成标量除法,整个更新只剩四行运算。

卡尔曼增益 K 是信任新观测的权重,决定中心跳多快:R 大则 K 小,中心动得慢。

最小可运行实现

class KalmanSpreadTracker: """单状态卡尔曼滤波:F=1、H=1,矩阵运算退化为标量""" def __init__(self, q=1e-4, r=2e-3): self.Q, self.R = np.array([[q]]), np.array([[r]]) self.x = np.array([[0.]]) # 状态估计:隐含价差中心 self.P = np.array([[1.]]) # 协方差:估计的不确定性 def update(self, z): # 预测:中心沿用上一期,不确定性加上 Q x_pred, P_pred = self.x, self.P + self.Q # 更新:卡尔曼增益 K = P/(P+R) K = P_pred / (P_pred + self.R) self.x = x_pred + K * (z - x_pred) self.P = (1 - K) * P_pred return self.x[0, 0] tracker = KalmanSpreadTracker() xs, ps = [], [] for s in spread_raw.values: # 逐期递推,不重置状态 xs.append(tracker.update(s)) ps.append(tracker.P[0, 0]) spread_kalman = np.array(xs)

注意 tracker 是一个对象被串行复用,状态不重置;ps存下每期各自的P,信号层要用到。

Q 和 R 分别怎么给

参数直觉含义给值方法
R报价里的随机杂质用价差最近 20 期一阶差分方差的滚动估计,如np.var(ret[-20:]),每 N 期重估一次,防止单一取值被行情"用旧"
Q中心漂移的速度网格粗调(1e-6 ~ 1e-2 量级),再按下文敏感性结果定稿

📈 信号层:用 2σ 阈值把偏离变成多/空/观望

本节回答"什么时候交易":把滤波中心与原始价差的连续偏离,转成 +1 / 0 / −1 三态信号。

阈值怎么算

用当期的协方差P_t作阈值尺度,阈值取2σ = 2·√P_t。与静态布林带的差别在于:静态方法的窗口和 σ 来自历史统计,这里来自滤波自身的递推更新——行情平静时P_t收窄、阈值收紧,行情剧烈时P_t放大、阈值放宽,不需要人工切换窗口。

信号生成代码

sigma = np.sqrt(ps) # 每期各自的阈值尺度 dev = spread_raw.values - spread_kalman signal = np.zeros(len(dev)) signal[dev > 2 * sigma] = -1 # 高于中心 → 做空价差 signal[dev < -2 * sigma] = 1 # 低于中心 → 做多价差 # 其余保持 0(观望)

信号规则汇总:

条件信号含义
spread_raw − x_t > 2√P_t−1价差显著高于动态中心,做空价差
x_t − spread_raw > 2√P_t+1价差显著低于动态中心,做多价差
其余0观望,不新开仓

回测层:回测结果怎么读,以及适用边界

本节回答两个问题:回测跑完后怎么解读数字,以及这套方法在哪些行情里会失效。

回测框架与绩效读数

回测用 gs-quant 现成框架:gs_quant/backtests/ 中的Backtest定义合约集合与初始资金,把信号序列交给引擎运行;绩效经 gs_quant/risk/ 下的Performance枚举读取,如Performance.SHARPE_RATIOPerformance.MAX_DRAWDOWN。读数时盯三点:交易次数是否在预期量级(过多说明阈值过紧);回撤是否集中在行情结构突变后的首次信号(若是,说明滤波在追噪声);绩效对交易成本是否敏感(频率越低越抗成本)。必要时可把滤波后的价差暴露接入 gs_quant/models/risk_model.py 的因子风险模型做风险归因,完整接线脚本见仓库对应示例 notebook。

参数敏感性怎么看

示例回测中,Q、R 在 1e-6 ~ 1e-2 范围内单独调整,夏普、回撤等指标波动普遍小于 8%。方向性结论:Q/R 不需要调到小数点后某一位,只需要量级正确;把力气花在"是否随行情重估 R"上,回报更大。

什么行情下这套方法会失效

  • 持续单边趋势:价差长期不回归时,任何动态中心都会追错方向,均值回复前提不成立
  • 结构性断点:供需、政策改变价差分布本身,滚动 R 会被系统性带偏
  • 高成本低流动性:信号本身就稀疏,手续费与滑点能吃掉全部边际
  • 厚尾分布:2σ 阈值会低估真实偏离幅度,可考虑放大倍数或粒子滤波

✅ 下一步清单:从示例到你的品种

本节是一份待办清单:读完后按顺序做什么,仓库里哪里可以继续看。

五条可执行动作

  1. 把示例合约换成自己的价差组合,先跑通数据层,肉眼检查价差序列有没有对齐缺失
  2. 以 Q=1e-4、R=2e-3 为起点跑通滤波层与信号层,确认信号期数量在合理量级
  3. 用 20 期滚动方差重估 R,对比绩效变化幅度,做第一次自适应实验
  4. 对 Q/R 做十倍网格敏感性分析,记录指标极差后再谈"稳健"
  5. 在回测中加入交易成本,重读频率、回撤位置、成本敏感这三个数

仓库里继续看什么

  • 时间序列技术指标(含exponential_moving_average,可作噪声估计的对照基线):gs_quant/timeseries/technicals.py
  • 回测引擎与事件、订单系统:gs_quant/backtests/
  • 因子风险模型(风险归因):gs_quant/models/risk_model.py

【免费下载链接】gs-quantPython toolkit for quantitative finance项目地址: https://gitcode.com/GitHub_Trending/gs/gs-quant

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询