Roadmap and Changelog


PyPortfolioOpt is now a “mature” package – it is stable and I don’t intend to implement major new functionality (though I will endeavour to fix bugs).


  • Major redesign of the backend, thanks to Philipp Schiele - Becuase we use cp.Parameter, we can efficiently re-run optimisation problems with different constants (e.g risk targets) - This leads to a significant improvement in plotting performance as we no longer have to repeatedly re-instantiate EfficientFrontier.
  • Several misc bug fixes (thanks to Eric Armbruster and Ayoub Ennassiri)


Mucked up the versioning on the 1.5.0 launch. Sorry!


Minor bug fixes


  • Reworked packaging: cvxpy is no longer a requirement as we default to ECOS_BB for discrete allocation.
  • Bumped minimum python version to 3.8. I would love to keep as many versions compatible (and I think most of the functionality should still work with 3.6, 3.7 but the dependencies have gotten too tricky to manage).
  • Changed to numpy pseudoinverse to allow for “cash” assets
  • Ticker labels for efficient frontier plot


  • Fixed cvxpy deprecating deepcopy. Thanks to Philipp for the fix!
  • Several other tiny checks and bug fixes. Cheers to everyone for the PRs!


  • Finally implemented CVaR optimization! This has been one of the most requested features. Many thanks to Nicolas Knudde for the initial draft.
  • Re-architected plotting so users can pass an ax, allowing for complex plots (see cookbook).
  • Helper method to compute the max-return portfolio (thanks to Philipp Schiele) for the suggestion).
  • Several bug fixes and test improvements (thanks to Carl Peasnell).


  • 100% test coverage
  • Reorganised docs; added FAQ page
  • Reorganised module structure to make it more scalable
  • Python 3.9 support, dockerfile versioning, misc packaging improvements (e.g cvxopt optional)


  • Implemented CDaR optimization – full credit to Nicolas Knudde.
  • Misc bug fixes


  • Significantly improved plotting functionality: can now plot constrained efficient frontier!
  • Efficient semivariance portfolios (thanks to Philipp Schiele)
  • Improved functionality for portfolios with short positions (thanks to Rich Caputo).
  • Significant improvement in test coverage (thanks to Carl Peasnell).
  • Several bug fixes and usability improvements.
  • Migrated from TravisCI to Github Actions.


  • Minor cleanup (forgotten commits from v1.3.0).


  • Added Idzorek’s method for calculating the omega matrix given percentage confidences.
  • Fixed max sharpe to allow for custom constraints
  • Grouped sector constraints
  • Improved error tracebacks
  • Adding new cookbook for examples (in progress).
  • Packaging: added bettter instructions for windows, added docker support.


Fixed critical ordering bug in sector constraints


Matplotlib now required dependency; support for pandas 1.0.


  • Added support for changing solvers and verbose output
  • Changed dict to OrderedDict to support python 3.5
  • Improved packaging/dependencies: simplified requirements.txt, improved processes before pushing.


  • Fixed bug in Ledoit-Wolf shrinkage calculation.
  • Fixed bug in plotting docs that caused them not to render.


  • Fixed compounding in expected_returns (thanks to Aditya Bhutra).
  • Improvements in advanced cvxpy API (thanks to Pat Newell).
  • Deprecating James-Stein
  • Exposed linkage_method in HRP.
  • Added support for cvxpy 1.1.
  • Added an error check for efficient_risk.
  • Small improvements to docs.


  • Fixed order-dependence bug in Black-Litterman market_implied_prior_returns
  • Fixed inaccuracy in BL cookbook.
  • Fixed bug in exponential covariance.


  • Fixed bug which required conservative risk targets for long/short portfolios.


  • Multiple additions and improvements to risk_models:
    • Introduced a new API, in which the function risk_models.risk_matrix(method="...") allows all the different risk models to be called. This should make testing easier.
    • All methods now accept returns data instead of prices, if you set the flag returns_data=True.
  • Automatically fix non-positive semidefinite covariance matrices!
  • Additions and improvements to expected_returns:
    • Introduced a new API, in which the function expected_returns.return_model(method="...") allows all the different return models to be called. This should make testing easier.
    • Added option to ‘properly’ compound returns.
    • Added the CAPM return model.
  • from pypfopt import plotting: moved all plotting functionality into a new class and added new plots. All other plotting functions (scattered in different classes) have been retained, but are now deprecated.


  • Migrated backend from scipy to cvxpy and made significant breaking changes to the API
    • PyPortfolioOpt is now significantly more robust and numerically stable.
    • These changes will not affect basic users, who can still access features like max_sharpe().
    • However, additional objectives and constraints (including L2 regularisation) are now explicitly added before optimising some ‘primary’ objective.
  • Added basic plotting capabilities for the efficient frontier, hierarchical clusters, and HRP dendrograms.
  • Added a basic transaction cost objective.
  • Made breaking changes to some modules and classes so that PyPortfolioOpt is easier to extend in future:
    • Replaced BaseScipyOptimizer with BaseConvexOptimizer
    • hierarchical_risk_parity was replaced by hierarchical_portfolios to leave the door open for other hierarchical methods.
    • Sadly, removed CVaR optimization for the time being until I can properly fix it.


Fixed minor issues in CLA: weight bound bug, efficient_frontier needed weights to be called, set_weights not needed.


Fixed small but important bug where passing expected_returns=None fails. According to the docs, users should be able to only pass covariance if they want to only optimize min volatility.


  • Black-Litterman model and docs.
  • Custom bounds per asset
  • Improved BaseOptimizer, adding a method that writes weights to text and fixing a bug in set_weights.
  • Unconstrained quadratic utility optimization (analytic)
  • Revamped docs, with information on types of attributes and more examples.


Fixed an error with dot products by amending the pandas requirements.


Made PuLP, sklearn, noisyopt optional dependencies to improve installation experience.


  • Fixed an optimization bug in EfficientFrontier.efficient_risk. An error is now thrown if optimization fails.
  • Added a hidden API to change the scipy optimizer method.


  • Improved the Black-Litterman linear algebra to avoid inverting the uncertainty matrix. It is now possible to have 100% confidence in views.
  • Clarified regarding the role of tau.
  • Added a pipfile for pipenv users.
  • Removed Value-at-risk from docs to discourage usage until it is properly fixed.


Began migration to cvxpy by changing the discrete allocation backend from PuLP to cvxpy.


  • Major improvements to discrete_allocation. Added functionality to allocate shorts; modified the linear programming method suggested by Dingyuan Wang; added postprocessing section to User Guide.
  • Further refactoring and docs for HRPOpt.
  • Major documentation update, e.g to support custom optimizers


  • Added CLA back in after getting permission from Dr Marcos López de Prado
  • Added more tests for different risk models.


  • Minor fix for clean_weights
  • Removed official support for python 3.4.
  • Minor improvement to semicovariance, thanks to Felipe Schneider.


  • Added prices_from_returns utility function and provided better docs for returns_from_prices.
  • Added cov_to_corr method to produce correlation matrices from covariance matrices.
  • Fixed readme examples.


  • Merged an amazing PR from Dingyuan Wang that rearchitects the project to make it more self-consistent and extensible.
  • New algorithm: ML de Prado’s CLA
  • New algorithms for converting continuous allocation to discrete (using linear programming).
  • Merged a PR implementing Single Factor and Constant Correlation shrinkage.


Merged PR from TommyBark fixing a bug in the arguments of a call to portfolio_performance.


Migrated the project internally to use the poetry dependency manager. Will still keep and requirements.txt, but poetry is now the recommended way to interact with PyPortfolioOpt.


Refactored shrinkage models, including single factor and constant correlation.


  • Hierarchical Risk Parity optimization
  • Semicovariance matrix
  • Exponential covariance matrix
  • CVaR optimization
  • Better support for custom objective functions
  • Multiple bug fixes (including minimum volatility vs minimum variance)
  • Refactored so all optimizers inherit from a BaseOptimizer.


  • Included python 3.7 in travis build
  • Merged PR from schneiderfelipe to fix an error message.


Initial release:

  • Efficient frontier (max sharpe, min variance, target risk/return)
  • L2 regularisation
  • Discrete allocation
  • Mean historical returns, exponential mean returns
  • Sample covariance, sklearn wrappers.
  • Tests
  • Docs


Minor bug fixes and documentation