卡尔曼滤波

卡尔曼滤波是时间序列的一个非常重要方法,在量化投资中有着诸多的应用,如:

  • 未来金融事件序列的预测
  • 金融事件序列去噪
  • 配对交易时变的对冲比率

对于一个时间序列,我们可以在每个时点观察到时间序列相应的值,当然这些观察值是包含着噪声的。试想一下,如果将这些噪声去除,那么对于这条“干净”的时间序列,我们是会相对容易地根据趋势对下一个“干净”的点做预测。当然这种理想的状态并不存在。

为了处理这种“眼见不为实”的现象,一个直观的想法是建立一个模型,将不能观测的去噪状态与可观察的状态用数学公式联系起来。于是,我们引入了一个叫做状态空间的东西。状态空间用来描述系统的真实状态,因此它是由系统中的诸多参数组成的一个矩阵。由于系统每个时刻都会发生变化,因此状态变量是时变的。一个简单的假设是T期的状态变量是T-1的状态变量加上误差项组成,并且T期的各参数是被T-1的参数线性决定的,于是可以得到所谓的“状态方程”。

状态变量是无法实际观测到的,我们实际只能对一些测量值进行观测,需要注意的是观测变量和状态变量是不同的两组变量。观测和状态变量之间的关系也可以用一个线性关系来表示,T期的观测变量由T期状态变量的线性组合和满足标准正态分布的随机误差项构成,这就是“测量方程”。

现在看看我们模型中的要素,状态方程中有时变的状态变量x(t),表示线性关系的矩阵F,过程噪音v(t-1);观测方程中有时变的观测变量z(t),表示线性关系的矩阵H,观测噪音w(t)。如果不考虑误差因素,那么根据x(t)很容易预测z(t+1),即:z(t+1)=HFx(t+1)。然而实际上该预测的z(t+1)与实际观测的z(t+1)有一个误差y,通过该误差可以对x(t+1)的预测值进行修正,x(t+1)的预测值由Fx(t)和Wy组成。下面列出上述所有的关系式:

Basis:
x(t)=Fx(t-1)+v(t-1)
z(t)=Hx(t)+w(t)
Forecast:
x(t+1)_ =Fx(t)+Wy
z(t+1)_=HFx(t)
y=z(t+1)-z(t+1)_

现在的问题就是如何确定W,W被称为卡尔曼增益。我们引入了两个新的变量,p(t)是x(t)预测值的协方差矩阵,s(t)是z(t)预测值的协方差矩阵。确定W的过程较为复杂,这里直接给出结论:

P(t)=cov(x(t)_)
S(t)=cov(z(t)_)
P(t+1)=FP(t)F'+Q
S(t+1)=HP(t+1)H'+R
W=P(t+1)Hinv(S(t+1))

下面是一个非常简单的例子来说明Kalman滤波器是如何进行预测的。假设现在研究的是一个室内的温度,想根据T时刻的温度去估计T+1时刻的真实温度。根据我们的经验,温度是很定不变的,假设T时刻真实的温度是23度,那么根据经验预测了23度这个温度(Fx(t)),预测的偏差是5度;同时根据房内的温度计我们发现了在T+1时刻测量的温度是25度(z(t+1)),测量偏差为4度。现在将这两部分预测合并起来,我们知道y=25-23=2,W=sqrt(5^2/(5^2+4^2 ))=0.78,于是最终的预测值为23+2*0.78=24.56,该值就是此时刻的最优估计。

根据上述的例子,可以构建一个简单的Kalman滤波器,其中状态初始的均值为23、偏差为5,观测的偏差是4,转移和观测矩阵都是1。进一步,在非理想的状态下,观测的温度状态并非恒定在23度,观测值夹杂着噪音,因此将23度加上白噪声作为实际观测值并用已经建立好的滤波器对其进行滤波。在Python中可采用pykalman这个包进行相关的操作。

import numpy as np  
from pykalman import KalmanFilter
import matplotlib.pyplot as plt

kf = KalmanFilter(n_dim_obs=1, 
                  n_dim_state=1, 
                  initial_state_mean=23,
                  initial_state_covariance=5,
                  transition_matrices=[1],
                  observation_matrices=[1],
                  observation_covariance=4,
                  transition_covariance=np.eye(1),
                  transition_offsets=None)

actual = [23]*100
sim = actual + np.random.normal(0,1,100)     
state_means, state_covariance = kf.filter(sim)   

plt.plot(actual,'r-')
plt.plot(sim,'k-')
plt.plot(state_means,'g-')

绿色的线代表的是滤波后的观测值,可以看到滤波后的序列明显与真实序列更接近,观测值中一些比较明显的噪声被过滤掉了。

卡尔曼滤波在量化中一个非常普遍的应用是对金融时间序列(如股票收盘价等)进行去噪。我们经常使用这样的技术使得时间序列变得更加平滑,并且过滤那些非常明显的噪声也有助于后续的建模。作为练习,大家可以选取一只股票的日收盘价序列作卡尔曼滤波。


我的微信公众号:会掘金的小鹿(NuggetsRoad)
是时候关注一波了!

编辑于 2019-03-24 23:12