Recently I’m trying to develop some handy tools to help backtest and analyse user-specified portfolio strategies. Now I’d like to do a quick demonstration through testing four portfolio strategies (minimum variance, maximum Sharpe Ratio, minimum CVaR, and equal-weighted) that rebalance weekly from 1990 to 2012.

Instead of specific stocks or ETFs, 10 S&P sector indices by GICS will be used as hypothetical assets. As aggregated equity trackers, they are similar in terms of market efficiency, liquidity, macro environment etc. And by using them we eliminated factors that jeopardize the quality of data such as IPO or survivorship bias. Moreover, most ETFs only emerged several years ago, with equity indices one can go back much further for a bigger sample.

Firstly, I got the data from Bloomberg and load it from a csv. file. Please note in order to transfer the raw data into a time-series object (zoo), we need to convert the dates in the csv. file into integers.

### load packages require(TTR) require(tseries) require(quadprog) require(Rglpk) require(quantmod) raw_data <- read.csv(file.choose(), header = TRUE) ## open the file directly raw_data[, 1] <- as.Date(raw_data[, 1], origin = '1899-12-30') ## convert numbers into dates raw_data <- zoo(raw_data[, -1], order.by = raw_data[, 1]) ## create a zoo object

With the data properly formatted, we can perform backtests based on our strategies.

minvar_test <- backtest(raw_data, period = 'weeks', hist = 52, secs = 10, model = 'minvar', reslow = .1 ^ 10, reshigh = 1) sharpe_test <- backtest(raw_data, period = 'weeks', hist = 52, secs = 10, model = 'sharpe') cvar_test <- backtest(raw_data, period = 'weeks', hist = 52, secs = 10, model = 'cvar', alpha = .01) equal_test <- backtest(raw_data, period = 'weeks', hist = 52, secs = 10, model = 'eql')

I’m not posting function *backtest* here because it’s quite bulky and has other optimization functions nested inside. But as you can see what it does is just take a zoo object, ask what strategy the user wants to test, and perform a backtest accordingly. By setting argument daily.track = TRUE, You can also track the portfolio’s position shift on daily basis. But due to time and space constrain I won’t show it this time neither.

Here’s the PnL curves of the tests.

And to see their position transitions, we need another function.

## returns a transitional map of a backtest strategy transition <- function(allo, main = NA) { cols = rainbow(ncol(allo)) x <- rep(1, nrow(allo)) plot(x, col = 'white', main = main, ylab = 'weight', ylim = c(0, 1), xlim = c(-nrow(allo) * .2, nrow(allo))) polygon(c(0, 0, 1:nrow(allo), nrow(allo)), c(0, 1, x, 0), col = cols[1], border = FALSE) for (i in 2:ncol(allo)) { polygon(c(0, 0, 1:nrow(allo), nrow(allo)), c(0, 1 - sum(allo[1, 1:i]), x - apply(allo[, 1:i], 1, sum), 0), col = cols[i], border = FALSE) } legend('topleft', colnames(allo), col = cols[1:ncol(allo)], pch = 15, text.col = cols[1:ncol(allo)], cex = 0.7, bty = 'n') } ## visualize the transitions par(mfrow = c(4, 1)) transition(cvar_allo, main = 'CVaR Portfolio Transition') transition(minvar_allo, main = 'Min-Variance Portfolio Transition') transition(sharpe_allo, main = 'Sharpe Portfolio Transition') transition(equal_allo, main = 'Equally Weighted Portfolio Transition')

Scalability was taken into consideration when these functions were built. I look forward to nesting more strategies into the existing functions.

roy

Pingback: Optimizing Ivy Portfolio « Investments