Portfolio Optimization with PyPortfolioOpt and Riskfolio-Lib: A Practical Guide

Portfolio optimization with PyPortfolioOpt and Riskfolio-Lib enables quantitative researchers to construct risk-adjusted portfolios using classical mean-variance techniques and modern hierarchical risk models, seamlessly integrated into the systematic trading pipeline curated in the paperswithbacktest/awesome-systematic-trading repository.

The paperswithbacktest/awesome-systematic-trading repository serves as a comprehensive catalog of 97+ libraries for quantitative finance, positioning these two Python packages at the core of the asset allocation workflow. Both tools transform raw return matrices into optimized weight vectors, bridging the gap between data ingestion and backtesting execution.

Architectural Role in the Quantitative Pipeline

Within the ecosystem outlined in the repository's README, PyPortfolioOpt and Riskfolio-Lib occupy the critical optimization layer between data preprocessing and strategy execution. According to the source code analysis, the pipeline flows through distinct stages:

  • Data Acquisition: Libraries like yfinance and AkShare fetch historical series (referenced in README.md at line 119).
  • Optimization Layer: PyPortfolioOpt solves convex problems including mean-variance and Black-Litterman models, while Riskfolio-Lib provides multi-objective optimization with CVaR and Omega risk measures (documented at lines 179 and 180).
  • Backtesting Consumption: Generated weights feed into engines like backtrader or QuantConnect (listed at line 87).
  • Performance Analytics: Metrics computation via quantstats or pyfolio evaluates the optimized allocations (found at line 67).

This architecture ensures that once you compute returns from raw price data, you can pass clean matrices to either optimizer and receive portfolio weights ready for live deployment or historical simulation.

PyPortfolioOpt: Convex Optimization Methods

Listed at line 179 of README.md, PyPortfolioOpt specializes in classical portfolio theory implementations. The library provides the EfficientFrontier class along with modules for risk_models and expected_returns, enabling users to solve minimum-variance, maximum-Sharpe, and market-implied Black-Litterman allocations.

Minimum-Variance Portfolio Implementation

The following implementation demonstrates the EfficientFrontier object solving for minimum volatility without requiring expected return estimates:

import pandas as pd
import yfinance as yf
from pypfopt import EfficientFrontier, risk_models, expected_returns

# Download price data for universe construction

tickers = ["AAPL", "MSFT", "GLD", "TLT"]
prices = yf.download(tickers, start="2020-01-01")["Adj Close"]

# Compute daily returns matrix

returns = prices.pct_change().dropna()

# Estimate covariance using sample covariance

cov_matrix = risk_models.sample_cov(returns)

# Initialize frontier with covariance only (no expected returns required)

ef = EfficientFrontier(None, cov_matrix)

# Solve minimum variance optimization

weights = ef.min_volatility()
cleaned_weights = ef.clean_weights()

print("Min-variance weights:")
print(cleaned_weights)

# Extract performance metrics

expected_annual_ret = ef.expected_return()
annual_vol = ef.portfolio_performance()[1]
print(f"Expected annual return: {expected_annual_ret:.2%}")
print(f"Annual volatility:      {annual_vol:.2%}")

The clean_weights() method rounds near-zero positions to exactly zero, producing a tradable allocation vector suitable for brokerage API submission.

Riskfolio-Lib: Advanced Risk-Aware Allocation

Documented immediately below PyPortfolioOpt at line 180, Riskfolio-Lib extends beyond traditional mean-variance frameworks. The library supports hierarchical risk parity (HRP), conditional value-at-risk (CVaR) minimization, and Omega ratio optimization, while handling complex constraint sets through the Portfolio class interface.

Hierarchical Risk Parity Optimization

This example utilizes rp.Portfolio with historical methods for mean and covariance estimation, applying the HRP algorithm that constructs portfolios based on the dendrogram structure of asset correlations:

import pandas as pd
import yfinance as yf
import riskfolio as rp

# Fetch historical prices

tickers = ["AAPL", "MSFT", "GLD", "TLT"]
prices = yf.download(tickers, start="2020-01-01")["Adj Close"]

# Calculate log-returns for optimization input

ret = prices.pct_change().dropna()

# Instantiate portfolio object

port = rp.Portfolio(returns=ret)

# Configure estimation methods and constraints

port.assets_stats(method_mu='hist', method_cov='hist')
port.set_constraints(w_min=0, w_max=1)  # Enforce long-only positions

# Execute HRP optimization

weights = port.optimise(method='HRP')
print("HRP weights:")
print(weights.T)

The assets_stats() method computes the necessary distributional parameters, while optimise(method='HRP') invokes the machine learning-based allocation that typically produces more stable out-of-sample weights than traditional inverse-volatility approaches.

Repository Integration Points

To locate these tools within the paperswithbacktest/awesome-systematic-trading codebase:

Component Location Direct Link
PyPortfolioOpt README.md line 179 Optimization table
Riskfolio-Lib README.md line 180 Optimization table
Data Sources README.md line 119 Price data acquisition
Backtesting Engines README.md line 87 Weight consumption
Analytics README.md line 67 Post-optimization metrics

These specific line references allow practitioners to verify library versions, documentation links, and complementary tools within the curated list.

Summary

  • PyPortfolioOpt (line 179) provides efficient convex solvers for mean-variance, minimum-volatility, and Black-Litterman portfolios using the EfficientFrontier class.
  • Riskfolio-Lib (line 180) delivers sophisticated risk models including CVaR, Omega, and HRP through the Portfolio object with extensive constraint handling.
  • Both libraries accept preprocessed return matrices from data sources listed at line 119 and generate weights consumable by backtesters documented at line 87.
  • The clean_weights() method in PyPortfolioOpt and set_constraints() in Riskfolio-Lib ensure outputs meet real-world trading restrictions.

Frequently Asked Questions

What differentiates PyPortfolioOpt from Riskfolio-Lib?

PyPortfolioOpt focuses on classical convex optimization problems such as mean-variance efficiency and Black-Litterman models, utilizing scipy and cvxpy solvers. Riskfolio-Lib extends into modern risk measures like CVaR and Omega while providing hierarchical clustering methods (HRP) and multi-objective optimization capabilities that exceed traditional quadratic programming frameworks.

How do I connect these optimizers to backtesting frameworks?

After generating weights via ef.clean_weights() or port.optimise(), export the resulting allocation vector to a pandas DataFrame with datetime indexing. Pass this series to backtesting engines like backtrader or zipline (referenced at README.md line 87) as the target position dictionary for each rebalancing date.

Which risk models are exclusive to Riskfolio-Lib?

While PyPortfolioOpt handles variance, semi-variance, and CVaR through quadratic programming, Riskfolio-Lib uniquely implements the Omega ratio, ** Sortino ratio**, Fama-French factor constraints, and hierarchical risk parity without requiring convexity assumptions, making it suitable for non-normal return distributions.

Where are these libraries documented in the Awesome Systematic Trading repository?

Both packages appear in the Optimization section of README.md, with PyPortfolioOpt specifically at line 179 and Riskfolio-Lib at line 180. The repository lists installation commands, GitHub source links, and brief descriptions of each library's mathematical foundations adjacent to these line numbers.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →