Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

In the last post, Multiple Factor Model – Building Risk Model, I have shown how to build a multiple factor risk model. In this post I want to explain why do we need a risk model and how it is used during portfolio construction process.

The covariance matrix is used during the mean-variance portfolio optimization to estimate portfolio risk. The sample covariance matrix can estimated using historical asset’s returns, but the use of the sample covariance matrix becomes problematic when the number of assets (N) is of the same order of magnitude or larger than the number of observations (T). In typical applications, there can be over a thousand stocks to choose from, but rarely more than ten years of monthly data (i.e. N = 1,000 and T = 120). I recommend following references for a detailed discussion:

One possible solution to estimating a covariance matrix is to model risk by a low-dimensional multiple factor model. Another advantage of using a multiple factor model to describe covariances between assets is that portfolio optimization algorithm works faster because the covariance matrix is quite sparse and well structured. For a detailed discussion please read: Portfolio Optimization with Factors, Scenarios, and Realistic Short Positions by B. Jacobs, K. Levy, and H. Markowitz (2005) [In problems with a large number of securities, computation time may differ by orders of magnitude between using a dense covariance matrix(sample covariance matrix) and using the diagonal or nearly diagonal covariance matrices permitted by a multiple factor model of covariance.]

The outline of this post:

• Construct minimum variance portfolio using the sample covariance matrix
• Construct minimum variance portfolio using the multiple factor risk model we created in the prior post

Let’s start by loading the multiple factor risk model we saved at the end of the prior post. [If you are missing risk.model.Rdata file, please execute fm.risk.model.test() function first to create and save multiple factor risk model.] Next, I will construct minimum variance portfolio using the historical covariance matrix.

###############################################################################
# Load Systematic Investor Toolbox (SIT)
# http://systematicinvestor.wordpress.com/systematic-investor-toolbox/
###############################################################################
con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb'))
source(con)
close(con)
#*****************************************************************
#******************************************************************

# Load factor data that we saved at the end of the fm.all.factor.test function
nperiods = nrow(next.month.ret)
n = ncol(next.month.ret)
tickers = colnames(next.month.ret)

# Load multiple factor risk model data that we saved at the end of the fm.risk.model.test function

#*****************************************************************
# Construct minimum variance portfolio using the sample covariance matrix
#******************************************************************

#--------------------------------------------------------------------------
# Create Covariance matrix based on the last 24 months of returns
#--------------------------------------------------------------------------
temp = last(mlag(next.month.ret),24)
cov.temp = cov(temp, use='complete.obs', method='pearson')
hist.cov = cov.temp

#--------------------------------------------------------------------------
#--------------------------------------------------------------------------
if(!is.positive.definite(cov.temp)) {
cov.temp <- make.positive.definite(cov.temp, 0.000000001)
}

#--------------------------------------------------------------------------
# Create constraints
#--------------------------------------------------------------------------
# set min/max wgts for individual stocks: 0 =< x <= 1
constraints = new.constraints(n, lb = 0, ub = 1)

# wgts must sum to 1 (fully invested)
constraints = add.constraints(rep(1,n), 1, type = '=', constraints)

#--------------------------------------------------------------------------
# Solve QP problem
#--------------------------------------------------------------------------
sol = solve.QP.bounds(Dmat = cov.temp, dvec = rep(0, nrow(cov.temp)) ,
Amat=constraints$A, bvec=constraints$b, constraints$meq, lb = constraints$lb, ub = constraints$ub) #-------------------------------------------------------------------------- # Plot Portfolio weights #-------------------------------------------------------------------------- x = round(sol$solution,4)
x = iif(x < 0, 0, x)
names(x) = colnames(next.month.ret)
hist.min.var.portfolio = x

# plot
barplot(100*x,las = 2,
main = 'Minimum variance portfolio weights (sample covariance matrix)')


To minimize portfolio risk computed under risk model framework we have to combine specific risk and factor covariance matrix into one covariance matrix. This process is described on pages 4-5 of the Portfolio Optimization with Factors, Scenarios, and Realistic Short Positions by B. Jacobs, K. Levy, and H. Markowitz (2005).

Let K be the number of factors in the risk model. We introduce K additional variables that represent portfolio’s factor exposure to each factor. Let’s add K constraints:

X1...Xn * factor.exposures = Xn+1...Xn+k

The new covariance matrix:

[specific.risk  0                 ]
[0              factor.covariance ]

Next, I will construct minimum variance portfolio using the the multiple factor risk model we created in the prior post.

	#*****************************************************************
# Construct minimum variance portfolio using the multiple factor risk model
#******************************************************************
t = nperiods
factor.exposures = all.data[t,,-1]
nfactors = ncol(factor.exposures)

#--------------------------------------------------------------------------
# Create constraints
#--------------------------------------------------------------------------
# set min/max wgts for individual stocks: 0 =< x <= 1
constraints = new.constraints(n, lb = 0, ub = 1)

# wgts must sum to 1 (fully invested)
constraints = add.constraints(rep(1,n), 1, type = '=', constraints)

# BX - Xnew = 0
constraints = add.constraints(rbind(factor.exposures, -diag(nfactors)), rep(0, nfactors), type = '=', constraints)

#--------------------------------------------------------------------------
# Create Covariance matrix
# [Qu  0]
# [ 0 Qf]
#--------------------------------------------------------------------------
temp = diag(n)
diag(temp) = specific.variance[t,]^2
cov.temp = diag(n + nfactors)
cov.temp[1:n,1:n] = temp
cov.temp[(n+1):(n+nfactors),(n+1):(n+nfactors)] = factor.covariance[t,,]

#--------------------------------------------------------------------------
# Solve QP problem
#--------------------------------------------------------------------------

sol = solve.QP.bounds(Dmat = cov.temp, dvec = rep(0, nrow(cov.temp)) ,
Amat=constraints$A, bvec=constraints$b, constraints$meq, lb = constraints$lb, ub = constraints$ub) #-------------------------------------------------------------------------- # Plot Portfolio weights #-------------------------------------------------------------------------- x = round(sol$solution,4)[1:n]
x = iif(x < 0, 0, x)
names(x) = colnames(next.month.ret)
risk.model.min.var.portfolio = x

# plot
barplot(100*x,las = 2,
main = 'Minimum variance portfolio weights (multiple factor risk model)')


The minimum variance portfolio computed under the risk model is more diversified. Also for a larger stock universe (i.e. 1000-2000 stocks) solving quadratic problem will take less time using a factor risk model that results in a sparse covariance matrix.

To view the complete source code for this example, please have a look at the fm.risk.model.test() function in factor.model.test.r at github.