Testing Asset Allocation Strategies

This vignette illustrates some ways to use the AssetAllocation package to backtest simple asset allocations. Example 1 shows how to backtest one of the pre-loaded asset allocations in the basic_asset_alloc object. The available allocations are these:

library(AssetAllocation)
library(PerformanceAnalytics)
names(basic_asset_alloc)
##  [1] "us_60_40"         "golden_butterfly" "rob_arnott"       "globalAA"        
##  [5] "permanent"        "desert"           "larry"            "big_rocks"       
##  [9] "sandwich"         "balanced_tax"     "balanced"         "income_gr"       
## [13] "income_gr_tax"    "con_income"       "con_income_tax"   "all_weather"

Each allocation is represented as a list with fields describing the name of the strategy, the tickers used, the desired weights, the rebalancing frequency, and the rebalancing function (which for the time being should always be set to “identity”. For example, Ray Dalio’s All Weather Portfolio strategy is defined as follows:

basic_asset_alloc$all_weather
## $name
## [1] "All Weather Portfolio"
## 
## $tickers
## [1] "SPY" "TLT" "IEF" "GLD" "DBC"
## 
## $default_weights
## [1] 0.300 0.400 0.150 0.075 0.075
## 
## $rebalance_frequency
## [1] "month"
## 
## $portfolio_rule_fn
## [1] "identity"

The package comes with returns data to test the 16 strategies in basic_asset_alloc. The returns are in the ETFs_daily data set. Type ?ETFs_daily for details.

Example 1: testing a pre-loaded allocation

In this first example, we use the pre-loaded returns matrix to backtest the Permanent Portfolio allocation. We then plot the cumulative returns.

## Example 1: backtesting one of the asset allocations in the package
strat_permanent <- basic_asset_alloc$permanent

# test using the data set provided in the package
bt_strat_permanent <- backtest_allocation(strat_permanent, ETFs_daily)

# plot cumulative returns
chart.CumReturns(bt_strat_permanent$returns,
                 main = paste0("Cumulative returns of the ",
                               bt_strat_permanent$strat$name,
                               " portfolio"),
                 ylab = "Cumulative returns"
)

# table with performance metrics
bt_strat_permanent$table_performance
##                               Permanent.Portfolio
## Annualized Return                          0.0664
## Annualized Std Dev                         0.0698
## Annualized Sharpe (Rf=0%)                  0.9513
## daily downside risk                        0.0031
## Annualised downside risk                   0.0488
## Downside potential                         0.0014
## Omega                                      1.1837
## Sortino ratio                              0.0862
## Upside potential                           0.0017
## Upside potential ratio                     0.6738
## Omega-sharpe ratio                         0.1837
## Semi Deviation                             0.0032
## Gain Deviation                             0.0029
## Loss Deviation                             0.0033
## Downside Deviation (MAR=210%)              0.0091
## Downside Deviation (Rf=0%)                 0.0031
## Downside Deviation (0%)                    0.0031
## Maximum Drawdown                           0.1533
## Historical VaR (95%)                      -0.0068
## Historical ES (95%)                       -0.0102
## Modified VaR (95%)                        -0.0068
## Modified ES (95%)                         -0.0121

Example 2: creating and testing a custom allocation

Here we create a custom strategy from scratch. The strategy invests equally in momentum (MTUM), value (VLUE), low volatility (USMV) and quality (QUAL) ETFs.

We first set up this custom strategy as follows:

factor_strat  <- list(name = "EW Factors",
                      tickers = c("MTUM", "VLUE", "USMV", "QUAL"),
                      default_weights = c(0.25, 0.25, 0.25, 0.25),
                      rebalance_frequency = "month",
                      portfolio_rule_fn = "identity")

Next, we can automatically download data and create a returns matrix using the get_return_data_from_tickers function:

returns_ETFs <- get_return_data_from_tickers(factor_strat$tickers,
                                             starting_date = "2013-08-01")
#> 'getSymbols' currently uses auto.assign=TRUE by default, but will
#> use auto.assign=FALSE in 0.5-0. You will still be able to use
#> 'loadSymbols' to automatically load data. getOption("getSymbols.env")
#> and getOption("getSymbols.auto.assign") will still be checked for
#> alternate defaults.
#> 
#> This message is shown once per session and may be disabled by setting 
#> options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.

Finally, we backtest the strategy and show the results:

# backtest the strategy
bt_factor_strat <- backtest_allocation(factor_strat,
                                       returns_ETFs)

# plot returns
library(PerformanceAnalytics)
chart.CumReturns(bt_factor_strat$returns,
                 main = paste0("Cumulative returns of the ",
                               bt_factor_strat$strat$name,
                               " portfolio"),
                 ylab = "Cumulative returns"
)


# table with performance metrics
bt_factor_strat$table_performance
#>                               EW.Factors
#> Annualized Return                 0.1370
#> Annualized Std Dev                0.1658
#> Annualized Sharpe (Rf=0%)         0.8265
#> daily downside risk               0.0075
#> Annualised downside risk          0.1191
#> Downside potential                0.0030
#> Omega                             1.1881
#> Sortino ratio                     0.0752
#> Upside potential                  0.0036
#> Upside potential ratio            0.5623
#> Omega-sharpe ratio                0.1881
#> Semi Deviation                    0.0077
#> Gain Deviation                    0.0074
#> Loss Deviation                    0.0090
#> Downside Deviation (MAR=210%)     0.0122
#> Downside Deviation (Rf=0%)        0.0075
#> Downside Deviation (0%)           0.0075
#> Maximum Drawdown                  0.3499
#> Historical VaR (95%)             -0.0150
#> Historical ES (95%)              -0.0255
#> Modified VaR (95%)               -0.0142
#> Modified ES (95%)                -0.0142