Backtesting Risk-Based Portfolios

Author

Shrutika Sinha

Overview

The project consists of empirically testing the performance of selected portfolio risk based investment strategies.

Tasks

  1. Download monthly market data for S&P500 listed stocks from 01-01-2010 to 31-12-2022.

  2. Generate 100 random resamples of 20 S&P500 listed stocks and 3 consecutive data.

  3. Empirically investigate the performance of the following traditional and risk-based portfolios.

    1. Global Minimum-Variance Portfolio with no short-selling
    2. Inverse Volatility Portfolio
    3. Risk parity portfolio
    4. Most diversified portfolio
    5. Maximum decorrelation portfolio
    6. Hierarchical Risk Parity Portfolio
    7. Markowitz's mean-variance portfolio (MVP) with no short-selling
  4. Critically discuss the results considering alternative risk-adjusted performance metrics (e.g., returns, volatility, Sharpe ratio, Sterling ratio, drawdown).

  5. Extra Points: Use the same data set to investigate the performance of portfolio management strategies using alternative risk measures, e.g., downside risk, value-at-risk (VaR),Conditional VaR (CVaR) or expected shortfall (ES).

Loading Essential Libraries

library(xts)
library(quantmod)
library(PerformanceAnalytics)
library(portfolioBacktest)
library(CVXR)
library(DT)

Loading Data

startDate <- "2010-01-01"
endDate <- "2022-12-31"
data(SP500_symbols)
sp500 <- stockDataDownload(stock_symbols = SP500_symbols, from=startDate,to=endDate, periodicity="monthly")
Loading stock data from local file /Users/vivekraj/Coding/R/Asset Pricing & Portfolio Management/stockdata_from_2010-01-01_to_2022-12-31_(065fe3c9e1991cd1ec13c8d1c18d3e2c).RData

Generate Random Re-samples

# 100 random resamples of 20 S&P500 listed stocks and 3 consecutive data.
set.seed(100)
dataset_list <- financialDataResample(sp500,             # dataset
                                         N_sample = 20,     # Desired number of financial instruments in each resample
                                         T_sample = 12*3,  # Desired length of each resample (consecutive samples with a random initial time)
                                         num_datasets = 100) # Number of resampled datasets
100 datasets resampled (with N = 20 instruments and length T = 36) from the original data between 2010-01-01 and 2022-12-01.
head(dataset_list$`dataset 1`$adjusted, 3)
                RHI      CMA  HOLX   UAL  ABMD      NOC      PNR      CHD
2016-02-01 33.57555 25.51389 34.63 57.26 80.01 169.9190 28.01455 40.87451
2016-03-01 39.92841 28.60306 34.50 59.86 94.81 175.6796 31.86062 41.68137
2016-04-01 32.83937 33.72963 33.59 45.81 97.14 183.1010 34.10365 41.91650
                FTI  ADBE    IT     NTAP      TJX       NI      ETN    MTD
2016-02-01 17.01593 85.15 82.40 20.15832 33.17339 16.80483 46.49743 314.91
2016-03-01 18.97904 93.80 89.35 22.14656 35.18468 18.56609 51.29395 344.76
2016-04-01 21.15026 94.22 87.17 19.18448 34.04853 17.89626 52.39142 357.95
                 LIN     PAYX      HRB     APTV
2016-02-01  87.85804 41.05777 23.91893 53.21378
2016-03-01  98.78529 43.15101 19.21953 60.16710
2016-04-01 102.11877 41.64100 14.82948 59.05230

Defining the Portfolios

1. Global Minimum-Variance Portfolio with no short-selling

# Global Minimum-Variance Portfolio with no short-selling
gmvp_portfolio_fn <- function(dataset,...) {
  X <- diff(log(dataset$adjusted))[-1] # computed the log-returns
  sigma <- cov(X) # computed the covariance matrix
  w <- solve(sigma,rep(1, nrow(sigma)))
  w <- abs(w)/sum(abs(w)) # normalize the weights so that they sum up to 1
  return(w)
}

2. Inverse Volatility Portfolio

inv_vol_portfolio_fn <- function(dataset, ...) {
  X <- diff(log(dataset$adjusted))[-1] # computed the log-returns
  volatility <- sd(X)
  w <- 1/volatility
  w <- abs(w)/sum(abs(w))
  return(w)
}

3. Risk Parity Portfolio

risk_parity_portfolio_fn <- function(dataset, ...) {
  X <- diff(log(dataset$adjusted))[-1] # computed the log-returns
  sigma <- cov(X) # computed the covariance matrix
  risk_contribution <- sqrt(diag(sigma) %*% X)
  w <- 1/risk_contribution
  w <- abs(w)/sum(abs(w))
  return(w)
}

4. Most Diversified Portfolio

most_diverse_portfolio_fn <- function(dataset, ...) {
  X <- diff(log(dataset$adjusted))[-1] # computed the log-returns
  # Calculate the correlation matrix
  corr_mat <- cor(X)
  # Calculate the inverse correlation matrix
  inv_corr_mat <- solve(corr_mat)
  w <- inv_corr_mat %*% rep(1, ncol(X))
  w <- abs(w)/sum(abs(w))
  return(w)
}

5. Maximum Decorrelation Portfolio

max_deco_portfolio_fn <- function(dataset, ...) {
  
}