Download Stock Data
stks =c("AAPL", "MSFT", "AMZN", "NVDA", "GOOGL", "GOOG", "META", "BRK-B",
"TSLA", "UNH", "XOM", "JNJ", "JPM", "V", "PG", "LLY", "AVGO",
"MA", "HD", "MRK")
stk_data <- stockDataDownload(stks, from = "2019-01-01", to = "2023-05-31", rm_stocks_with_na = TRUE)
## Loading stock data from local file /cloud/project/stockdata_from_2019-01-01_to_2023-05-31_(0f9cf120d38e5ba793ee9b2a12c3efc1).RData
save.image("STKS_riskParity.RData")
Optimization
load("STKS_riskParity.RData")
prices <- stk_data$adjusted
prices <- do.call(merge,lapply(as.list(1:ncol(prices)), function(ii){
tmp <- na.locf(Cl(to.monthly(prices[,ii], name=names(prices[,ii]))))
names(tmp) <- gsub(".Close","",names(tmp))
tmp
}))
stk_data = list(`adjusted`= prices)
risk_parity <- function(dataset, ...) {
prices <- dataset$adjusted
log_returns <- diff(log(prices))[-1]
log_returns[is.na(log_returns)] <- 0
riskParityPortfolio(cov(log_returns))$w
}
max_sharpe_ratio <- function(dataset, ...) {
prices <- dataset$adjusted
log_returns <- diff(log(prices))[-1]
log_returns[is.na(log_returns)] <- 0
N <- ncol(prices)
Sigma <- cov(log_returns)
mu <- colMeans(log_returns)
if (all(mu <= 1e-8))
return(rep(0, N))
Dmat <- 2 * Sigma
Amat <- diag(N)
Amat <- cbind(mu, Amat)
bvec <- c(1, rep(0, N))
dvec <- rep(0, N)
res <- try(solve.QP(Dmat = Dmat, dvec = dvec, Amat = Amat, bvec = bvec, meq = 1), silent = TRUE)
if(inherits(res,'try-error')){
D_mat <- nearPD(Dmat)
res <- solve.QP(Dmat = as.matrix(D_mat$mat), dvec = dvec, Amat = Amat, bvec = bvec, meq = 1)
}
w <- res$solution
w/sum(w)
}
bt <- portfolioBacktest(list("risk parity portfolio" = risk_parity,
"tangency portfolio" = max_sharpe_ratio),
list(stk_data),
lookback = 6,
optimize_every = 3,
rebalance_every = 1,
shortselling = TRUE,
benchmarks = '1/N',
execution = "next period"
)
## Backtesting 2 portfolios over 1 datasets (periodicity = monthly data)...
## Backtesting benchmarks...
Table of Stats
cat("\nRebalanced: ")
##
## Rebalanced:
index(bt$`risk parity portfolio`$data1$w_rebalanced)
## [1] "Jun 2019" "Jul 2019" "Aug 2019" "Sep 2019" "Oct 2019" "Nov 2019"
## [7] "Dec 2019" "Jan 2020" "Feb 2020" "Mar 2020" "Apr 2020" "May 2020"
## [13] "Jun 2020" "Jul 2020" "Aug 2020" "Sep 2020" "Oct 2020" "Nov 2020"
## [19] "Dec 2020" "Jan 2021" "Feb 2021" "Mar 2021" "Apr 2021" "May 2021"
## [25] "Jun 2021" "Jul 2021" "Aug 2021" "Sep 2021" "Oct 2021" "Nov 2021"
## [31] "Dec 2021" "Jan 2022" "Feb 2022" "Mar 2022" "Apr 2022" "May 2022"
## [37] "Jun 2022" "Jul 2022" "Aug 2022" "Sep 2022" "Oct 2022" "Nov 2022"
## [43] "Dec 2022" "Jan 2023" "Feb 2023" "Mar 2023"
round(backtestSummary(bt)$performance,4)
## risk parity portfolio tangency portfolio 1/N
## Sharpe ratio 5.1805 4.9795 5.8403
## max drawdown 0.2098 0.2226 0.2057
## annual return 5.0913 5.1154 5.4966
## annual volatility 0.9828 1.0273 0.9411
## Sortino ratio 8.9534 9.2194 10.9557
## downside deviation 0.5686 0.5548 0.5017
## Sterling ratio 24.2706 22.9819 26.7218
## Omega ratio 2.1958 2.1866 2.3825
## VaR (0.95) 0.0846 0.0918 0.0782
## CVaR (0.95) 0.1087 0.0984 0.0827
## rebalancing period 1.0217 1.0217 1.0217
## turnover 0.2899 0.5199 0.0530
## ROT (bps) 688.6805 376.1225 4072.5262
## cpu time 0.0037 0.0154 0.0008
## failure rate 0.0000 0.0000 0.0000
Returns + Drawdown Charts
portfolioBacktest::backtestChartCumReturn(bt)

portfolioBacktest::backtestChartDrawdown(bt)

Weight Allocation through Time
backtestChartStackedBar(bt, portfolio = "risk parity portfolio", legend = TRUE)

backtestChartStackedBar(bt, portfolio = "tangency portfolio" , legend = TRUE)
