Search code examples
rcovariancer-portfolioanalytics

Calculate Portfolio Variance In R Given Weights, Volatility and a Correlation Matrix


I have a dynamic data set that contains a vector of weights, volatility and a correlation matrix. I would like to create a function that computes the variance of the full portfolio. I would also like to avoid any for loops (if possible).

Here is a made up sample for a 3 asset portfolio.

tickers = c("AAPL", "MSFT", "AMZN")
weights = c(.33, .33, .33)
volatility = c(.2, .25, .23)

mat = data.frame(row.names = c("AAPL", "MSFT", "AMZN"), AAPL = c(1, .87, .76), MSFT = c(.87, 1, .76), AMZN = c(.87, .76, 1))
print(mat)

     AAPL MSFT AMZN
AAPL 1.00 0.87 0.87
MSFT 0.87 1.00 0.76
AMZN 0.76 0.76 1.00

I will do the example manually. However I would like the final product to be a function where the inputs are simply tickers, weights, volatility and corr matrix. The output should be a single number with the daily portfolio variance.

firstPart = .33^2*(volatility[1]/sqrt(252))^2 + .33^2*(volatility[2]/sqrt(252))^2 + .33^2*(volatility[3]/sqrt(252))^2
AAPL.MSFT.Part = 2*.33*.33*(.87*((volatility[1]/sqrt(252))*(volatility[2]/sqrt(252))))
AAPL.AMZN.Part = 2*.33*.33*(.76*((volatility[1]/sqrt(252))*(volatility[3]/sqrt(252))))
MSFT.AMZN.Part = 2*.33*.33*(.76*((volatility[2]/sqrt(252))*(volatility[3]/sqrt(252))))

Portfolio.Variance = sum(c(firstPart, AAPL.MSFT.Part, AAPL.AMZN.Part, MSFT.AMZN.Part))

print(Portfolio.Variance)
 0.0001727361 

Solution

  • If you are familiar with matrices you can try a simple implementation along the lines of:

    Formula

    Sigma refers to the variance/covariance matrix. If you have data on the asset returns (preferably a data frame or xts object, where columns are assets and rows are date/time), this matrix can easily be computed using the base r function cov(). However, if you only have data on correlation/variance you will have to convert to covariance using the formula:

    Conversion

    Simple demo of the above mentioned formulas:

    # Setup
    
    sd.A <- 0.2 #AAPL
    sd.B <- 0.25 #MSFT
    sd.C <- 0.23 #AMZN
    
    p.AB <- 0.87 #AAPL/MSFT
    p.AC <- 0.76 #AAPL/AMZN
    p.BC <- 0.76 #MSFT/AMZN
    
    cov.AB <- sd.A * sd.B * p.AB
    cov.AC <- sd.A * sd.C * p.AC
    cov.BC <- sd.B * sd.C * p.BC
    
    sigma <- matrix(c(sd.A^2, cov.AB, cov.AC,
                      cov.AB, sd.B^2, cov.BC,
                      cov.AC, cov.BC, sd.C^2),
                      nrow = 3,
                      ncol = 3,
                      byrow = TRUE)
    
    # If you have the return data no need for the above and just do:
    
    sigma <- cov(returns)
    
    # Solution
    
    w <- as.matrix(c(.33, .33, .33))
    volatility <- sqrt(t(w)%*%sigma%*%w)