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$
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$
  • 1
    $\begingroup$ Good answer. nloptr would allow either an L1-norm or an L2-norm. $\endgroup$ – John May 20 '15 at 15:29
  • $\begingroup$ Yes, @Richard, you are correct that quadprog won't work. Can you recommend any alternative packages? $\endgroup$ – Antonius Gavin May 21 '15 at 10:37
  • $\begingroup$ I edited and took into account the comment of John about the package nloptr. $\endgroup$ – Ric May 21 '15 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$ – Antonius Gavin May 21 '15 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$ – Ric May 21 '15 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$
  • $\begingroup$ This is a very clever solution. $\endgroup$ – Antonius Gavin May 26 '15 at 11:03
  • 1
    $\begingroup$ Really very clever! In short $y_i = |w_i|$ -> right? $\endgroup$ – Ric May 26 '15 at 12:05
  • $\begingroup$ @Richard exactly. Absolutely excellent. $\endgroup$ – Antonius Gavin May 26 '15 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 May 26 '15 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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