5
$\begingroup$

In the context of modern portfolio theory, one often wishes to minimise $\mathbf{w}^{\mathrm{{\scriptstyle T}}}\boldsymbol{\Sigma}\mathbf{w}$ subject to $\mathbf{w}^{T}\boldsymbol{\mu}=c_{1}$, $\left\Vert \mathbf{w}\right\Vert _{1}<c_{2}$ and $\mathbf{w}^{T}\mathbf{1}=1$. Is there an R function or package to do this?

$\endgroup$
0

2 Answers 2

4
$\begingroup$

If you can add linear constriants (as you can do in quadprog) then you can formulate $w \mu = c_1$ as linear constraint, no matter what $\mu$ is (and first delete it from the objective by setting the parameter to zero. The only problem is the one norm. Let my clarify, this is: $$ \sum_{i=1}^n |w_i| < c_2 $$ Thus you allow for short sales but you want to limit leverage -> right? I am afraid that quadprog can not handle such constraints.

Some solvers can handle quadratic constraints then $$ \sum_{i=1}^n |w_i|^2 = w^T w< c_2^* $$ would limit leverage. The first equation above describes a constraint for the $L_1$-norm. If you mean that $|w_i|$ should be bounded for each $i$ then of course you get this by the two inequalities: $$ w \le c_2 \quad \text{and} \quad w \ge -c_2. $$

EDIT after the comment of John: THe package nloptr can handle non-linear constraints. Follow the examples in the link to define the objective function and the constraint. Note that the gradient of $$ f(w) = w^T \Sigma w $$ is given by $$ 2 \Sigma w.$$ Providing the gradient will improve the result of this non-linear optimizer.

EDIT: If you want something built for portfolio optimization directly then you could look at fPorfolio and e.g. this presentaton. I find that the documentation lacks details and I wonder whether all features "promised" in the presentation work properly. On page 13 they say that the package can handle non-linear constraints. If you try it then please tell us whether this works.

$\endgroup$
6
  • 1
    $\begingroup$ Good answer. nloptr would allow either an L1-norm or an L2-norm. $\endgroup$
    – John
    Commented May 20, 2015 at 15:29
  • $\begingroup$ Yes, @Richard, you are correct that quadprog won't work. Can you recommend any alternative packages? $\endgroup$ Commented May 21, 2015 at 10:37
  • $\begingroup$ I edited and took into account the comment of John about the package nloptr. $\endgroup$
    – Richi Wa
    Commented May 21, 2015 at 11:20
  • $\begingroup$ @Richard -- thank you for the suggestion to use nloptr. I'll certainly give it a go. But is there not something more suited for a qudratic programming setup (with non linear constraints) as opposed to using a generic optimisation package? I've had experience with these things before... and they often either fail to converge or end up at local optima. Either way, thank you for input it's greatly appreciated. $\endgroup$ Commented May 21, 2015 at 11:52
  • $\begingroup$ You could have a closer look at fPortfolio but I don't know whether everything that they promised really works. $\endgroup$
    – Richi Wa
    Commented May 21, 2015 at 12:28
2
$\begingroup$

I wonder if it's possible to use solve.QP from quadprog by using dummy variables. One dummy variable $y_i$ would be used for each $w_i$, each $y_i$ would be constrained to be greater than zero, and the leverage constraint would be applied to the sum of the $y_i$. Problem formulation would look like $$ \text{min } w^tΣw $$ subject to the constraints $$ w^t\mu= c_1 $$ $$ w^t 1 = 1 $$

$$ y_i \geq 0 $$ $$ w_i + y_i \geq 0 $$ $$ -w_i + y_i \geq 0 $$

$$ -\sum y_i \geq -c_2 $$

Code could look like

leveraged_port <- function( er,cov.mat, target_return=NULL, leverage=1., tickers=NULL ){
   library(quadprog)
# leverage checks and adjustments
   if(leverage < 1.) stop( "leverage must be >= 1.")
   if( target_return > (leverage+1)/2*max(er)) stop("target_return not achievable; increase leverage or decrease target_return")
   lev_adj  <- 1.E-06
   if(leverage < 1 + lev_adj) leverage  <- 1 + lev_adj
   n_asset <- length(er)
   zeros <- integer(n_asset)
 # quad problem
 # calculate small diag value for dummy variables so Dmat is positive def.
    diag_dum <- 1.e-05*min(diag(cov.mat))
    Dmat <- diag(diag_dum, nrow=2*n_asset, ncol=2*n_asset)
    Dmat[1:n_asset, 1:n_asset] <- 2*cov.mat
    dvec <- numeric(2*n_asset)
    meq <-  2
 # constraints on weights
    bvec <- c(1, target_return)
    Amat <- matrix( c(rep(1,n_asset), er, diag(n_asset), -diag(n_asset), diag(0, nrow=n_asset),
                      zeros), nrow=n_asset) 
 # constraints on dummy variables
    bvec <- c(bvec, zeros, zeros, zeros, -leverage)
    Amat <- rbind( Amat, matrix(c(zeros, zeros, diag(n_asset), diag(n_asset), diag(n_asset), 
                                  -rep(1,n_asset)), nrow=n_asset))
    sol<-solve.QP(Dmat, dvec, Amat, bvec, meq=meq)
    weights<-sol$solution[1:n_asset]
        names(weights) <- tickers
        exp.ret <- t(er)%*%weights
        std.dev <- sqrt(weights %*% cov.mat %*% weights)
        ret <- list(er = as.vector(exp.ret),
                    StdDev = as.vector(std.dev),
                    weights = weights,
                    sum_weights = sum(weights),
                    leverage = sum(abs(weights)),
                    lagrange_mults=sol$Lagrangian )  
 }

Results on the following example problem seem feasible

library(quantmod)
tickers <- c("MSFT","AAPL", "AMZN", "YHOO", "XOM", "CVX", "UNH", "NKE")
prices <- do.call(cbind, 
         lapply(tickers, function(x) getSymbols(x, from="2010-01-01", auto.assign=FALSE, warnings=FALSE)[,6]))
colnames(prices) <- tickers
returns <- diff(prices, arithmetic=FALSE, na.pad=FALSE) - 1
means <- sapply(returns, mean)

QPsol <- leveraged_port(er=means, cov.mat=cov(coredata(returns)), target_return=.0016, leverage=1.8, tickers)

with the results

QPsol
$er
[1] 0.0016

$StdDev
[1] 0.01830004

$weights
         MSFT          AAPL          AMZN          YHOO           XOM           CVX           UNH           NKE 
-9.809695e-14  1.044254e+00 -5.297152e-14 -1.780017e-17 -4.000000e-01 -1.556950e-13  3.557464e-01  4.224909e-14 

$sum_weights
[1] 1

$leverage
[1] 1.8
$\endgroup$
4
  • $\begingroup$ This is a very clever solution. $\endgroup$ Commented May 26, 2015 at 11:03
  • 1
    $\begingroup$ Really very clever! In short $y_i = |w_i|$ -> right? $\endgroup$
    – Richi Wa
    Commented May 26, 2015 at 12:05
  • $\begingroup$ @Richard exactly. Absolutely excellent. $\endgroup$ Commented May 26, 2015 at 12:57
  • $\begingroup$ Auxiliary variables can be tricky though when you extend them to other circumstances, like turnover constraints or transaction costs. You sometimes have to impose additional constraints to ensure that $w_{i}y_{i}=0$, which makes the problem no longer fit for quadratic optimizers. $\endgroup$
    – John
    Commented May 26, 2015 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.