portfolio-optimization

majiayu000's avatarfrom majiayu000

Portfolio optimization using PyPortfolioOpt for mean-variance optimization, efficient frontier analysis, risk modeling, and discrete allocation. Use when building investment portfolios, calculating optimal weights, analyzing risk-return tradeoffs, maximizing Sharpe ratio, minimizing volatility, or converting weights to share allocations. Supports HRP, CVaR, semivariance, and custom objectives.

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 5, 2026

When & Why to Use This Skill

This Claude skill provides a comprehensive suite of portfolio optimization tools powered by the PyPortfolioOpt library. It enables users to perform advanced financial engineering tasks, including mean-variance optimization, efficient frontier analysis, and sophisticated risk modeling. By automating complex mathematical frameworks like HRP and CVaR, it helps investors and financial analysts build data-driven investment strategies, maximize risk-adjusted returns (Sharpe ratio), and convert theoretical weights into actionable share allocations.

Use Cases

  • Investment Strategy Construction: Calculate optimal asset weights for a new portfolio to achieve specific financial goals, such as maximizing the Sharpe ratio or minimizing overall volatility.
  • Advanced Risk Management: Utilize robust risk models like Hierarchical Risk Parity (HRP), Semicovariance, and Conditional Value at Risk (CVaR) to protect portfolios against tail risks and market downturns.
  • Portfolio Rebalancing and Allocation: Analyze current market prices and historical data to rebalance existing holdings and generate discrete share counts for execution based on a specific budget.
  • Quantitative Financial Research: Conduct 'what-if' analysis by adding custom constraints (e.g., sector exposure limits) and visualizing the efficient frontier to understand the risk-return tradeoff of different asset classes.
nameportfolio-optimization
descriptionPortfolio optimization using PyPortfolioOpt for mean-variance optimization, efficient frontier analysis, risk modeling, and discrete allocation. Use when building investment portfolios, calculating optimal weights, analyzing risk-return tradeoffs, maximizing Sharpe ratio, minimizing volatility, or converting weights to share allocations. Supports HRP, CVaR, semivariance, and custom objectives.

Portfolio Optimization

Portfolio optimization using PyPortfolioOpt library.

Installation

pip install pypfopt pandas numpy matplotlib

Quick Start

from pypfopt import EfficientFrontier, risk_models, expected_returns
from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

# Calculate expected returns and covariance
mu = expected_returns.mean_historical_return(prices_df)
S = risk_models.sample_cov(prices_df)

# Optimize for max Sharpe ratio
ef = EfficientFrontier(mu, S)
weights = ef.max_sharpe(risk_free_rate=0.02)
cleaned_weights = ef.clean_weights()
ret, vol, sharpe = ef.portfolio_performance(verbose=True)

# Convert to share allocation
latest_prices = get_latest_prices(prices_df)
da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=100000)
allocation, leftover = da.greedy_portfolio()

Core Workflows

1. Expected Returns

from pypfopt.expected_returns import mean_historical_return, ema_historical_return, capm_return

# Mean historical (default)
mu = mean_historical_return(prices_df, frequency=252, compounding=True)

# Exponentially weighted (more weight to recent)
mu = ema_historical_return(prices_df, span=500)

# CAPM-based
mu = capm_return(prices_df, market_prices=benchmark_df, risk_free_rate=0.02)

2. Risk Models

from pypfopt.risk_models import sample_cov, exp_cov, semicovariance, CovarianceShrinkage

# Sample covariance
S = sample_cov(prices_df)

# Exponentially weighted
S = exp_cov(prices_df, span=180)

# Semicovariance (downside risk only)
S = semicovariance(prices_df, benchmark=0)

# Shrinkage methods (more robust)
cs = CovarianceShrinkage(prices_df)
S = cs.ledoit_wolf()  # or cs.oracle_approximating()

3. Optimization Objectives

ef = EfficientFrontier(mu, S, weight_bounds=(0, 1))

# Max Sharpe ratio
ef.max_sharpe(risk_free_rate=0.02)

# Min volatility
ef.min_volatility()

# Max quadratic utility: max w'μ - (δ/2)w'Σw
ef.max_quadratic_utility(risk_aversion=1.0)

# Target return
ef.efficient_return(target_return=0.15)

# Target risk
ef.efficient_risk(target_volatility=0.20)

# Get results
weights = ef.clean_weights()
ret, vol, sharpe = ef.portfolio_performance()

4. Constraints

ef = EfficientFrontier(mu, S)

# Sector constraints
ef.add_constraint(lambda w: w[0] >= 0.2)  # Min 20% in asset 0
ef.add_constraint(lambda w: w[2] == 0.15)  # Exactly 15% in asset 2
ef.add_constraint(lambda w: w[3] + w[4] <= 0.10)  # Max 10% combined

# L2 regularization (diversification)
from pypfopt import objective_functions
ef.add_objective(objective_functions.L2_reg, gamma=0.1)

5. Alternative Methods

# Hierarchical Risk Parity
from pypfopt import HRPOpt
hrp = HRPOpt(returns_df)
weights = hrp.optimize()
ret, vol, sharpe = hrp.portfolio_performance()

# Efficient CVaR (tail risk)
from pypfopt.efficient_frontier import EfficientCVaR
ef_cvar = EfficientCVaR(mu, returns_df, beta=0.95)
ef_cvar.min_cvar()

# Efficient Semivariance
from pypfopt.efficient_frontier import EfficientSemivariance
ef_semi = EfficientSemivariance(mu, returns_df, benchmark=0)
ef_semi.min_semivariance()

6. Discrete Allocation

from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices

latest_prices = get_latest_prices(prices_df)
da = DiscreteAllocation(weights, latest_prices, total_portfolio_value=100000)

# Greedy algorithm (faster)
allocation, leftover = da.greedy_portfolio()

# Integer programming (more precise)
allocation, leftover = da.lp_portfolio()

Plotting

from pypfopt import plotting
import matplotlib.pyplot as plt

# Efficient frontier
fig, ax = plt.subplots()
plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True)

# With random portfolios overlay
n_samples = 10000
w = np.random.dirichlet(np.ones(ef.n_assets), n_samples)
rets = w.dot(ef.expected_returns)
stds = np.sqrt(np.diag(w @ ef.cov_matrix @ w.T))
ax.scatter(stds, rets, marker=".", c=rets/stds, cmap="viridis_r")

# Covariance matrix
plotting.plot_covariance(S)

# Portfolio weights
plotting.plot_weights(weights)

# HRP dendrogram
plotting.plot_dendrogram(hrp)

Reference Files