Skip to main content
Article
portfolio-managementquantitative-financepythonpyportfoliooptmean-variance-optimizationsharpe-ratioyfinance

Simulate Portfolio Optimization with Python

BlackRock's Portfolio Optimizer is an institutional tool. We'll replicate its core function—mean-variance optimization—using the open-source PyPortfolioOpt library in Python to find an optimal asset allocation that maximizes risk-adjusted returns.

intermediate15 min4 steps
The play
  1. Install Dependencies and Fetch Data
    The Portfolio Optimizer agent requires historical market data to model risk and returns. We'll simulate this by installing the necessary Python libraries and using `yfinance` to download daily price data for a sample of tickers.
  2. Calculate Expected Returns and Covariance
    Mean-variance optimization, a core capability of the Portfolio Optimizer, needs two key inputs: expected returns and the covariance matrix of asset returns. We'll use helper methods from PyPortfolioOpt to calculate these from our historical price data.
  3. Run Mean-Variance Optimization
    With our inputs ready, we'll instantiate the `EfficientFrontier` object. We then call the `max_sharpe()` method to solve for the portfolio weights that maximize the Sharpe ratio, representing the most efficient portfolio in terms of risk-adjusted return.
  4. Review the Optimal Portfolio
    The output of the optimization is a dictionary of asset weights. We'll print these weights and the portfolio's expected performance (annual return, volatility, and Sharpe ratio) to see the final, optimized allocation.
Starter code
import yfinance as yf
import pandas as pd
from pypfopt.efficient_frontier import EfficientFrontier
from pypfopt import risk_models
from pypfopt import expected_returns

# This script simulates the core function of the Portfolio Optimizer agent
# by finding the optimal asset allocation for a given set of stocks.

def optimize_portfolio(tickers, start_date="2020-01-01", end_date="2023-01-01"):
    """Fetches stock data, performs MVO, and prints the optimal portfolio."""
    print(f"Optimizing portfolio for: {', '.join(tickers)}\n")

    # 1. Fetch historical price data
    try:
        df = yf.download(tickers, start=start_date, end=end_date)["Adj Close"]
        if df.empty:
            print("Could not download data. Check tickers and date range.")
            return
    except Exception as e:
        print(f"Error downloading data: {e}")
        return

    # 2. Calculate expected returns and the covariance matrix
    mu = expected_returns.mean_historical_return(df)
    S = risk_models.sample_cov(df)

    # 3. Perform Mean-Variance Optimization to maximize Sharpe Ratio
    ef = EfficientFrontier(mu, S)
    weights = ef.max_sharpe()
    cleaned_weights = ef.clean_weights()

    # 4. Display results
    print("Optimal Weights:")
    print(pd.Series(cleaned_weights).to_string())
    print("\n--------------------------------------\n")
    print("Expected Portfolio Performance:")
    ef.portfolio_performance(verbose=True)

if __name__ == '__main__':
    # Define the universe of assets for the portfolio
    # You can change these to any tickers available on Yahoo Finance
    portfolio_tickers = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'JPM']
    
    optimize_portfolio(portfolio_tickers)
Simulate Portfolio Optimization with Python — Action Pack