2
$\begingroup$

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

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

op <- par(no.readonly = TRUE)
Sys.setenv(TZ = 'UTC')

# Contents:

# 1. Installing packages
# 2. Loading packages
# 3. Custom functions
# 4. Downloading and preparing data
# 5. Cross-Betas Kalman filtering

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

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

# *********************************
# 2. Loading packages
# *********************************

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)
})  

# *********************************
# 4. Downloading and preparing data
# *********************************

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?

$\endgroup$
3
  • $\begingroup$ 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? $\endgroup$
    – Lisa Ann
    Jul 10, 2013 at 13:40
  • $\begingroup$ 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. $\endgroup$
    – John
    Jul 10, 2013 at 19:07
  • $\begingroup$ @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. $\endgroup$
    – Lisa Ann
    Jul 10, 2013 at 19:11

1 Answer 1

2
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ ...in 2 days :) $\endgroup$
    – Lisa Ann
    Jul 10, 2013 at 20:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.