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
yfinanceandAkSharefetch historical series (referenced inREADME.mdat line 119). - Optimization Layer:
PyPortfolioOptsolves convex problems including mean-variance and Black-Litterman models, whileRiskfolio-Libprovides multi-objective optimization with CVaR and Omega risk measures (documented at lines 179 and 180). - Backtesting Consumption: Generated weights feed into engines like
backtraderorQuantConnect(listed at line 87). - Performance Analytics: Metrics computation via
quantstatsorpyfolioevaluates 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
EfficientFrontierclass. - Riskfolio-Lib (line 180) delivers sophisticated risk models including CVaR, Omega, and HRP through the
Portfolioobject 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 andset_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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →