Robust Asset Allocation(RAA 2014) is a Tactical Asset Allocation(TAA) strategy written by Wes Gray from Alpha Architect. RAA is a dynamic algorithm Index that seeks capital appreciation with downside protection. It’s objectives are to focus on growth able to keep up with inflation, have a downside protection feature, facilitate superior tax efficiency and flexibility(balanced, aggressive, moderate). RAA invests in a globally diverse set of stock, bond, REIT and commodity ETFs. With the stocks split in four portfolios by domestic and international tilted on momentum and value rules. The balanced RAA is a portfolio(RAAb) with a weighting of \(40\%\) in stocks(split in four portfolios), \(20\%\) to REITs, \(20\%\) to commodities and \(20\%\) to bonds which is rebalanced monthly. If RAAb’s ten month cumulative return is greater than the bond’s ten month cumulative return then you go long with \(50\%\) of your wealth. If the price of RAAb is greater than the ten month Simple Moving Average of RAAb’s price, go long \(50\%\) of wealth. If both conditions are met you are fully invested, if neither condition is met you are completely in cash.
The seven Exchange Traded Funds(ETFs) used in this replication have ticker symbols:
(QMOM) Alpha Architect U.S. Quantitative Momentum ETF
(QVAL) Alpha Architect U.S. Quantitative Value ETF
(IMOM) Alpha Architect International Quantitative Momentum ETF
(IVAL) Alpha Architect International Quantitative Value ETF
(VNQ) Vanguard Real Estate Index Fund ETF
(DBC) Invesco DB Commodity Index Tracking Fund
(IEF) iShares 7-10 Year Treasury Bond ETF
From November \(2016\) we can see the equity curve, monthly return histogram and drawdown chart of the RAA balanced strategy. Also shown is a performance metric of RAA displaying calculated Annual Returns, Annual Standard Deviation, Annual Sharpe Ratio, Max Drawdown and Calmar Ratio.
## RAA Balanced Returns
## Annualized Return 0.0289000
## Annualized Std Dev 0.0775000
## Annualized Sharpe (Rf=0%) 0.3729000
## Max Drawdown 0.1278481
## Calmar Ratio 0.2260496
The opensource code is presented below written in R and can be run calling the quantstrat package.
require(quantstrat)
### Replication of Robust Asset Allocation RAA balanced by Wes Gray
# By: Matthew Kiegerl
################################################################################
#
# We first make a balanced 40/20/20 portfolio (RAAb)rebalanced monthly,
# Equity/Real Assets(REITs/Commodities)/Bonds.
#
# If the ten month cumulative return of RAAb
# is greater than the bond fund's ten month
# cumulative return then you go long 50% of wealth.
#
# If the price of RAAb is greater than its ten month SMA
# go long 50% of wealth
#
# If both conditions are met you are fully invested
# or if neither is true you are in cash
#
################################################################################
# 7major Global Asset Classes represented by ETF tickers
tickers <- c("QMOM", #Alpha Architect U.S. Quantitative Momentum ETF
"QVAL", #Alpha Architect U.S. Quantitative Value ETF
"IMOM", #Alpha Architect International Quantitative Momentum ETF
"IVAL", #Alpha Architect International Quantitative Value ETF
"VNQ", #Vanguard Real Estate Index Fund ETF
"DBC", #Invesco DB Commodity Index Tracking Fund
"IEF" #iShares 7-10 Year Treasury Bond ETF
)
# Get daily Adjusted Prices of tickers
# create empty list object
# run loop fill list with ticker names and Ad prices by date
prices <- list()
for(i in 1:length(tickers)) {
ticker <- Ad(get(getSymbols(tickers[i],
from = '2000-01-01')))
colnames(ticker) <- tickers[i]
prices[[i]] <- ticker
}
# Bind the list object by column of prices
prices <- na.omit(do.call(cbind, prices))
# turn the daily price data to monthly price data
monthly.prices <- to.period(prices, period = "months", OHLC = FALSE)
# calculate monthly returns
monthly.rets <- na.omit(Return.calculate(monthly.prices))
# Create the framework portfolio(RAA) for from the monthly return data
# rebalance the portfolio monthly
# 40% equity, 40% Real Assets, 20% Bonds
RAAbalancedMONTHLY <- Return.portfolio(
monthly.rets,
weights = c(10/100, 10/100, 10/100, 10/100, 2/10, 2/10, 1/5),
rebalance_on = 'months')
colnames(RAAbalancedMONTHLY) <- "RAA_Bal_RetsM"
### Rule 1 TMOM, RAA - Bond > 0 = 50% long of portfolio ###
# create an empty list object
stratSig <- list()
# Start loop to calc the ten month cumsRets of RAAb and the IEF bonds.
for(i in 1:(length(monthly.rets[,1])-9)) {
# 10 months of Rets
tenmonthsStrat <- RAAbalancedMONTHLY[c(i:(i+9)),]
tenmonthsIEF <- monthly.rets$IEF[c(i:(i+9)),]
# compute cum returns
stratCum <- Return.cumulative(tenmonthsStrat)
iefCum <- Return.cumulative(tenmonthsIEF)
# Excess returns = RAA cum rets - IEF cum rets
# If excess rets > 0 go long strat with 50%
xRetsSig <- ((stratCum - iefCum) > 0)
stratSig[[i]] <- xRetsSig
}
# end Loop
# rbind Signal(matrix) list into one column
stratSig <- do.call(rbind, stratSig)
# create Data Frame with signal column and RAA Bal rets make equal length
DFxsRets <- cbind(stratSig, RAAbalancedMONTHLY[10:length(RAAbalancedMONTHLY), ])
colnames(DFxsRets) <- c("stratSig", "RAAbalMrets")
# Start loop, multiply sig row by next RAA rets row for realized return
RAA_B_xsRets <- list()
for(i in 1:(length(DFxsRets$stratSig)-1)) {
returns <- as.numeric(DFxsRets$stratSig[i]) * as.numeric(DFxsRets$RAAbalMrets[i+1])
RAA_B_xsRets[[i]] <- returns
}
#end Loop
# Bind rows into a single column of Realized returns, len=60, class = list
RAA_B_xsRets <- do.call(rbind, RAA_B_xsRets)
# make xsRets into XTS object
firstpart <- cbind(DFxsRets[2:length(stratSig)], RAA_B_xsRets)
### Rule 2 ,SMA10 on RAAb, if ret > SMA = 50% of Portfolio ###
# Cum sum RAAb monthly rets, sma10 on cum sum RAA rets
cumRetsRAA <- cumsum(RAAbalancedMONTHLY)
SMAcumRetsRAA <- SMA(cumRetsRAA, 10)
# make Data Frame Cbind RAA rets, Cum sum rets and sma
RAA_DF_sma<- na.omit(cbind(RAAbalancedMONTHLY, cumRetsRAA, SMAcumRetsRAA))
colnames(RAA_DF_sma) <- c("RetsRAA","CumRetsRAA","SMA")
#signal for sma strat, cum rets>sma
#start loop create signal
smaSig<- list()
for(i in 1:length(RAA_DF_sma$RetsRAA)) {
momDiff <- (as.numeric(RAA_DF_sma$CumRetsRAA[i]) - as.numeric(RAA_DF_sma$SMA[i])) > 0
smaSig[[i]] <- momDiff
}
# end loop
# Bind rows
smaSig <- do.call(rbind, smaSig)
#create Data Frame with signal and RAA rets
RAA_DF_sma <- cbind(RAA_DF_sma, smaSig)
# Start loop, multiply sig row by next RAA rets row for realized return
RAA_B_smaRets <- list()
for(i in 1:(length(RAA_DF_sma$RetsRAA)-1)) {
returns <- as.numeric(RAA_DF_sma$smaSig[i]) * as.numeric(RAA_DF_sma$RetsRAA[i+1])
RAA_B_smaRets[[i]] <- returns
}#end Loop
# Bind rows into a single column of Realized returns, len=60, class = list
RAA_B_smaRets <- do.call(rbind, RAA_B_smaRets)
# make SMA rets into XTS object
secondpart <- cbind(RAA_DF_sma[2:length(smaSig)], RAA_B_smaRets)
# Combine two strategy rets, 50% to each allocation, sum up parts
TMOMrets <- firstpart$RAA_B_xsRets*.5
SMArets <- secondpart$RAA_B_smaRets*.5
RAA_B_rets <- TMOMrets + SMArets
colnames(RAA_B_rets) <- "RAA Balanced Returns"
Thanks for reading!