It’s been more than a month since I last posted. Time flies when you are busy working on the things you enjoy.

After reading a piece on the lacklustre performance of hedge funds versus a standard 60/40 portfolio mix, it got me thinking deeper about stock bond allocation. In this post I am going to dissect and check the internal workings of the equity bond allocation and see if there are any tactical overlay that can improve a static allocation mix.

Data: I will be using monthly data from Data Stream and Bloomberg; SP500 and 10 Year treasuries, all total return from January 1988 to May 2012.

Here a backtest helper function wrapped around SIT:

require(TTR) require(quantmod) setInternet2(TRUE) con = gzcon(url('https://github.com/systematicinvestor/SIT/raw/master/sit.gz', 'rb')) source(con) close(con) btest<-function(data1,allocation,rebalancing){ data <- list(prices=data1[,1:2]) data$weight<-data1[,1:2] data$weight[!is.na(data$weight)]<- NA data$execution.price<-data1[,1:2] data$execution.price[!is.na(data$execution.price)]<-NA data$dates<-index(data1[,1:2]) prices = data$prices nperiods = nrow(prices) data$weight[] = NA data$weight[1,] = allocation period.ends = seq(1,nrow(data$prices),rebalancing)-1 period.ends<-period.ends[period.ends>0] data$weight[period.ends,]<-repmat(allocation, len(period.ends), 1) capital = 100000 data$weight[] = (capital / prices) * data$weight model = bt.run(data, type='share', capital=capital) return(model) }

This simply runs the backtest for provided allocation and rebalancing period for 2 assets. To check the performance of all equity allocation from 0 to 1 in increments of n%, I will be using the following wrapper function:

sensitivity<-function(data1,rebalancing,allocation.increments){ equity.allocation<-seq(0,1,allocation.increments) #Y-axis eq = matrix(NA, nrow=nrow(data1), ncol=1) for(i in equity.allocation) { allocation <- matrix(c((1-i),i), nrow=1) temp<-btest(data1,allocation,rebalancing) eq<-cbind(eq,temp$equity) } eq<-eq[,-1] colnames(eq) = 1-equity.allocation cagr<-matrix(NA,nrow=ncol(eq),ncol=1) for(i in 1:ncol(eq)){ cagr[i]<-compute.cagr(eq[,i]) } cagr<-as.data.frame(cbind(1-equity.allocation,cagr)) colnames(cagr)<-c('Equity Allocation','CAGR') sharpe<-matrix(NA,nrow=ncol(eq),ncol=1) eq.ret<-ROC(eq) eq.ret[is.na(eq.ret)]<-0 for(i in 1:ncol(eq)){ sharpe[i]<-compute.sharpe(eq.ret[,i]) } sharpe<-as.data.frame(cbind(1-equity.allocation,sharpe)) colnames(sharpe)<-c('Equity Allocation','Sharpe') return(list(eq=eq,cagr=cagr,sharpe=sharpe)) }

Running the sensitivity function in increments of 5% provides:

As you increase the equity allocation, you become more aggressive, which is obviously displayed from the chart above. What is the optimal allocation based on highest CAGR or Sharpe? The sensitivity function also returns a list of the performance of each equity allocation and the chart:

In the above chart, I’ve graphed two lines each with its own respective axis. From the chart, it seems that the equity allocation that provided the highest Sharpe Ratio is ~0.25. This seems to be similar to a risk parity allocation as historical data shows that such allocation is very close to optimal risk parity.

Diving deeper, I went in to check each successive 12 month period’s highest Sharpe equity allocation from 1988 to 2012. In another word, this takes us back in time!

From this chart, the max sharpe allocation varied significantly over each year. Whenever crisis hit, the allocation to bonds seems to dominate that on equity and vice versa in bull markets. This intuitively make sense as you would want to be in risk off mode during bear markets.

The last chart shows the rolling 12 month performance of each equity allocation from 0 to 1 in increments on 5%.

In another post, I will follow up on whether there are any tactical overlays that can improve performance.

Hi there,

thank you very much for your great blog and for posting all this codes.

Would it be possible for you to share the last part of the code for the charting of the results?

thanks once again