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:
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
component contribution to risk (CCTR) – the amount of volatility contributed by each security
component contribution to risk percentage (CCTR_Percent) – the percentage of volatility contributed by each security
There are three main stages to the analysis:
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.
Calculate the risk budget. The matrix-based nature of R allows for user friendly linear algebra calculatons.
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