Smarter portfolio diversification with Black-Litterman

December 7, 2024
Facebook logo.
Twitter logo.
LinkedIn logo.
Get this code in Google Colab

Smarter portfolio diversification with Black-Litterman

In today's newsletter, we're going to dive deep into the Black-Litterman model.

This powerful tool, used by professional investors worldwide, combines personal views on asset performance with historical market data to create a personalized asset allocation strategy.

By the end of this issue, you'll have the Python code and understanding to use the Black-Litterman model just like the pros.

Let's get started!

Smarter portfolio diversification with Black-Litterman

The Black-Litterman model is a tool for optimizing investment portfolios by combining market equilibrium with investor insights. Developed by Fischer Black and Robert Litterman, it aims to create balanced portfolios that avoid extreme allocations.

In practice, the model starts by calculating equilibrium returns using CAPM and market weights. Investor views are then incorporated using a Bayesian approach, adjusting these returns based on subjective insights. This process results in diversified portfolios that reflect both market conditions and personal expectations.

Professionals use the Black-Litterman model to tailor portfolios, incorporating their market views while maintaining stability. It helps institutional investors achieve better diversification and adapt to market changes. Let's see how it works with Python.

Imports and set up

We’ll use PyPortfolioOpt for the analysis along with pandas and yFinance.

1import pandas as pd
2import yfinance as yf
3
4from pypfopt import expected_returns, risk_models, black_litterman
5from pypfopt.black_litterman import BlackLittermanModel
6from pypfopt.efficient_frontier import EfficientFrontier
7
8import warnings
9warnings.filterwarnings("ignore")

We start by downloading the historical stock price data for a set of companies. We use Yahoo Finance to get the data.

1mag_7 = [
2    "AAPL",
3    "AMZN",
4    "NVDA",
5    "TLSA",
6    "GOOGL",
7    "META",
8    "MSFT",
9]
10
11prices = yf.download(mag_7, start="2020-01-01")["Adj Close"]

We define a list of major tech companies, often referred to as the "Magnificent 7". We then use the yfinance library to download the adjusted closing price of these stocks starting from January 1, 2020. This data will be used to calculate returns and risks for our portfolio optimization.

Define our views and market capitalizations

Next, we define our own views on the expected returns for each stock and gather market capitalization data.

1views = {
2    "AAPL": 0.05,
3    "AMZN": 0.15,
4    "NVDA": 0.25,
5    "TLSA": -0.05,
6    "GOOGL": -0.15,
7    "META": 0.07,
8    "MSFT": 0.12
9}
10
11mcaps = {
12    "AAPL": 2.5e12,
13    "AMZN": 1.3e12,
14    "NVDA": 1.0e12,
15    "TLSA": 0.9e12,
16    "GOOGL": 1.4e12,
17    "META": 0.7e12,
18    "MSFT": 2.0e12,
19}

We define our views on the expected returns for each stock. These views represent our subjective beliefs about the future performance of these companies. For example, we expect Apple's return to be 5% and Amazon's to be 15%.

Additionally, we provide the market capitalizations of each company, which reflect their total market value. This information will be used in the Black-Litterman model to incorporate market views.

Calculate expected returns and covariance

We calculate historical expected returns and the covariance matrix to assess the risk and return of our portfolio.

1expected_returns_mean = expected_returns.mean_historical_return(prices)
2cov_matrix = risk_models.sample_cov(prices)
3
4delta = black_litterman.market_implied_risk_aversion(prices)
5market_prior = black_litterman.market_implied_prior_returns(mcaps, delta, cov_matrix)

We compute the historical expected returns for each company using the mean of their historical returns. The covariance matrix measures how the returns of the stocks move together, providing insight into the portfolio's risk.

We also calculate the market's implied risk aversion, which reflects the market's overall attitude towards risk. With the market capitalizations and risk aversion, we estimate the market's prior expected returns, which serve as a baseline before incorporating our views.

Create a Black-Litterman model and optimize the portfolio

We create a Black-Litterman model using our views and optimize the portfolio to maximize the Sharpe ratio.

1bl = BlackLittermanModel(
2    cov_matrix,
3    absolute_views=views,
4    pi=market_prior
5)
6
7bl_returns = bl.bl_returns()
8
9ef = EfficientFrontier(bl_returns, cov_matrix)
10
11weights = ef.max_sharpe()
12
13bl_weights = pd.DataFrame(
14    list(weights.items()), 
15    columns=["symbol", "weight"]
16).set_index("symbol")
17
18performance = ef.portfolio_performance(verbose=True)

We create a Black-Litterman model using the covariance matrix, our views on expected returns, and the market's prior returns. This model adjusts the market's baseline expectations with our views, resulting in a set of expected returns that reflect both market data and personal insights.

We then use these adjusted returns to construct an efficient frontier, which shows the best possible returns for a given level of risk.

We optimize the portfolio to achieve the maximum Sharpe ratio, which balances risk and return, and derive the optimal weights for each stock. The calculated performance metrics provide an overview of the portfolio's return, volatility, and risk-adjusted return.

Your next steps

Try experimenting with different views on the expected returns for each stock. You can adjust the values in the "views" dictionary to see how they affect the optimized portfolio weights. This exercise will help you understand the impact of subjective beliefs on portfolio construction and risk management.

Man with glasses and a wristwatch, wearing a white shirt, looking thoughtfully at a laptop with a data screen in the background.