# Counterintuitive time varying Beta with Kalman filter

If you're used to play with R, you'll enjoy the following reproducible code:

# =================================================== #
# An example of state-space monitor via Kalman filter #
# =================================================== #

Sys.setenv(TZ = 'UTC')

# Contents:

# 1. Installing packages
# 3. Custom functions
# 5. Cross-Betas Kalman filtering

# *********************************
# 1. Installing packages
# *********************************

install.packages('KFAS')
install.packages('latticeExtra')
install.packages('quantmod')

# *********************************
# *********************************

require(compiler)
require(latticeExtra)
require(KFAS)
require(quantmod)

# *********************************
# 3. Custom functions
# *********************************

# This function returns the time varying state-space representation
# parameters of a linear model which represents y ~ X

Kalman.beta <- cmpfun(function(y, X)
{
model <- regSSM(y = y, X = cbind(1, X), H = NA, Q = diag(NA, 2))
object <- fitSSM(inits = rep(0, 3), model = model)$model KFAS <- KFS(object = object) alpha.beta <- xts(t(KFAS$alphahat), index(y))
colnames(alpha.beta) <- rep(paste(colnames(y), 'vs' , colnames(X)), 2)
return(alpha.beta)
})

# *********************************
# *********************************

env <- new.env()
Symbols <- c('SPY', 'QQQ', 'XLF', 'TLT')
getSymbols(Symbols = Symbols, env = env, from = '1950-01-01')
args <- eapply(env = env, FUN = function(x){ClCl(x)})
X <- na.omit(do.call(what = merge, args = args))
colnames(X) <- Symbols
xyplot(X)

# *********************************
# 5. Cross-Betas Kalman filtering
# *********************************

Betas <- NULL
k <- 0

for(i in 1:ncol(X))
{
for(j in (1:ncol(X))[-i])
{
k <- k + 1
Betas[[k]] <- Kalman.beta(y = X[,i], X = X[,j])[,2]
}
}

Beta.matrix <- do.call(what = merge, args = Betas)
colnames(Beta.matrix) <- gsub(pattern = '.', fixed = TRUE,
x = colnames(Beta.matrix), replacement = ' ')
xyplot(Beta.matrix, superpose = FALSE, auto.key = FALSE,
main = '')


What does this code do? It basically uses Kalman filter to estimate time varying $\beta_{t}$ of each asset against each other and plot them.

What's the matter with that?

If you use a simple linear regression model to estimate $\beta$ constant over time you will see it often happens, as instance, that $\beta_{t}<1<\beta$ or $\beta_{t}>0>\beta$ for the most of the time series... which is really counterintuitive!

How could SPY be negatively correlated with QQQ while it's quite obvious they are strongly correlated and $\beta \approx 1$? And so on...

How would you explain this?

Is there anything wrong with my code?

-
Maybe I've found an issue: args <- eapply(env = env, FUN = function(x){ClCl(x)}) should be replaced by args <- eapply(env = env, FUN = function(x){ClCl(x)})[Symbols] to keep the downloading sequence. I'm checking final results with that amended and they now seem correct. Is it the same for you? Do results seem correct to you after that replacing? –  Lisa Ann Jul 10 '13 at 13:40
I don't quite understand what you're talking about with respect to the $\beta_{t}$ being bigger than zero if $\beta$ is less than zero. Why don't you try to create a data generating process that involves a time-varying $\beta_{t}$ and then run your code on that to see how good it does. I've only ever programmed my own Kalman Filters so I can't say whether you're using the KFAS package correctly or not. It's not terribly challenging and you could use that to help confirm if that's causing a problem with your code. –  John Jul 10 '13 at 19:07
@John, I've found the error. Obviously KFAS works fine, the issue was in eapply(): I always forget it shuffles the input elements. In this case it shuffled my assets, then the $\beta_{t}$ shown were not the ones matching the original Yahoo query. See my comment above for solution. –  Lisa Ann Jul 10 '13 at 19:11

This is definitely not a Kalman filter's issue: if you replace this line of code

args <- eapply(env = env, FUN = function(x){ClCl(x)})


with this one

args <- eapply(env = env, FUN = function(x){ClCl(x)})[Symbols]


eapply() will keep the order of the original Yahoo query from quantmod. You can check and you will see each $\beta_{t}$ matches about the $\beta$ from simple OLS linear regression CAPM-like.

-
You can accept your own answer. :) –  chrisaycock Jul 10 '13 at 19:29
...in 2 days :) –  Lisa Ann Jul 10 '13 at 20:12