# PyPortfolioOpt

Prices in, weights out — efficient frontier, Black-Litterman and HRP.

*https://stockmarketstack.com/tools/pyportfolioopt · Market Analysis & Portfolio Optimization Libraries*

## Facts

### At a glance

| Field | Value |
| --- | --- |
| Vendor | PyPortfolio |
| Category | Market Analysis & Portfolio Optimization Libraries |
| Job | optimization |
| Website | https://github.com/PyPortfolio/PyPortfolioOpt |
| Pricing model | open-source |
| Free tier | true |
| Open source | true |
| Licence | MIT |
| Self-hosted | true |
| Tested hands-on | false |
| Last updated | 2026-09-19 |

### Coverage

| Field | Value |
| --- | --- |
| Asset classes | stocks, etf, bonds, commodities |
| Markets | global |
| Works outside the US | true |
| Data latency | none |
| Platforms | library |
| AI features | none |

### Interfaces

| Field | Value |
| --- | --- |
| API | false |
| Webhooks | false |
| Scripting | Python |
| Python | true |
| Spreadsheet add-in | false |
| MCP server | false |
| Export | csv, json |

### Capabilities

Yes: none

No: charting, screening, scanning, backtesting, automation, live_trading, paper_trading, portfolio_tracking, broker_import, tax_reporting, alerts, news, options_analysis

*Verified: pricing 2026-09-19; capabilities 2026-09-19; coverage 2026-09-19.*

## What it is

PyPortfolioOpt is the library most people meet first when they go looking for Markowitz in
Python. The shape is deliberately scikit-learn-ish: `expected_returns` and `risk_models` turn a
price DataFrame into a mean vector and a covariance matrix, `EfficientFrontier` takes the pair and
solves for weights under `max_sharpe()`, `min_volatility()`, `efficient_risk()` or
`efficient_return()`, and `DiscreteAllocation` turns the resulting fractions into how many shares
to buy with the cash you actually have.

Around that core: shrinkage covariance (Ledoit-Wolf, oracle approximating, exponentially
weighted), L2 regularisation and sector constraints through `objective_functions`,
`BlackLittermanModel` for folding absolute or relative views into the prior, `HRPOpt` for
hierarchical risk parity, `CLA` for Markowitz's critical line algorithm, and efficient
semivariance, CVaR and CDaR frontiers in their own modules.

The project changed hands in 2026, and that is the fact worth knowing before you depend on it.
The repository now lives under the PyPortfolio organisation — the old `robertmartin8` URL
redirects — and carries a GC.OS sponsorship badge, the same stewardship arrangement as sktime.
Version 1.6.0 landed on 26 February 2026 after 1.5.6 in December 2024, and its notes read like a
rescue rather than a feature release: Python 3.14 and pandas 3 support, Python 3.8 and 3.9 retired,
soft dependencies moved out of the core install, CI rebuilt. The published package metadata still
names Robert Andrew Martin as maintainer; the release was cut by Franz Király.

## Pricing

Free and MIT, with nothing for sale — no pro build, no hosted tier, no data bundle. What is not
free of charge in the licence sense is the `all-extras` depset, which adds matplotlib, plotly,
ecos and cvxopt. The last two are GPLv3. That is irrelevant if you are running research on your
own machine and material if you redistribute a binary.

## Data & coverage

None, and that is by design. Grep the installed package for a network call and you find nothing:
no bundled dataset, no fetcher, no vendor client. Asset classes and markets are whatever your
price series covers, so the library is as global as your data source is.

## Integrations

cvxpy does the solving, so anything cvxpy supports is available by passing `solver=`. Hard
dependencies are numpy, pandas, scipy, scikit-learn and — new in 1.6.0 — `scikit-base`, the
base-class package from the sktime ecosystem, which is the clearest signal of where the project now
sits. Weights come back as a dict or an `OrderedDict`; `save_weights_to_file` writes csv, json or
txt, and everything else is a pandas object you export yourself.

## Limitations

- No data and no backtest. If you arrived from a backtesting framework expecting to test a
  rebalancing rule, this is the wrong shelf — it computes one weight vector per call, and looping
  it over time is your code.
- Mean-variance is only as good as the expected returns you feed it, and the README says so.
  Historical means are a poor forecast, which is the reason Black-Litterman and shrinkage are in
  the package at all.
- `DiscreteAllocation.lp_portfolio()` needs a mixed-integer solver. It currently defaults to
  ECOS_BB when `ecos` is installed and warns that in 1.7.0 the default becomes cvxpy's own choice —
  code written against today's behaviour will need an explicit `solver=` argument.
- PyPI still classifies it Development Status 4 - Beta, eight years in.
- 82 open issues and a release cadence measured in years, not weeks. The new maintainers are real
  but the backlog is real too.

## Alternatives

[Riskfolio-Lib](https://stockmarketstack.com/tools/riskfolio-lib) covers far more risk measures and is the one to reach for if
CVaR, drawdown-at-risk or Kelly objectives are the point. [skfolio](https://stockmarketstack.com/tools/skfolio) is the
scikit-learn-native take, with cross-validation and hyper-parameter search around the optimiser
rather than bolted on. [Portfolio Optimizer](https://stockmarketstack.com/tools/portfolio-optimizer) does the same mathematics
over HTTP for people who are not writing Python at all, and
[Portfolio Visualizer](https://stockmarketstack.com/tools/portfolio-visualizer) is the no-code version of the question.

## FAQ

### Is PyPortfolioOpt still maintained?

Yes, by different people than wrote it. The repository moved from robertmartin8 to the PyPortfolio organisation, where it is a GC.OS sponsored project, and version 1.6.0 shipped on 26 February 2026 after fourteen months without a release. The last commit to main was 7 July 2026, the repository is not archived, and 82 issues are open excluding pull requests.

### Does PyPortfolioOpt download prices or run a backtest?

Neither. Nothing in the installed package makes a network call — no yfinance, no requests, no urllib — and there is no simulation loop, no rebalancing schedule and no broker. You hand it a price or returns DataFrame you sourced yourself, and it hands you a weight vector back.

### Which solver do I need, and do I have to pay for one?

No. cvxpy is a hard dependency and the solvers it installs handle everything on the continuous side. The one exception is the integer allocation step, DiscreteAllocation.lp_portfolio, which needs a mixed-integer solver and defaults to ECOS_BB when the optional ecos package is present.

### Is the licence really MIT?

The LICENSE file is MIT and so is every line you import. Watch the optional extras rather than the core — the all-extras depset installs ecos and cvxopt, both of which are GPLv3, so a team that ships binaries should install them deliberately rather than by reflex.

## Also worth comparing

- [Riskfolio-Lib](https://stockmarketstack.com/tools/riskfolio-lib.md) — Twenty-six convex risk measures, four objectives, one cvxpy-backed optimiser.
- [skfolio](https://stockmarketstack.com/tools/skfolio.md) — Portfolio optimisation as scikit-learn estimators — fit, predict, cross-validate.
- [Portfolio Optimizer](https://stockmarketstack.com/tools/portfolio-optimizer.md) — 248 portfolio maths endpoints over HTTP — no install, no solver, no account.
- [arch](https://stockmarketstack.com/tools/arch.md) — GARCH and the rest of the volatility-model family, plus the tests you need around them.
- [empyrical-reloaded](https://stockmarketstack.com/tools/empyrical-reloaded.md) — The maintained fork of Quantopian's empyrical — risk statistics, no plots.
- [ffn](https://stockmarketstack.com/tools/ffn.md) — Performance stats, drawdowns and portfolio weights from a DataFrame of prices.
