This entry is an example of how to use R to calculate a risk budget for individual securities in a portfolio. In this example risk is defined as portfolio volatility or standard deviation, however as I will show in other entries risk does not have to be limited to volatility. I use a portfolio of equally weighted technology stocks as the sample portfolio for the analysis. The three outputs of the risk budget are:

  1. marginal contribution to risk (MCTR) – the approximate change in the portfolio volatility from a 1% increase in the security weight – or the partial derivative of the portfolio volatility with respect to the security’s weight

  2. component contribution to risk (CCTR) – the amount of volatility contributed by each security

  3. component contribution to risk percentage (CCTR_Percent) – the percentage of volatility contributed by each security

There are three main stages to the analysis:

  1. Gather the security return history. I will use the fImport package to gather the price history for each security from the yahoo finance database. A useful function in the timeSeries package converts the prices into continuously compounded returns.

  2. Calculate the risk budget. The matrix-based nature of R allows for user friendly linear algebra calculatons.

  3. Output the results in a table for analysis.

# get security returns -----------------------------------------------------------------------

# requires fImport package to gather returns from yahoo finance data base
if(require(fImport) == FALSE){
  install.packages("fImport")
  require(fImport)
}

# example securities - tech stock tickers
tix <- c("AAPL", "MSFT", "YHOO", "GOOG", "AMZN", "ORCL", "RHT")

# yahooSeries gets data in Open-High-Low-Close format
ohlc <- yahooSeries(tix, from = "2012-01-01", to = "2014-12-31", frequency = "daily")

# price (adjusted close) data in every 6th column
price <- ohlc[, seq(6, length(tix)*6, 6)]

# calculate continuously compounded returns
ccReturns <- timeSeries::returns(price, method = "continuous")

# risk budget analysis requires weights - equal weights used as example
weights <- rep(1/length(tix), length(tix))

# calculate the risk budget --------------------------------------------------------------

# portfolio standard deviation or volitility
portVol <- sqrt(t(weights) %*% cov(ccReturns) %*% weights)

# marginal contribution to risk
MCTR <- weights %*% cov(ccReturns) / portVol[1,1]

# component contribution to risk 
CCTR <- MCTR * weights 

CCTR_P <- CCTR / portVol[1,1]

# output results -------------------------------------------------------------------------

results <- data.frame(tix, weights, as.vector(MCTR), as.vector(CCTR), as.vector(CCTR_P))
colnames(results) <- c("Tickers", "Port Weight", "MCTR", "CCTR", "CCTR_Percent")
results[, 2:NCOL(results)] <- round(results[, 2:NCOL(results)], 3)
results
##   Tickers Port Weight  MCTR  CCTR CCTR_Percent
## 1    AAPL       0.143 0.008 0.001        0.105
## 2    MSFT       0.143 0.007 0.001        0.093
## 3    YHOO       0.143 0.014 0.002        0.188
## 4    GOOG       0.143 0.010 0.001        0.143
## 5    AMZN       0.143 0.014 0.002        0.198
## 6    ORCL       0.143 0.009 0.001        0.119
## 7     RHT       0.143 0.011 0.002        0.153

The PerformanceAnalytics package has a function that will calculate the risk budget for future convenience and is a good check on the results above.

if(require(PerformanceAnalytics) == FALSE){
  install.packages("PerformanceAnalytics")
  require(PerformanceAnalytics)
}

# clean up the column names in the returns timeSeries object
colnames(ccReturns) <- gsub(".Adj.Close", "", colnames(ccReturns))

args(StdDev)
## function (R, ..., clean = c("none", "boudt", "geltner"), portfolio_method = c("single", 
##     "component"), weights = NULL, mu = NULL, sigma = NULL, use = "everything", 
##     method = c("pearson", "kendall", "spearman")) 
## NULL
portRisk <- StdDev(ccReturns, weights = weights, portfolio_method = "component")

str(portRisk)
## List of 3
##  $ StdDev            : num [1, 1] 0.0103
##  $ contribution      : Named num [1:7] 0.001081 0.000951 0.001929 0.001473 0.002038 ...
##   ..- attr(*, "names")= chr [1:7] "AAPL" "MSFT" "YHOO" "GOOG" ...
##  $ pct_contrib_StdDev: Named num [1:7] 0.1053 0.0926 0.1879 0.1435 0.1985 ...
##   ..- attr(*, "names")= chr [1:7] "AAPL" "MSFT" "YHOO" "GOOG" ...
round(portRisk$pct_contrib_StdDev, 3)
##  AAPL  MSFT  YHOO  GOOG  AMZN  ORCL   RHT 
## 0.105 0.093 0.188 0.143 0.198 0.119 0.153