# Adding a volatility filter with VIX

October 2, 2011
By

(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.

require(quantmod)
require(PerformanceAnalytics)

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

maxDrawdown(vf_ret)
#[1] 0.1532796
table.AnnualizedReturns(vf_ret)
# Annualized Return            0.0084
# Annualized Std Dev           0.0757
# Annualized Sharpe (Rf=0%)    0.1110

R-bloggers.com 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...