Kalman Filter (02) – S&P 500 and Dow Jones Pairs Trading


Our previous article on Kalman filter gave us a simple linear regression output. The model is designed to handle noisy data, but not on streaming data and time adaptive parameters. This post we will study more general usage of the Kalman filter.
Simple Pairs Trading
From the linear regression result between S&P 500 and Dow Jons ETFs, a simple strategy can be easily derived. The regression parameters and
give us not just an equation to evaluate the relative value of the price pair, but also confidence ranges for divergent signals. Here we can modify the linear relationship
to a two-sigma event detector below
When
we might just long the S&P 500 ETF (SPY) and short the Doe Jons ETF (DIA) and wait for them to converge, and vice versa for the case when
Moreover, we close the position when the prices converge within the range. We provide a sample code below to test the strategy from the year 2000 to 2015. The divergent event is capture by using the
confidence interval calculated from the ordinary least-squares fitting results from the `statesmodel` module.
parameters | coef | std err | t value | [95.0% Conf. Int.] |
---|---|---|---|---|
-2.0651 | 0.385 | -5.364 | [-2.820, -1.310] | |
0.8903 | 0.003 | 264.258 | [0.884, 0.897] |
Python code implementation is included in the IPython Notebook file. Let’s check the outcome:

There are two difficulties with the strategy.
- The linear regression is derived from the whole history of data. It is impossible for us to use the linear regressed pair to trade from the beginning.
-
From our last finding, the parameters
should not be constant.
We expect to resolve the issues by Kalman filter.
Kalman Filter
The full model of a Kalman filter can be characterized as
and
where
are the latent vector,
are the observation vector,
are the transition matrices,
are the observation matrices,
are the transition white noise following the distribution
,
are the measurement white noise following the distribution
.
By letting be an identity matrices,
,
, and
, we have the time-adaptive linear regression model between the two prices.
So how this Kalman Filter improve the model?
One of the advantages using Kalman Filter is to find the latent factor distributions. The inferences on these parameters can give us more thoughts on building a mean-reverting trading strategy.
The noise affects latent variable
distribution. We cannot directly observe
, so we start with an initial conjecture, then continuously modify
mean and variance. The
is observation noise. It simply indicates that, based on the information on
distribution, how the errors between the estimates and actual values behave. If
is large, then in our case the linear regression might not be a good model to capture the relationship between S&P 500 ETF and Dow Jones ETF. We will make an assumption on
and
.
Okay, now what do we have? We can observe the prices from the market. We assume the linear relationship between the prices dynamics. Time adaptive parameters need an updating mechanism taking in streaming data. Kalman filter has another advantage for online optimization. It can be accomplished by using
filter_update function
from pykalman
module.
For pairs trading with Kalman filter, we need to decide the two timings:
- When to buy and sell?
- When to close?
The updated state variance in Kalman filter provides a hint on this part since it indicates upper and lower bounds of the difference between DIA and SPY prices derived from the model. Each iteration Kalman filter outputs the updated mean and variance of , which is estimated at time
. The estimated statistics are computed through Kalman gain. Details can be found in many literature. Then we simply enter the positions if the price difference is large that certain standard divation of the price deviation. To achieve it, we compute the estimation error variance
and use it to identify the divergent event. That is, we trade the pair when where
controls the number of standard deviation.
By setting , we have

Improved Kalman Filter Pairs Trading
We can increase the accuracy of the linear regression prediction by estimating the changing speed and acceleration of future regression parameters. It is a common method used in signal processing. Through Taylor expansion, we have
where denote the speed and acceleration of the latent factor
at time
. To plug it into our Kalman filter, we can simply take
and
However, the measurement matrices is defined as
to maintain the same simple linear regression form.
Just to make the model simpler, we set and apply the trick to the first order on
and
. The key parts of the code and the result are shown below.
Creating Kalman Filter
[sourcecode language=”python” light=”true” wraplines=”false” collapse=”false”]
# Create a Kalman Filter Object
kf = KalmanFilter(n_dim_obs=1,
n_dim_state=4,
transition_matrices=A,
transition_covariance=Q,
observation_covariance=R,
observation_matrices=array_SPY)
kf = kf.em(df_data.ix[‘1999’][‘DIA’].values)# Linear Regression Outputs
alpha = kf.initial_state_mean[3]
beta = kf.initial_state_mean[0]
[/sourcecode]
Kalman Filter Update
[sourcecode language=”python” light=”true” wraplines=”false” collapse=”false”]
for row in df_data.ix[‘2000’:].iterrows():
price_spy = row[1][‘SPY’]
price_dia = row[1][‘DIA’]# Kalman filter update
updated_mean, updated_variance = kf.filter_update(filtered_state_mean=updated_mean,
filtered_state_covariance=updated_variance,
observation_matrix=np.expand_dims(np.array([price_spy, 0, 1, 0]), 0),
observation=np.array([price_dia])
)
[/sourcecode]
Partial rule of buying and selling: to long SPY and short DIA we check if
Trading (Long SPY, Short DIA)
[sourcecode language=”python” light=”true” wraplines=”false” collapse=”false”]
if (price_dia > price_spy * beta + alpha + 1*P and
not long_spy_short_dia): # Long SPY-DIA Spread
if short_spy_long_dia:
total_wealth += shares_spy * (price_spy – cost_spy) + shares_dia * (price_dia – cost_dia)
short_spy_long_dia = False
shares_spy = total_wealth / price_spy
shares_dia = -1 * total_wealth / price_dia
cost_spy = price_spy
cost_dia = price_dia
long_spy_short_dia = True
[/sourcecode]
Performance is improved.

What’s Next?
We have shown how Kalman filter can used for pairs trading between S&P 500 ETF and Dow Jons ETF. We double the Sharpe ratio by implementing a second-order time adaptive linear regression based on Kalman filter and Taylor expansion. In our next topic on Kalman filter, we will examine the -asset pairs trading and probably non-linear Kalman filter.