# Best Libraries for Portfolio Optimization: PyPortfolioOpt vs Riskfolio-Lib

> Compare PyPortfolioOpt and Riskfolio-Lib for portfolio optimization. Discover which library offers the best tools for your asset allocation needs.

- Repository: [Papers With Backtest/awesome-systematic-trading](https://github.com/paperswithbacktest/awesome-systematic-trading)
- Tags: comparison
- Published: 2026-07-31

---

**PyPortfolioOpt provides a straightforward API for classical mean-variance optimization and Hierarchical Risk Parity, while Riskfolio-Lib offers advanced risk budgeting, CVaR optimization, and multi-period strategies for sophisticated asset allocation.**

The `paperswithbacktest/awesome-systematic-trading` repository maintains a curated list of quantitative finance tools for systematic trading strategies. When evaluating the best libraries for portfolio optimization, two Python packages consistently stand out: PyPortfolioOpt and Riskfolio-Lib. Both libraries implement modern portfolio theory but differ significantly in their API design, risk model coverage, and constraint handling capabilities.

## PyPortfolioOpt: Classical Methods and Clean API

PyPortfolioOpt, authored by Robert Martin, focuses on providing a Pythonic interface to classical portfolio optimization techniques. According to the repository's [`README.md`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/README.md) under the Optimization section, this library excels in efficient frontier calculations and modern heuristic approaches.

### API Design and Core Functionality

The library adopts a builder-pattern architecture centered around specialized classes. The `EfficientFrontier` object serves as the primary interface, exposing intuitive methods such as `max_sharpe()`, `min_volatility()`, and `efficient_risk()`. This design pattern makes it straightforward to instantiate an optimizer with expected returns and covariance matrices, then chain methods to adjust constraints and objectives.

For alternative strategies, PyPortfolioOpt provides dedicated classes like `HRPPortfolio` for Hierarchical Risk Parity, which requires no expected return estimates and operates purely on price-based hierarchical clustering.

### Supported Optimization Models

PyPortfolioOpt covers the foundational models of modern portfolio theory:

- **Mean-Variance Optimization**: Classic Markowitz framework with tangency portfolios
- **Black-Litterman**: Bayesian-inspired asset allocation incorporating investor views
- **Hierarchical Risk Parity**: Tree-based allocation using clustering algorithms
- **Custom Objectives**: Support for target returns, risk targets, and quadratic utility functions

## Riskfolio-Lib: Advanced Risk Budgeting and Constraints

Riskfolio-Lib, developed by Dany Cajas, extends beyond classical optimization to embrace contemporary risk measures and complex constraint languages. The library targets practitioners requiring sophisticated risk budgeting and tail-risk management.

### High-Level Portfolio Class

Unlike PyPortfolioOpt's multiple specialized classes, Riskfolio-Lib centralizes functionality in a single `Portfolio` class. Users instantiate this class with historical returns, then configure optimization parameters through attributes like `risk_measures` and `objective`. The `optimise()` method executes the actual computation based on these configurations.

This approach decouples estimation from optimization. Users first call `assets_stats()` to estimate means and covariances using methods like `'hist'` for historical or `'ew'` for exponential weighting, then configure the optimization separately.

### Advanced Risk Measures and Constraints

Riskfolio-Lib distinguishes itself through extensive risk measure support beyond variance:

- **Conditional Value-at-Risk (CVaR)**: Also known as Expected Shortfall
- **Drawdown Measures**: Worst-case drawdown and average drawdown optimization
- **Tail-Risk Adjusted**: Higher-moment risk measures for non-normal distributions
- **Multi-Period Planning**: Dynamic programming approaches for multi-stage allocation

The constraint system in Riskfolio-Lib offers granular control through a dictionary-based specification supporting cardinality constraints, group constraints, and risk-budgeting limits.

## PyPortfolioOpt vs Riskfolio-Lib: Key Differences

| Feature | **PyPortfolioOpt** | **Riskfolio-Lib** |
|---|---|---|
| **Model Coverage** | Classical mean-variance, Black-Litterman, HRP, minimum-variance, maximum-Sharpe, target-return, and custom risk-parity models. | Classical mean-variance plus extensive risk-budgeting and factor-model approaches (CVaR, Expected Shortfall, Drawdown, Tail-Risk), multi-period planning, and Bayesian estimators. |
| **API Style** | Simple "builder-pattern" objects (`EfficientFrontier`, `HRPPortfolio`) with methods like `max_sharpe()`, `efficient_risk()`. | High-level `Portfolio` class where users specify `RiskMeasure.CVaR` and call `optimise()` with constraints. |
| **Constraint Handling** | Linear constraints (`weight_bounds`, `sector_constraints`, `cash`). | Rich constraint language including budget, risk-budget, group, cardinality, and custom linear/quadratic constraints via dictionary. |
| **Visualization** | Built-in Matplotlib helpers (`plot_efficient_frontier`, `plot_weights`). | Separate `plot` module with frontier, weight, and risk-budget visualizations. |
| **Dependencies** | NumPy, Pandas, SciPy, optional `cvxpy`. | Extended scientific stack (`scikit-learn`, `statsmodels`) with `cvxpy` as default solver. |

**PyPortfolioOpt** suits practitioners needing quick efficient-frontier solutions with minimal configuration. **Riskfolio-Lib** serves researchers and advanced practitioners requiring custom risk measures or complex institutional constraints.

## Practical Implementation Examples

Below are minimal implementations demonstrating maximum Sharpe ratio optimization in both libraries. These examples assume price data loaded as Pandas DataFrames with assets as columns.

### PyPortfolioOpt: Maximum Sharpe Ratio

```python
import pandas as pd
from pypfopt import EfficientFrontier, risk_models, expected_returns

# Load price data - DataFrame with assets as columns

prices = pd.read_csv('prices.csv', parse_dates=['Date'], index_col='Date')

# Estimate expected returns and sample covariance

mu = expected_returns.mean_historical_return(prices)
Sigma = risk_models.sample_cov(prices)

# Instantiate optimizer and maximize Sharpe ratio

ef = EfficientFrontier(mu, Sigma)
raw_weights = ef.max_sharpe()
cleaned_weights = ef.clean_weights()

print("Optimal weights:", cleaned_weights)
ef.portfolio_performance(verbose=True)

```

The `EfficientFrontier` class handles the optimization internally using `scipy.optimize` or `cvxpy` depending on the constraint complexity. The `clean_weights()` method rounds small values to zero for practical implementation.

### Riskfolio-Lib: Maximum Sharpe Ratio

```python
import pandas as pd
import riskfolio as rp

# Load price data

prices = pd.read_csv('prices.csv', parse_dates=['Date'], index_col='Date')
returns = prices.pct_change().dropna()

# Create Portfolio object and estimate statistics

port = rp.Portfolio(returns=returns)
port.assets_stats(method_mu='hist', method_cov='hist')

# Configure optimization parameters

port.risk_measures = 'Sharpe'
port.objective = 'max'
port.constraints = {'weight_bounds': (0, 1)}

# Execute optimization

weights = port.optimise()
print("Optimal weights:", weights)

```

Here, the `Portfolio` class encapsulates all estimation and optimization logic. The `optimise()` method selects the appropriate solver based on the specified risk measure and constraints.

## Integration with Systematic Trading Workflows

Both libraries integrate seamlessly with the broader ecosystem documented in `paperswithbacktest/awesome-systematic-trading`. The repository's `static/strategies/` directory contains QuantConnect implementations demonstrating how portfolio optimization outputs feed into systematic execution engines.

For international users, the [`README_zh.md`](https://github.com/paperswithbacktest/awesome-systematic-trading/blob/main/README_zh.md) file mirrors the English documentation, ensuring Chinese-speaking practitioners can evaluate these libraries effectively. When deploying optimizations in production, consider the dependency footprint: PyPortfolioOpt's lighter requirements suit constrained environments, while Riskfolio-Lib's extended stack supports more sophisticated statistical methods.

## Summary

- **PyPortfolioOpt** offers a clean, object-oriented API for classical mean-variance optimization, Black-Litterman, and Hierarchical Risk Parity with minimal dependencies.
- **Riskfolio-Lib** provides comprehensive risk budgeting capabilities, supporting CVaR, Expected Shortfall, and drawdown-based optimization through a unified `Portfolio` class.
- **Constraint flexibility** differs significantly: PyPortfolioOpt handles standard linear constraints, while Riskfolio-Lib accommodates complex cardinality and group constraints.
- **Implementation complexity** favors PyPortfolioOpt for rapid prototyping, while Riskfolio-Lib suits research environments requiring custom risk measures.

## Frequently Asked Questions

### Which library is better for beginners?

**PyPortfolioOpt** provides the gentler learning curve due to its intuitive builder-pattern API and extensive documentation. The separation of `EfficientFrontier`, `HRPPortfolio`, and other classes makes it clear which optimization model applies to specific use cases. Riskfolio-Lib's unified `Portfolio` class, while powerful, requires understanding the relationship between estimation methods and risk measures before effective use.

### Can I use both libraries in the same project?

Yes, practitioners often use **PyPortfolioOpt** for rapid efficient-frontier analysis and **Riskfolio-Lib** for specialized risk-budgeting requirements. Both libraries output standard weight dictionaries compatible with Pandas DataFrames, allowing seamless integration where PyPortfolioOpt handles the core mean-variance allocation and Riskfolio-Lib manages tail-risk overlays.

### Does Riskfolio-Lib support Black-Litterman models?

While Riskfolio-Lib focuses primarily on risk-based and factor-model approaches, it includes Bayesian estimators that can incorporate views similar to the Black-Litterman framework. However, **PyPortfolioOpt** provides a more explicit `BlackLittermanModel` class with dedicated methods for view specification and uncertainty quantification, making it the preferred choice for Black-Litterman implementation.

### How do I handle custom constraints in PyPortfolioOpt?

PyPortfolioOpt supports custom constraints through the `add_constraint()` method or by passing constraint matrices directly to the `EfficientFrontier` constructor. For linear inequalities, you can specify sector constraints and bounds via dictionaries. However, for complex cardinality constraints or risk-budgeting limits native to **Riskfolio-Lib**, you may need to implement custom `cvxpy` constraints or switch libraries depending on the specific requirement.