Permanent Portfolio
First, just a quick update: I’m moving the release date of the SIT package a few months down the road, probably in November.
Now back to the post. Recently I came across a series of interesting posts about the Permanent Portfolio at the GestaltU blog. Today I want to show you how to back-test the Permanent Portfolio using the Systematic Investor Toolbox.
The simple version of the Permanent Portfolio consists of equal allocations to stocks(SPY), gold(GLD), treasuries(TLT), and cash(SHY). [25% allocation each] The portfolio is rebalanced once a year if any allocation breaks out from the 15% – 35% range.
############################################################################### # Load Systematic Investor Toolbox (SIT) # https://systematicinvestor.wordpress.com/systematic-investor-toolbox/ ############################################################################### setInternet2(TRUE) con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb')) source(con) close(con) #***************************************************************** # Load historical data #****************************************************************** load.packages('quantmod') tickers = spl('SPY,TLT,GLD,SHY') data <- new.env() getSymbols(tickers, src = 'yahoo', from = '1980-01-01', env = data, auto.assign = T) for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T) # extend GLD with Gold.PM - London Gold afternoon fixing prices data$GLD = extend.GLD(data$GLD) bt.prep(data, align='remove.na') #***************************************************************** # Code Strategies #****************************************************************** prices = data$prices n = ncol(prices) nperiods = nrow(prices) # annual period.ends = endpoints(prices, 'years') period.ends = period.ends[period.ends > 0] period.ends.y = c(1, period.ends) # quarterly period.ends = endpoints(prices, 'quarters') period.ends = period.ends[period.ends > 0] period.ends.q = c(1, period.ends) models = list() #***************************************************************** # Code Strategies #****************************************************************** target.allocation = matrix(rep(1/n,n), nrow=1) # Buy & Hold data$weight[] = NA data$weight[period.ends.y[1],] = target.allocation models$buy.hold = bt.run.share(data, clean.signal=F) # Equal Weight Annual data$weight[] = NA data$weight[period.ends.y,] = ntop(prices[period.ends.y,], n) models$equal.weight.y = bt.run.share(data, clean.signal=F) # Equal Weight Quarterly data$weight[] = NA data$weight[period.ends.q,] = ntop(prices[period.ends.q,], n) models$equal.weight.q = bt.run.share(data, clean.signal=F)
To rebalance base on the 10% threshold (i.e. portfolio weights breaking out from the 15% – 35% range) I will use bt.max.deviation.rebalancing() function introduced in the Backtesting Rebalancing methods post.
#***************************************************************** # Rebalance based on threshold #****************************************************************** # Rebalance only when threshold is broken models$threshold.y = bt.max.deviation.rebalancing(data, models$buy.hold, target.allocation, 10/100, 0, period.ends = period.ends.y) # Rebalance only when threshold is broken models$threshold.q = bt.max.deviation.rebalancing(data, models$buy.hold, target.allocation, 10/100, 0, period.ends = period.ends.q) #***************************************************************** # Create Report #****************************************************************** plotbt.custom.report.part1(models) plotbt.strategy.sidebyside(models) # Plot Portfolio Turnover for each Rebalancing method layout(1:2) barplot.with.labels(sapply(models, compute.turnover, data), 'Average Annual Portfolio Turnover', F) barplot.with.labels(sapply(models, compute.max.deviation, target.allocation), 'Maximum Deviation from Target Mix')
The Quarterly rebalancing with 10% threshold produces an attractive portfolio with top performance and low turnover.
To view the complete source code for this example, please have a look at the bt.permanent.portfolio.test() function in bt.test.r at github.
Just wondering if you’ve tried to implement any of the Anticor algos. Here’s the link to (I think) the original paper.
Click to access live-1336-2275-jair.pdf