QP Portfolio › Visualizing Portfolio Optimization

Michael BrenndoerferSeptember 7, 20254 min read
Machine Learning from ScratchAll chapters
Part 9 of 9Optimization
Chapter 64QP Portfolio › Visualizing Portfolio Optimization
Reading section 3 of 8 · Visualizing Portfolio Optimization · 4 minSection 3 of 8 · 4 min

Book contents

Section 3 of 8 · 4 min read

QP Portfolio › Visualizing Portfolio OptimizationOne section · Sections in this chapter3 / 8 ↓
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]:
Code
import 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]:
Console
Expected 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.0001
Out[7]:
Visualization
Heatmap showing correlation coefficients between five asset classes: Stocks, Bonds, Commodities, Real Estate, and Cash.
Correlation matrix showing relationships between asset class returns. Stocks have positive correlation with REITs (0.31), Bonds (0.28), and Commodities (0.23), while Bonds exhibit low correlation with the remaining assets. Cash has low correlation with all assets due to its minimal volatility.

Now let's visualize the efficient frontier by solving the optimization problem for different target returns:

In[8]:
Code
def 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
Scatter plot showing efficient frontier curve with individual asset points, displaying optimal risk-return combinations for portfolio optimization.
The efficient frontier showing the optimal risk-return trade-off for a five-asset portfolio. The red curve represents portfolios that offer the highest expected return for each level of risk. Individual assets are shown as blue dots, with Cash offering the lowest risk/return and Stocks the highest. The green star marks the minimum variance portfolio.