Accelerating the pace of engineering and science

# Documentation Center

• Trial Software

## Portfolio Optimization (Black Litterman Approach)

This example shows how to generate a MEX function and C source code from MATLAB code that performs portfolio optimization using the Black Litterman approach.

Prerequisites

To run this example, you must install a C compiler and set it up using the 'mex -setup' command. For more information, see Setting Up Your C CompilerSetting Up Your C Compiler.

Create a New Folder and Copy Relevant Files

The following code will create a folder in your current working folder (pwd). The new folder will only contain the files that are relevant for this example. If you do not want to affect the current folder (or if you cannot generate files in this folder), you should change your working folder.

Run Command: Create a New Folder and Copy Relevant Files

```coderdemo_setup('coderdemo_portfolio_optimization');
```

The hblblacklitterman.mhblblacklitterman.m function reads in financial information regarding a portfolio and performs portfolio optimization using the Black Litterman approach.

```type hlblacklitterman
```
```function [er, ps, w, pw, lambda, theta] = hlblacklitterman(delta, weq, sigma, tau, P, Q, Omega)%#codegen
% hlblacklitterman
%   This function performs the Black-Litterman blending of the prior
%   and the views into a new posterior estimate of the returns as
%   described in the paper by He and Litterman.
% Inputs
%   delta  - Risk tolerance from the equilibrium portfolio
%   weq    - Weights of the assets in the equilibrium portfolio
%   sigma  - Prior covariance matrix
%   tau    - Coefficiet of uncertainty in the prior estimate of the mean (pi)
%   P      - Pick matrix for the view(s)
%   Q      - Vector of view returns
%   Omega  - Matrix of variance of the views (diagonal)
% Outputs
%   Er     - Posterior estimate of the mean returns
%   w      - Unconstrained weights computed given the Posterior estimates
%            of the mean and covariance of returns.
%   lambda - A measure of the impact of each view on the posterior estimates.
%   theta  - A measure of the share of the prior and sample information in the
%            posterior precision.

% Reverse optimize and back out the equilibrium returns
% This is formula (12) page 6.
pi = weq * sigma * delta;
% We use tau * sigma many places so just compute it once
ts = tau * sigma;
% Compute posterior estimate of the mean
% This is a simplified version of formula (8) on page 4.
er = pi' + ts * P' * inv(P * ts * P' + Omega) * (Q - P * pi');
% We can also do it the long way to illustrate that d1 + d2 = I
d = inv(inv(ts) + P' * inv(Omega) * P);
d1 = d * inv(ts);
d2 = d * P' * inv(Omega) * P;
er2 = d1 * pi' + d2 * pinv(P) * Q;
% Compute posterior estimate of the uncertainty in the mean
% This is a simplified and combined version of formulas (9) and (15)
ps = ts - ts * P' * inv(P * ts * P' + Omega) * P * ts;
posteriorSigma = sigma + ps;
% Compute the share of the posterior precision from prior and views,
% then for each individual view so we can compare it with lambda
theta=zeros(1,2+size(P,1));
theta(1,1) = (trace(inv(ts) * ps) / size(ts,1));
theta(1,2) = (trace(P'*inv(Omega)*P* ps) / size(ts,1));
for i=1:size(P,1)
theta(1,2+i) = (trace(P(i,:)'*inv(Omega(i,i))*P(i,:)* ps) / size(ts,1));
end
% Compute posterior weights based solely on changed covariance
w = (er' * inv(delta * posteriorSigma))';
% Compute posterior weights based on uncertainty in mean and covariance
pw = (pi * inv(delta * posteriorSigma))';
% Compute lambda value
% We solve for lambda from formula (17) page 7, rather than formula (18)
% just because it is less to type, and we've already computed w*.
lambda = pinv(P)' * (w'*(1+tau) - weq)';
end

% Black-Litterman example code for MatLab (hlblacklitterman.m)
% Copyright (c) Jay Walters, blacklitterman.org, 2008.
%
% Redistribution and use in source and binary forms,
% with or without modification, are permitted provided
% that the following conditions are met:
%
% Redistributions of source code must retain the above
% copyright notice, this list of conditions and the following
% disclaimer.
%
% Redistributions in binary form must reproduce the above
% copyright notice, this list of conditions and the following
% disclaimer in the documentation and/or other materials
% provided with the distribution.
%
% Neither the name of blacklitterman.org nor the names of its
% contributors may be used to endorse or promote products
% derived from this software without specific prior written
% permission.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
% CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
% DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
% CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
% SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
% BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
% WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
% NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
% DAMAGE.
%
% This program uses the examples from the paper "The Intuition
% Behind Black-Litterman Model  Portfolios", by He and Litterman,
% 1999.  You can find a copy of this  paper at the following url.
%     http:%papers.ssrn.com/sol3/papers.cfm?abstract_id=334304
%
% For more details on the Black-Litterman model you can also view
% "The BlackLitterman Model: A Detailed Exploration", by this author
% at the following url.
%     http:%www.blacklitterman.org/Black-Litterman.pdf
%
```

The %#codegen directive indicates that the MATLAB code is intended for code generation.

Generate the MEX Function for Testing

Generate a MEX function using the 'codegen' command.

```codegen hlblacklitterman -args {0, zeros(1, 7), zeros(7,7), 0, zeros(1, 7), 0, 0}
```

Before generating C code, you should first test the MEX function in MATLAB to ensure that it is functionally equivalent to the original MATLAB code and that no run-time errors occur. By default, 'codegen' generates a MEX function named 'hlblacklitterman_mex' in the current folder. This allows you to test the MATLAB code and MEX function and compare the results.

Run the MEX Function

Call the generated MEX function

```testMex();
```
```View 1
Country        P       mu      w*
Australia	     0	 4.328	 1.524
France   	 -29.5	 9.288	-3.948
Germany  	   100	 11.04	 35.41
Japan    	     0	 4.506	 11.05
UK       	 -70.5	 6.953	-9.462
USA      	     0	 8.069	 58.57
q        	     5
omega/tau	     0.0213
lambda   	     0.317
theta   	     0.0714
pr theta  	     0.929

View 1
Country        P       mu      w*
Australia	     0	 4.328	 1.524
France   	 -29.5	 9.288	-3.948
Germany  	   100	 11.04	 35.41
Japan    	     0	 4.506	 11.05
UK       	 -70.5	 6.953	-9.462
USA      	     0	 8.069	 58.57
q        	     5
omega/tau	     0.0213
lambda   	     0.317
theta   	     0.0714
pr theta  	     0.929

Execution Time - MATLAB function: 0.025513 seconds
Execution Time - MEX function   : 0.0029123 seconds
```

Generate C Code

```cfg = coder.config('lib');
codegen -config cfg hlblacklitterman  -args {0, zeros(1, 7), zeros(7,7), 0, zeros(1, 7), 0, 0}
```

Using 'codegen' with the specified '-config cfg' option produces a standalone C library.

Inspect the Generated Code

By default, the code generated for the library is in the folder codegen/lib/hbblacklitterman/

The files are:

```dir codegen/lib/hlblacklitterman/
```
```.                                inv.c
..                               inv.h
buildInfo.mat                    inv.obj
codeInfo.mat                     pinv.c
hlblacklitterman.c               pinv.h
hlblacklitterman.h               pinv.obj
hlblacklitterman.lib             rtGetInf.c
hlblacklitterman.obj             rtGetInf.h
hlblacklitterman_initialize.c    rtGetInf.obj
hlblacklitterman_initialize.h    rtGetNaN.c
hlblacklitterman_initialize.obj  rtGetNaN.h
hlblacklitterman_ref.rsp         rtGetNaN.obj
hlblacklitterman_rtw.bat         rt_nonfinite.c
hlblacklitterman_rtw.mk          rt_nonfinite.h
hlblacklitterman_terminate.c     rt_nonfinite.obj
hlblacklitterman_terminate.h     rtw_proj.tmw
hlblacklitterman_terminate.obj   rtwtypes.h
hlblacklitterman_types.h
interface

```

Inspect the C Code for the 'hlblacklitterman.c' Function

```type codegen/lib/hlblacklitterman/hlblacklitterman.c
```
```/*
* hlblacklitterman.c
*
* Code generation for function 'hlblacklitterman'
*
* C source code generated on: Fri Aug 09 01:28:13 2013
*
*/

/* Include files */
#include "rt_nonfinite.h"
#include "hlblacklitterman.h"
#include "pinv.h"
#include "inv.h"

/* Function Definitions */
void hlblacklitterman(double delta, const double weq[7], const double sigma[49],
double tau, const double P[7], double Q, double Omega,
double er[7], double ps[49], double w[7], double pw[7],
double *lambda, double theta[3])
{
double b_weq[7];
double pi[7];
int i0;
int k;
double ts[49];
double y;
double b_y[7];
double c_y;
double b_ts[7];
double unusedExpr[7];
double c_ts[7];
double d_ts[49];
int i1;
double posteriorSigma[49];
double d_y[49];
double x[49];

/*  hlblacklitterman */
/*    This function performs the Black-Litterman blending of the prior */
/*    and the views into a new posterior estimate of the returns as */
/*    described in the paper by He and Litterman. */
/*  Inputs */
/*    delta  - Risk tolerance from the equilibrium portfolio */
/*    weq    - Weights of the assets in the equilibrium portfolio */
/*    sigma  - Prior covariance matrix */
/*    tau    - Coefficiet of uncertainty in the prior estimate of the mean (pi) */
/*    P      - Pick matrix for the view(s) */
/*    Q      - Vector of view returns */
/*    Omega  - Matrix of variance of the views (diagonal) */
/*  Outputs */
/*    Er     - Posterior estimate of the mean returns */
/*    w      - Unconstrained weights computed given the Posterior estimates */
/*             of the mean and covariance of returns. */
/*    lambda - A measure of the impact of each view on the posterior estimates. */
/*    theta  - A measure of the share of the prior and sample information in the */
/*             posterior precision. */
/*  Reverse optimize and back out the equilibrium returns */
/*  This is formula (12) page 6. */
for (i0 = 0; i0 < 7; i0++) {
b_weq[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_weq[i0] += weq[k] * sigma[k + 7 * i0];
}

pi[i0] = b_weq[i0] * delta;
}

/*  We use tau * sigma many places so just compute it once */
for (i0 = 0; i0 < 49; i0++) {
ts[i0] = tau * sigma[i0];
}

/*  Compute posterior estimate of the mean */
/*  This is a simplified version of formula (8) on page 4. */
y = 0.0;
for (i0 = 0; i0 < 7; i0++) {
b_y[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_y[i0] += P[k] * ts[k + 7 * i0];
}

y += b_y[i0] * P[i0];
}

y = 1.0 / (y + Omega);
c_y = 0.0;
for (k = 0; k < 7; k++) {
c_y += P[k] * pi[k];
b_ts[k] = 0.0;
for (i0 = 0; i0 < 7; i0++) {
b_ts[k] += ts[k + 7 * i0] * P[i0];
}
}

c_y = Q - c_y;
for (i0 = 0; i0 < 7; i0++) {
er[i0] = pi[i0] + b_ts[i0] * y * c_y;
}

/*  We can also do it the long way to illustrate that d1 + d2 = I */
pinv(P, unusedExpr);

/*  Compute posterior estimate of the uncertainty in the mean */
/*  This is a simplified and combined version of formulas (9) and (15) */
y = 0.0;
for (i0 = 0; i0 < 7; i0++) {
b_y[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_y[i0] += P[k] * ts[k + 7 * i0];
}

y += b_y[i0] * P[i0];
c_ts[i0] = 0.0;
for (k = 0; k < 7; k++) {
c_ts[i0] += ts[i0 + 7 * k] * P[k];
}
}

y = 1.0 / (y + Omega);
for (i0 = 0; i0 < 7; i0++) {
b_ts[i0] = c_ts[i0] * y;
for (k = 0; k < 7; k++) {
d_ts[i0 + 7 * k] = b_ts[i0] * P[k];
}
}

for (i0 = 0; i0 < 7; i0++) {
for (k = 0; k < 7; k++) {
c_y = 0.0;
for (i1 = 0; i1 < 7; i1++) {
c_y += d_ts[i0 + 7 * i1] * ts[i1 + 7 * k];
}

ps[i0 + 7 * k] = ts[i0 + 7 * k] - c_y;
}
}

for (i0 = 0; i0 < 49; i0++) {
posteriorSigma[i0] = sigma[i0] + ps[i0];
}

/*  Compute the share of the posterior precision from prior and views, */
/*  then for each individual view so we can compare it with lambda */
invNxN(ts, d_y);
c_y = 0.0;
for (i0 = 0; i0 < 7; i0++) {
for (k = 0; k < 7; k++) {
x[i0 + 7 * k] = 0.0;
for (i1 = 0; i1 < 7; i1++) {
x[i0 + 7 * k] += d_y[i0 + 7 * i1] * ps[i1 + 7 * k];
}
}

c_y += x[i0 + 7 * i0];
}

theta[0] = c_y / 7.0;
y = 1.0 / Omega;
c_y = 0.0;
for (i0 = 0; i0 < 7; i0++) {
for (k = 0; k < 7; k++) {
d_ts[i0 + 7 * k] = P[i0] * y * P[k];
}

for (k = 0; k < 7; k++) {
d_y[i0 + 7 * k] = 0.0;
for (i1 = 0; i1 < 7; i1++) {
d_y[i0 + 7 * k] += d_ts[i0 + 7 * i1] * ps[i1 + 7 * k];
}
}

c_y += d_y[i0 + 7 * i0];
}

theta[1] = c_y / 7.0;
y = 1.0 / Omega;
c_y = 0.0;
for (i0 = 0; i0 < 7; i0++) {
for (k = 0; k < 7; k++) {
d_ts[i0 + 7 * k] = P[i0] * y * P[k];
}

for (k = 0; k < 7; k++) {
d_y[i0 + 7 * k] = 0.0;
for (i1 = 0; i1 < 7; i1++) {
d_y[i0 + 7 * k] += d_ts[i0 + 7 * i1] * ps[i1 + 7 * k];
}
}

c_y += d_y[i0 + 7 * i0];
}

theta[2] = c_y / 7.0;

/*  Compute posterior weights based solely on changed covariance */
for (i0 = 0; i0 < 49; i0++) {
d_y[i0] = delta * posteriorSigma[i0];
}

invNxN(d_y, x);
for (i0 = 0; i0 < 7; i0++) {
b_weq[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_weq[i0] += er[k] * x[k + 7 * i0];
}

w[i0] = b_weq[i0];
}

/*  Compute posterior weights based on uncertainty in mean and covariance */
for (i0 = 0; i0 < 49; i0++) {
posteriorSigma[i0] *= delta;
}

invNxN(posteriorSigma, d_y);
for (i0 = 0; i0 < 7; i0++) {
b_weq[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_weq[i0] += pi[k] * d_y[k + 7 * i0];
}

pw[i0] = b_weq[i0];
}

/*  Compute lambda value */
/*  We solve for lambda from formula (17) page 7, rather than formula (18) */
/*  just because it is less to type, and we've already computed w*. */
pinv(P, b_ts);
*lambda = 0.0;
for (i0 = 0; i0 < 7; i0++) {
pi[i0] = b_ts[i0];
b_weq[i0] = 0.0;
for (k = 0; k < 7; k++) {
b_weq[i0] += er[k] * x[k + 7 * i0];
}

b_ts[i0] = b_weq[i0] * (1.0 + tau) - weq[i0];
*lambda += pi[i0] * b_ts[i0];
}

/*  Black-Litterman example code for MatLab (hlblacklitterman.m) */
/*  Copyright (c) Jay Walters, blacklitterman.org, 2008. */
/*  */
/*  Redistribution and use in source and binary forms,  */
/*  with or without modification, are permitted provided  */
/*  that the following conditions are met: */
/*  */
/*  Redistributions of source code must retain the above  */
/*  copyright notice, this list of conditions and the following  */
/*  disclaimer. */
/*   */
/*  Redistributions in binary form must reproduce the above  */
/*  copyright notice, this list of conditions and the following  */
/*  disclaimer in the documentation and/or other materials  */
/*  provided with the distribution. */
/*    */
/*  Neither the name of blacklitterman.org nor the names of its */
/*  contributors may be used to endorse or promote products  */
/*  derived from this software without specific prior written */
/*  permission. */
/*    */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND  */
/*  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,  */
/*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF  */
/*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  */
/*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR  */
/*  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,  */
/*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,  */
/*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  */
/*  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
/*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  */
/*  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING  */
/*  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  */
/*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH  */
/*  DAMAGE. */
/*  */
/*  This program uses the examples from the paper "The Intuition  */
/*  Behind Black-Litterman Model  Portfolios", by He and Litterman, */
/*  1999.  You can find a copy of this  paper at the following url. */
/*      http:%papers.ssrn.com/sol3/papers.cfm?abstract_id=334304 */
/*  */
/*  For more details on the Black-Litterman model you can also view */
/*  "The BlackLitterman Model: A Detailed Exploration", by this author */
/*  at the following url. */
/*      http:%www.blacklitterman.org/Black-Litterman.pdf */
/*  */
}

/* End of code generation (hlblacklitterman.c) */
```

Cleanup

```cleanup