Source: Idzorek, T. M. (2004, July 20). A STEP-BY-STEP GUIDE TO THE BLACK-LITTERMAN MODEL.
(Note: "returns" always refers to returns in excess of the risk-free rate)
The Black-Litterman model takes prior return data for a collection of asset classes, and a manager's views on future returns in those asset classes, and estimates the future distribution of returns. This can be used to determine the optimal weights for a portfolio in those asset classes.
BLP.py provides the Model class to implement the B-L model and determine the optimal weights in a collection of asset classes to maximize the Sharpe ratio of the portfolio.
In example_script.py, we use return data from example_returndata.csv to define three models, with the same asset classes and prior weights but different parameters, and print the model information and computed optimal weights to example_output.csv.
You will need Python 3 with pip.
- Clone this github repo OR download and unzip this repo
- Go the downloaded project directory and run:
pip install -r .\requirements.txt
- To test, run:
python example_script.py
- You should see a new file: new_example_output.csv
- Verify that new_example_output.csv matches example_output.csv
- A list of asset classes
- A list of prior weights in the asset classes
- The covariance matrix of the excess returns of the asset classes
- A scalar risk aversion parameter
- tau: a scalar parameter that weights the covariance matrix
- tauv: a scalar parameter that weights the manager's views
- P: a numpy matrix expressing the types of the manager's views. See 'Example parameters' below for an explanation. P should have dimensions KxN, where K is the number of views and N is the number of asset classes
- Q: a numpy matrix expressing the quantities of the manager's views. See 'Example parameters' below for an explanation. Q should have dimensions Kx1, where K is the number of views
- An optional identifier, which can be a string or a scalar
For the first model in example_script.py, we use:
model_one = BLP.Model.fromPriorData(
assetClasses=['US Equity', 'Foreign EQ', 'Emerging EQ'],
assetWeights=[0.5, 0.4, 0.1],
riskAversion=3,
covMatrix=covMatrix,
tau=0.1,
tauv=0.1,
P=np.asarray(
[[1,0,0],
[0,1,-1]]
),
Q=np.asarray(
[[0.015],
[0.03]]
),
identifier=1
)
(the covariance matrix is a pandas DataFrame with values [[0.001846, 0.001599, 0.002031], [0.001599, 0.002438, 0.002393], [0.002031, 0.002393, 0.004383]]
)
P and Q express the views. Each row of P and Q represents a view about the performance of the asset classes in the near future. Views can be absolute or relative.
For example, the first rows of P and Q are [1,0,0]
and [0.015]
. This corresponds to the view that "US Equity (the first column) will earn 1.5% excess returns". This is an absolute view - it pertains to the absolute performance of one asset class.
The second rows of P and Q are [0,1,-1]
and [0.03]
. This corresponds to the view that "Foreign EQ (the second column) will outperform Emerging EQ (the third column) by 3%". This is a relative view - it pertains to the relative performance of two asset classes.
To access the optimal portfolio, use Model.optimalPortfolio:
print(model.optimalPortfolio)
{
'weights': [0.6264713805169178, 0.7083398924977391, -0.33481127301465685],
'returns': 0.0072094451581498666,
'sd': 0.044395302498840196,
'sharpe': 0.16239207196162725
}
To access the expected returns and covariance matrix of the estimated distribution of excess returns, use Model.posteriorDistribution():
estReturns, estCov = model.posteriorDistribution()
print(estReturns)
[0.00617828 0.00746541 0.00582155]
print(estCov)
[[0.00193794 0.00167853 0.00213255]
[0.00167853 0.00260806 0.00256085]
[0.00213255 0.00256085 0.00465072]]
To access a pandas DataFrame containing all information about the parameters and results of the model, use Model.df:
model.df.to_csv('model_results.csv')