QP Portfolio › Visualizing Portfolio Optimization
Michael BrenndoerferSeptember 7, 20254 min read
Machine Learning from ScratchAll chapters Part 9 of 9Optimization
QP Portfolio › Visualizing Portfolio OptimizationOne section · Sections in this chapter3 / 8 ↓
Sections in this chapter8
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
With the mathematical framework in place, let's see how these concepts manifest with real asset data. We'll construct a five-asset portfolio and visualize the efficient frontier, the set of optimal portfolios that offer the highest return for each level of risk.
In[6]:
Codeimport warnings
import numpy as np
import pandas as pd
warnings.filterwarnings("ignore")
# Define asset classes
assets = ["Stocks", "Bonds", "Commodities", "REITs", "Cash"]
# Use realistic expected returns directly (annualized)
# These match the values discussed in the Example section
expected_returns = pd.Series(
[0.12, 0.04, 0.08, 0.10, 0.02], # 12%, 4%, 8%, 10%, 2%
index=assets,
)
# Define realistic covariance matrix (annualized)
# Stocks: 20% vol, Bonds: 10% vol, Commodities: 24.5% vol, REITs: 17.3% vol, Cash: ~0% vol
cov_data = np.array(
[
[0.0400, 0.0050, 0.0150, 0.0120, 0.0000], # Stocks
[0.0050, 0.0100, 0.0000, 0.0010, 0.0000], # Bonds
[0.0150, 0.0000, 0.0600, 0.0100, 0.0000], # Commodities
[0.0120, 0.0010, 0.0100, 0.0300, 0.0000], # REITs
[
0.0000,
0.0000,
0.0000,
0.0000,
0.0001,
], # Cash (tiny variance to avoid NaN)
]
)
cov_matrix = pd.DataFrame(cov_data, index=assets, columns=assets)
# Generate sample returns for correlation visualization (using population parameters)
np.random.seed(42)
n_periods = 252
returns_data = np.random.multivariate_normal(
mean=expected_returns.values / 252, # Daily returns
cov=cov_matrix.values / 252, # Daily covariance
size=n_periods,
)
returns_df = pd.DataFrame(returns_data, columns=assets)
print("Expected Annual Returns:")
print(expected_returns.round(4))
print("\nAnnualized Covariance Matrix:")
print(cov_matrix.round(4))Out[6]:
ConsoleExpected Annual Returns:
Stocks 0.12
Bonds 0.04
Commodities 0.08
REITs 0.10
Cash 0.02
dtype: float64
Annualized Covariance Matrix:
Stocks Bonds Commodities REITs Cash
Stocks 0.040 0.005 0.015 0.012 0.0000
Bonds 0.005 0.010 0.000 0.001 0.0000
Commodities 0.015 0.000 0.060 0.010 0.0000
REITs 0.012 0.001 0.010 0.030 0.0000
Cash 0.000 0.000 0.000 0.000 0.0001Out[7]:
Visualization
Now let's visualize the efficient frontier by solving the optimization problem for different target returns:
In[8]:
Codedef portfolio_variance(weights, cov_matrix):
"""Calculate portfolio variance given weights and covariance matrix"""
return np.dot(weights.T, np.dot(cov_matrix, weights))
def portfolio_return(weights, expected_returns):
"""Calculate portfolio expected return given weights and expected returns"""
return np.sum(weights * expected_returns)
def optimize_portfolio(expected_returns, cov_matrix, target_return):
"""Optimize portfolio for given target return using scipy"""
n_assets = len(expected_returns)
# Objective function (minimize variance)
def objective(weights):
return portfolio_variance(weights, cov_matrix)
# Constraints
constraints = [
{"type": "eq", "fun": lambda w: np.sum(w) - 1}, # Budget constraint
{
"type": "eq",
"fun": lambda w: (
portfolio_return(w, expected_returns) - target_return
),
}, # Return constraint
]
# Bounds (no short selling)
bounds = tuple((0, 1) for _ in range(n_assets))
# Initial guess (equal weights)
x0 = np.array([1 / n_assets] * n_assets)
# Optimize
result = minimize(
objective, x0, method="SLSQP", bounds=bounds, constraints=constraints
)
return result.x if result.success else None
# Generate efficient frontier
target_returns = np.linspace(expected_returns.min(), expected_returns.max(), 50)
efficient_weights = []
efficient_returns = []
efficient_risks = []
for target_ret in target_returns:
weights = optimize_portfolio(expected_returns, cov_matrix, target_ret)
if weights is not None:
efficient_weights.append(weights)
efficient_returns.append(portfolio_return(weights, expected_returns))
efficient_risks.append(np.sqrt(portfolio_variance(weights, cov_matrix)))
efficient_returns = np.array(efficient_returns)
efficient_risks = np.array(efficient_risks)Out[9]:
Visualization