Optimal Investing with the Markowitz Model
by Jason Schattman, Waterloo Maple, Inc., October 2000
Introduction
Suppose your stock broker passes you a hot stock tip. You're tempted to sell some of your current investments to buy this stock. However, doing so will add risk to your portfolio because the stock's price jumps or falls wildly during any given month. The reallocation will also cost you some commission fees. Is the potential increase in return obtained by buying the stock worth the added risk and costs? More generally, how should you allocate investment capital among thousands of investment opportunities?
To address these questions, we start by stating the two competing goals of investment: (1) long-term growth of net worth, and (2) low risk. A good portfolio grows consistently without wild short-term fluctuations in value. Investing solely in technology stocks will probably yield greater long-term return than investing solely in utilities but will subject the investor's portfolio to stomach-churning roller coaster rides with every quarterly earnings report. Our question then becomes, how do you choose a portfolio that optimally balances long-term return against short-term risk?
The idea is to allocate capital among investments that have good long-term prospects individually but balance each other out in the short-term. For instance, during months when dotcoms go up, utilities tend to go down, and vice versa. The Markowitz Model, proposed in 1952 by Harry Markowitz, is an optimization model for balancing the expected return and risk of a portfolio. The model uses the statistical variance of a stock's price as the measure of its risk and its expected return as the measure of its long-term prospects. The decision variables are the amounts you invest in each asset. The objective is to minimize the overall variance of the portfolio's return, subject to the constraints that (1) the expected return of the portfolio is at least some target level, and (2) you don't invest more capital than you have. You can also add constraints that forbid selling the assets short.
We implement the Markowitz Model using the NonlinearProgramming package.
Setting up the Markowitz Model
We first load the necessary packages.
> restart;
> libname:="C:/mylib/nlp",libname:
> with(NonlinearProgramming);
> with(LinearAlgebra): with(linalg):
Warning, the previous binding of the name GramSchmidt has been removed and it now has an assigned value
Warning, the protected names norm and trace have been redefined and unprotected
Suppose for simplicity that we will allocate our investment capital among four assets.
> numAssets := 4;
Our decision variables are how much of each asset to buy.
> buy := Vector( [seq(x[i], i=1..numAssets)]);
Constraint #1: We cannot invest more capital c than we have.
> budgetConstraint := add(buy[i],i=1..numAssets) <= c;
We assume we have estimates for the expected rates of return for each asset over the given horizon.
> expectedRates := Vector( [seq(r[i], i=1..numAssets)] );
The total expected return of the portfolio is the dot product of the buy amounts and the expected rates of return.
> expectedReturn := Multiply( Transpose(expectedRates), buy );
Constraint #2: The total expected return must meet our target, which can be expressed as a "goal rate" times our initial capital c .
> returnConstraint := expectedReturn >= c * goalRate;
To derive the variance of the portfolio's return, we need the matrix of covariances for the assets' returns. The (i,j) element of the matrix is the covariance of the returns of assets i and j.
> Q := Matrix( [ seq( [seq( cov[i,j], j=1..numAssets)], i=1..numAssets)] );
The objective is to minimize the variance of the portfolio's total return, subject to constraints #1 and #2
. It can be shown that
, where Q is the covariance matrix of the random vector
r.
We now form this quantity.
> buy_T := Transpose( buy );
> variance := expand( Multiply( buy_T, Multiply( Q, buy ) ) );
Notice that the variance is a quadratic function of the decision variables.
Solving the model with nonlinear programming
We're now ready to read in data and solve the optimization problem. Let's suppose the four assets under consideration have estimated rates of return over the next year of 5%, 10%, 15% and 30%, respectively.
> r := <.05, .10, .15, .30>;
Although asset 1 has a lower expected return, it's price also has a lower variance (.08) and is negatively correlated with the other assets' prices (-.05). Assets 3 and 4 have high expected returns but high variances (.35 each) and are positively correlated (.06) with each other.
>
cov := << .08,-.05,-.05,-.05> |
<-.05, .16,-.02,-.02> |
<-.05,-.02, .35, .06> |
<-.05,-.02, .06, .35>>;
We now have a well defined objective function (variance) that we wish to minimize.
> variance;
Let's assume we will not settle for a total expected annual return rate less than 10%, and we have $10,000 to invest.
> goalRate:=.10; c :=10000;
Our two constraints are now well defined.
> returnConstraint;
> budgetConstraint;
Finally, we solve the optimization problem generated from the above data. We first set the information level to 2, meaning we want the algorithm to report all iterations. If we only wanted the final answer, we would use level 1.
> infolevel['Optimize']:=2: infolevel['PrimalDualLogBarrier']:=2:
The parameters to the procedure Optimize(...) are as follows: the objective is variance , we want to minimize , we have 4 decision variables, the constraints are budgetConstraint and returnConstraint , we specifiy we want nonnegative decision variables (i.e. short selling prohibited), and we choose as starting point (2500, 2500, 2500, 2500) . That is, our default plan is to invest evenly in all assets. The primal-dual log-barrier optimization algorithm will start from there and search for better allocations.
> Optimize( variance, min, 4, {budgetConstraint, returnConstraint}, nonnegative, <c/4, c/4, c/4, c/4>);
OptimizeInteriorPointMethod: Constrained convex problem: solving with convex primal-dual log-barrier algorithm
PrimalDualLogBarrier: Minimize
PrimalDualLogBarrier: subject to [0 <= x[3], 0 <= x[1], 0 <= x[2], 0 <= x[4], 0 <= -1000.00+.5e-1*x[1]+.10*x[2]+.15*x[3]+.30*x[4], 0 <= -x[1]-x[2]-x[3]-x[4]+10000]
PrimalDualLogBarrier: Starting point
PrimalDualLogBarrier:
InitialBarrierParameter: Initial barrier parameter 167497.9303
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier: Global optimum found at
Thus, among all allocations with expected return of 10% or higher, investing $3663 in asset 1, $2208 in asset 2, $906 in asset 3 and $1534 in asset 4 is the one with minimum variance.
What if we revise our estimates? Suppose we expect asset 4 to plummet next year. Let's run the model again with the new return data. We'll use a new starting point (c/3, c/3, c/3, 0) that's closer to our expectations of the optimal allocation.
> r[4] := -.20;
> expectedReturn; returnConstraint;
> Optimize( variance, min, 4, {budgetConstraint, returnConstraint}, nonnegative, <c/3,c/3,c/3,0>);
OptimizeInteriorPointMethod: Constrained convex problem: solving with convex primal-dual log-barrier algorithm
PrimalDualLogBarrier: Minimize
PrimalDualLogBarrier: subject to [0 <= -1000.00+.5e-1*x[1]+.10*x[2]+.15*x[3]-.20*x[4], 0 <= x[3], 0 <= x[1], 0 <= x[2], 0 <= x[4], 0 <= -x[1]-x[2]-x[3]-x[4]+10000]
PrimalDualLogBarrier: Starting point
PrimalDualLogBarrier:
InitialBarrierParameter: Initial barrier parameter 192450.0984
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier: Global optimum found at
The model predicts we should invest $0 in asset 4, as expected. The optimal allocation among the other three takes up the slack.
Given that we expect asset 4 to fall so drastically, we might consider selling it short. What happens to our optimal allocation if we allow short selling? To find out, we run the model again, but this time change the nonnegative parameter to free. This lifts the restriction that the decision variables be nonnegative.
> Optimize( variance, min, 4, {budgetConstraint, returnConstraint}, free, <c/4,c/4,c/4,c/4>);
OptimizeInteriorPointMethod: Constrained convex problem: solving with convex primal-dual log-barrier algorithm
PrimalDualLogBarrier: Minimize
PrimalDualLogBarrier: subject to [0 <= -x[1]-x[2]-x[3]-x[4]+10000, 0 <= -1000.00+.5e-1*x[1]+.10*x[2]+.15*x[3]-.50*x[4]]
PrimalDualLogBarrier: Starting point
PrimalDualLogBarrier:
InitialBarrierParameter: Initial barrier parameter 150000.
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier:
PrimalDualLogBarrier: Global optimum found at
The model recommends we sell asset 4 short by $1496. Why does it recommend such small investments in the other assets? Recall we set our target return to 10%. The model finds the allocation of minimum variance that will achieve this target. Apparently, the short sale of asset 4 by itself is almost enough to get a 10% total expected return. Allocating more funds to the others would raise the variance.