# Backtest with rolling volatility in R

So I'm very new in R. I want to backtest a strategy for 3 stocks SPY, EEM, AGG.

With library(RiskPortfolios), I can calculate

optimalPortfolio(Sigma = Sigma,
control = list(type = 'invvol',constraint = 'lo'))


which gives me the inverse volatility for the whole time period that the stock prices are available.

What if I want calculate inv vol weights based on volatility of the past 20 trading days?

I also want to rebalance the portfolio monthly with the new weights that are based on volatility of the past 20 trading days instead of keeping the same weighting for the entire time. I heard I can do it with package (PerformanceAnalytics) but I do not know how.

Here is a sketch how such a backtest can be done with the btest function, which is in the PMwR package. The package is not on CRAN, but is available from https://github.com/enricoschumann/PMwR. (Disclosure: I am the package author.)

The main input for btest is a function that computes the target portfolio, either as an actual position or as weights. In your case, it may look as follows:

inv_vol <- function() {

## get prices for last 20 days
## and compute returns
R <- returns(Close(n = 20))

optimalPortfolio(Sigma = cov(R),
control = list(type = 'invvol',
constraint = 'lo'))
}


I should warn here that I have never used the RiskPortfolios package. If you really only want portfolio weights proportional to inverse vol, you may write the function as follows:

inv_vol2 <- function() {

## get prices for last 20 days
## and compute returns
R <- returns(Close(n = 20))

w <- 1/apply(R, 2, sd)
w/sum(w)
}


Here would be the complete example. I first prepare some data. I could not get price data for your ticker AAG from Yahoo, so I replaced it. Just plug in your prices: they should be stored as a zoo series prices and not have missing values.

library("PMwR")
library("RiskPortfolios")
library("tseries")
library("zoo")

start <- as.Date("2017-1-1")
ticker <- c("SPY", "EEM", "IUSB")

temp <- list()
for (t in ticker)
temp[[t]] <- get.hist.quote(t, start = start,

prices <- do.call(merge, temp)
colnames(prices) <- ticker

##                 SPY      EEM     IUSB
## 2017-01-03 220.0632 34.74012 48.47526
## 2017-01-04 221.3724 35.00487 48.50420
## 2017-01-05 221.1965 35.38727 48.60073
## 2017-01-06 221.9879 35.24019 48.52351
## 2017-01-09 221.2552 35.21078 48.56213
## 2017-01-10 221.2552 35.41669 48.55247


The backtest is run by passing the data and the inv_vol function to btest.

res <- btest(list(coredata(prices)),
signal = inv_vol,
do.rebalance = "lastofmonth",
b = 20,  ## burnin
convert.weights = TRUE,
initial.cash = 100,
include.data = TRUE,
timestamp = index(prices))


Access the results:

## summary stats
summary(as.NAVseries(res))
## ---------------------------------------------------------
## 31 Jan 2017 ==> 11 May 2018   (323 data points, 0 NAs)
##         100         108.488
## ---------------------------------------------------------
## High                  111.86  (26 Jan 2018)
## Low                    99.35  (09 Mar 2017)
## ---------------------------------------------------------
## Return (%)               6.6  (annualised)
## ---------------------------------------------------------
## Max. drawdown (%)        4.2
## _ peak                111.86  (26 Jan 2018)
## _ trough              107.11  (08 Feb 2018)
## _ underwater now (%)     3.0
## ---------------------------------------------------------
## Volatility (%)           3.5  (annualised)
## _ upside                 3.2
## _ downside               2.1
## ---------------------------------------------------------
##
## Monthly returns  ▂▁▂▃█▅▃
##
##      Jan  Feb Mar  Apr May Jun Jul Aug  Sep Oct Nov Dec  YTD
## 2017      0.0 0.8  1.0 1.1 0.3 1.6 0.9 -0.1 1.2 0.6 0.9  8.5
## 2018 2.1 -2.2 0.4 -0.9 0.6                              -0.1