Adding a volatility filter with VIX

October 2, 2011

(This article was first published on Shifting sands, and kindly contributed to R-bloggers)

We saw in the basic system how we could add a factor, namely the 200 day moving average, to improve the overall performance of our system. You could spend a lot of time playing with different moving averages, and different combinations of crossovers if you are so inclined, but its fairly easy to see they only work well in strongly trending markets. 

Instead of looking for further optimisation through price, what other factors might be of use in improving risk adjusted returns? And, more importantly for now, how can we represent them in R?

For this example I will use VIX as a proxy for overall market volatility. When VIX is high (for some definition of high), it means uncertainty reigns and for a long only system, its probably better to wait it out. We will quantify this as when the VIX is under it’s 50 day moving average, volatility is low enough to risk our equity in the hope of gains.

Implementing this in R is quite straightforward, we just generate a second lagged signal vector and take the product of the 200 day MA vector.

The results are better. The extra factor reduces risk adjusted return, though on the whole the system isn’t something I would put my own money into. At the very least it clearly gives a better result than buy & hold. Hopefully you can see the benefit of researching orthogonal factors as inputs. 

As an aside, you could think of the work by Mebane Faber as introducing additional factors through the use of different asset classes and the relative performance of each. A relative performance filter, plus use of a price based filter like the 200 day moving average, provides a very solid overall performance. Looking for different factors you can model and use is probably going to be more fruitful than testing say the 250 SMA vs 200 SMA. There is only so much any one factor can give. 


getSymbols(c(‘SPY’, ‘^VIX’), from=’1999-01-01′)
SPY$ma200 <- SMA(Cl(SPY), 200)
VIX$ma50 <- SMA(Cl(VIX), 50)
spy <- SPY[‘2000/2011’]
vix <- VIX[‘2000/2011’]
sig <- Lag(ifelse(Cl(spy) > spy$ma200, 1, 0))

vix_sig <- Lag(ifelse(Cl(vix) < vix$ma50, 1, 0))
vf_sig <- sig * vix_sig
vf_ret <- ROC(Cl(spy)) * vf_sig
vf_eq <- exp(cumsum(na.omit(vf_ret)))

#[1] 0.1532796
# Annualized Return            0.0084
# Annualized Std Dev           0.0757
# Annualized Sharpe (Rf=0%)    0.1110

To leave a comment for the author, please follow the link and comment on their blog: Shifting sands. offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.


Mango solutions

RStudio homepage

Zero Inflated Models and Generalized Linear Mixed Models with R

Dommino data lab

Quantide: statistical consulting and training



CRC R books series

Six Sigma Online Training

Contact us if you wish to help support R-bloggers, and place your banner here.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)