construct the data
asset.names = c("MSFT", "NORD", "SBUX")
er = c(0.0427, 0.0015, 0.0285)
names(er) = asset.names
covmat = matrix(c(0.0100, 0.0018, 0.0011,
0.0018, 0.0109, 0.0026,
0.0011, 0.0026, 0.0199),
nrow=3, ncol=3)
r.free = 0.005
dimnames(covmat) = list(asset.names, asset.names)
define function globalMin.portfolio
globalMin.portfolio <-
function(er, cov.mat, shorts=TRUE)
{
call <- match.call()
#
# check for valid inputs
#
asset.names <- names(er)
er <- as.vector(er) # assign names if none exist
cov.mat <- as.matrix(cov.mat)
N <- length(er)
if(N != nrow(cov.mat))
stop("invalid inputs")
if(any(diag(chol(cov.mat)) <= 0))
stop("Covariance matrix not positive definite")
# remark: could use generalized inverse if cov.mat is positive semi-definite
#
# compute global minimum portfolio
#
if(shorts==TRUE){
cov.mat.inv <- solve(cov.mat)
one.vec <- rep(1,N)
w.gmin <- rowSums(cov.mat.inv) / sum(cov.mat.inv)
w.gmin <- as.vector(w.gmin)
} else if(shorts==FALSE){
Dmat <- 2*cov.mat
dvec <- rep.int(0, N)
Amat <- cbind(rep(1,N), diag(1,N))
bvec <- c(1, rep(0,N))
result <- quadprog::solve.QP(Dmat=Dmat,dvec=dvec,Amat=Amat,bvec=bvec,meq=1)
w.gmin <- round(result$solution, 6)
} else {
stop("shorts needs to be logical. For no-shorts, shorts=FALSE.")
}
names(w.gmin) <- asset.names
er.gmin <- crossprod(w.gmin,er)
sd.gmin <- sqrt(t(w.gmin) %*% cov.mat %*% w.gmin)
gmin.port <- list("call" = call,
"er" = as.vector(er.gmin),
"sd" = as.vector(sd.gmin),
"weights" = w.gmin)
class(gmin.port) <- "portfolio"
gmin.port
}
compute global minimum variance portfolio
gmin.port = globalMin.portfolio(er, covmat)
attributes(gmin.port)
## $names
## [1] "call" "er" "sd" "weights"
##
## $class
## [1] "portfolio"
print(gmin.port)
## $call
## globalMin.portfolio(er = er, cov.mat = covmat)
##
## $er
## [1] 0.02489184
##
## $sd
## [1] 0.07267607
##
## $weights
## MSFT NORD SBUX
## 0.4411093 0.3656263 0.1932644
##
## attr(,"class")
## [1] "portfolio"
summary(gmin.port, risk.free=r.free)
## Length Class Mode
## call 3 -none- call
## er 1 -none- numeric
## sd 1 -none- numeric
## weights 3 -none- numeric
plot(gmin.port$weights, col="blue")

compute global minimum variance portfolio with no short sales
gmin.port.ns = globalMin.portfolio(er, covmat, shorts=FALSE)
attributes(gmin.port.ns)
## $names
## [1] "call" "er" "sd" "weights"
##
## $class
## [1] "portfolio"
print(gmin.port.ns)
## $call
## globalMin.portfolio(er = er, cov.mat = covmat, shorts = FALSE)
##
## $er
## [1] 0.02489182
##
## $sd
## [1] 0.072676
##
## $weights
## MSFT NORD SBUX
## 0.441109 0.365626 0.193264
##
## attr(,"class")
## [1] "portfolio"
summary(gmin.port.ns, risk.free=r.free)
## Length Class Mode
## call 4 -none- call
## er 1 -none- numeric
## sd 1 -none- numeric
## weights 3 -none- numeric
plot(gmin.port.ns$weights, col="blue")
