skfolio


Nameskfolio JSON
Version 0.11.0 PyPI version JSON
download
home_pageNone
SummaryPortfolio optimization built on top of scikit-learn
upload_time2025-07-26 20:36:29
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseBSD 3-Clause License Copyright (c) 2007-2023 The skfolio developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
keywords portfolio optimization optimisation finance asset allocation quantitative quant investment strategy machine-learning scikit-learn data-mining data-science
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            .. -*- mode: rst -*-

|Licence| |Codecov| |Black| |PythonVersion| |PyPi| |CI/CD| |Downloads| |Ruff| |Contribution| |Website| |JupyterLite| |Discord| |DOI|

.. |Licence| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
   :target: https://github.com/skfolio/skfolio/blob/main/LICENSE

.. |Codecov| image:: https://codecov.io/gh/skfolio/skfolio/graph/badge.svg?token=KJ0SE4LHPV
   :target: https://codecov.io/gh/skfolio/skfolio

.. |PythonVersion| image:: https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue.svg
   :target: https://pypi.org/project/skfolio/

.. |PyPi| image:: https://img.shields.io/pypi/v/skfolio
   :target: https://pypi.org/project/skfolio

.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
   :target: https://github.com/psf/black

.. |CI/CD| image:: https://img.shields.io/github/actions/workflow/status/skfolio/skfolio/release.yml.svg?logo=github
   :target: https://github.com/skfolio/skfolio/raw/main/LICENSE

.. |Downloads| image:: https://static.pepy.tech/badge/skfolio
   :target: https://pepy.tech/project/skfolio

.. |Ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
   :target: https://github.com/astral-sh/ruff

.. |Contribution| image:: https://img.shields.io/badge/Contributions-Welcome-blue
   :target: https://github.com/skfolio/skfolio/blob/main/CONTRIBUTING.md

.. |Website| image:: https://img.shields.io/website.svg?down_color=red&down_message=down&up_color=53cc0d&up_message=up&url=https://skfolio.org
   :target: https://skfolio.org

.. |JupyterLite| image:: https://jupyterlite.rtfd.io/en/latest/_static/badge.svg
   :target: https://skfolio.org/lite

.. |Discord| image:: https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white
   :target: https://discord.gg/Bu7EtNYugS

.. |DOI| image:: https://zenodo.org/badge/731792488.svg
   :target: https://doi.org/10.5281/zenodo.16148630

.. |PythonMinVersion| replace:: 3.10
.. |NumpyMinVersion| replace:: 1.23.4
.. |ScipyMinVersion| replace:: 1.8.0
.. |PandasMinVersion| replace:: 1.4.1
.. |CvxpyBaseMinVersion| replace:: 1.5.0
.. |ClarabelMinVersion| replace:: 0.9.0
.. |SklearnMinVersion| replace:: 1.6.0
.. |JoblibMinVersion| replace:: 1.3.2
.. |PlotlyMinVersion| replace:: 5.22.0


===============
|icon|  skfolio
===============
.. |icon| image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/logo_animate.svg
    :width: 100
    :alt: skfolio documentation
    :target: https://skfolio.org/


**skfolio** is a Python library for portfolio optimization and risk management built on
top of scikit-learn. It offers a unified interface and tools compatible with
scikit-learn to build, fine-tune, cross-validate and stress-test portfolio models.

It is distributed under the open-source 3-Clause BSD license.

.. image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/expo.jpg
    :target: https://skfolio.org/auto_examples/
    :alt: examples

Important links
~~~~~~~~~~~~~~~

- Documentation: https://skfolio.org/
- Examples: https://skfolio.org/auto_examples/
- User Guide: https://skfolio.org/user_guide/
- GitHub Repo: https://github.com/skfolio/skfolio/

Installation
~~~~~~~~~~~~

`skfolio` is available on PyPI and can be installed with::

    pip install -U skfolio


Dependencies
~~~~~~~~~~~~

`skfolio` requires:

- python (>= |PythonMinVersion|)
- numpy (>= |NumpyMinVersion|)
- scipy (>= |ScipyMinVersion|)
- pandas (>= |PandasMinVersion|)
- cvxpy-base (>= |CvxpyBaseMinVersion|)
- clarabel (>= |ClarabelMinVersion|)
- scikit-learn (>= |SklearnMinVersion|)
- joblib (>= |JoblibMinVersion|)
- plotly (>= |PlotlyMinVersion|)

Docker
~~~~~~

You can also spin up a reproducible JupyterLab environment using Docker:

Build the image::

    docker build -t skfolio-jupyterlab .

Run the container::

    docker run -p 8888:8888 -v <path-to-your-folder-containing-data>:/app/data -it skfolio-jupyterlab

Browse:

Open localhost:8888/lab and start using `skfolio`

Key Concepts
~~~~~~~~~~~~
Since the development of modern portfolio theory by Markowitz (1952), mean-variance
optimization (MVO) has received considerable attention.

Unfortunately, it faces a number of shortcomings, including high sensitivity to the
input parameters (expected returns and covariance), weight concentration, high turnover,
and poor out-of-sample performance.

It is well-known that naive allocation (1/N, inverse-vol, etc.) tends to outperform
MVO out-of-sample (DeMiguel, 2007).

Numerous approaches have been developed to alleviate these shortcomings (shrinkage,
additional constraints, regularization, uncertainty set, higher moments, Bayesian
approaches, coherent risk measures, left-tail risk optimization, distributionally robust
optimization, factor model, risk-parity, hierarchical clustering, ensemble methods,
pre-selection, etc.).

Given the large number of methods, and the fact that they can be combined, there is a
need for a unified framework with a machine-learning approach to perform model
selection, validation, and parameter tuning while mitigating the risk of data leakage
and overfitting.

This framework is built on scikit-learn's API.

Available models
~~~~~~~~~~~~~~~~

* Portfolio Optimization:
    * Naive:
        * Equal-Weighted
        * Inverse-Volatility
        * Random (Dirichlet)
    * Convex:
        * Mean-Risk
        * Risk Budgeting
        * Maximum Diversification
        * Distributionally Robust CVaR
    * Clustering:
        * Hierarchical Risk Parity
        * Hierarchical Equal Risk Contribution
        * Nested Clusters Optimization
    * Ensemble Methods:
        * Stacking Optimization

* Expected Returns Estimator:
    * Empirical
    * Exponentially Weighted
    * Equilibrium
    * Shrinkage

* Covariance Estimator:
    * Empirical
    * Gerber
    * Denoising
    * Detoning
    * Exponentially Weighted
    * Ledoit-Wolf
    * Oracle Approximating Shrinkage
    * Shrunk Covariance
    * Graphical Lasso CV
    * Implied Covariance

* Distance Estimator:
    * Pearson Distance
    * Kendall Distance
    * Spearman Distance
    * Covariance Distance (based on any of the above covariance estimators)
    * Distance Correlation
    * Variation of Information

* Distribution Estimator:
    * Univariate:
        * Gaussian
        * Student's t
        * Johnson Su
        * Normal Inverse Gaussian
    * Bivariate Copula
        * Gaussian Copula
        * Student's t Copula
        * Clayton Copula
        * Gumbel Copula
        * Joe Copula
        * Independent Copula
    * Multivariate
        * Vine Copula (Regular, Centered, Clustered, Conditional Sampling)

* Prior Estimator:
    * Empirical
    * Black & Litterman
    * Factor Model
    * Synthetic Data (Stress Test, Factor Stress Test)
    * Entropy Pooling
    * Opinion Pooling

* Uncertainty Set Estimator:
    * On Expected Returns:
        * Empirical
        * Circular Bootstrap
    * On Covariance:
        * Empirical
        * Circular Bootstrap

* Pre-Selection Transformer:
    * Non-Dominated Selection
    * Select K Extremes (Best or Worst)
    * Drop Highly Correlated Assets
    * Select Non-Expiring Assets
    * Select Complete Assets (handle late inception, delisting, etc.)
    * Drop Zero Variance

* Cross-Validation and Model Selection:
    * Compatible with all `sklearn` methods (KFold, etc.)
    * Walk Forward
    * Combinatorial Purged Cross-Validation
    * Multiple Randomized Cross-Validation

* Hyper-Parameter Tuning:
    * Compatible with all `sklearn` methods (GridSearchCV, RandomizedSearchCV)

* Risk Measures:
    * Variance
    * Semi-Variance
    * Mean Absolute Deviation
    * First Lower Partial Moment
    * CVaR (Conditional Value at Risk)
    * EVaR (Entropic Value at Risk)
    * Worst Realization
    * CDaR (Conditional Drawdown at Risk)
    * Maximum Drawdown
    * Average Drawdown
    * EDaR (Entropic Drawdown at Risk)
    * Ulcer Index
    * Gini Mean Difference
    * Value at Risk
    * Drawdown at Risk
    * Entropic Risk Measure
    * Fourth Central Moment
    * Fourth Lower Partial Moment
    * Skew
    * Kurtosis

* Optimization Features:
    * Minimize Risk
    * Maximize Returns
    * Maximize Utility
    * Maximize Ratio
    * Transaction Costs
    * Management Fees
    * L1 and L2 Regularization
    * Weight Constraints
    * Group Constraints
    * Budget Constraints
    * Tracking Error Constraints
    * Turnover Constraints
    * Cardinality and Group Cardinality Constraints
    * Threshold (Long and Short) Constraints

Quickstart
~~~~~~~~~~
The code snippets below are designed to introduce the functionality of `skfolio` so you
can start using it quickly. It follows the same API as scikit-learn.

Imports
-------
.. code-block:: python

    from sklearn import set_config
    from sklearn.model_selection import (
        GridSearchCV,
        KFold,
        RandomizedSearchCV,
        train_test_split,
    )
    from sklearn.pipeline import Pipeline
    from scipy.stats import loguniform

    from skfolio import RatioMeasure, RiskMeasure
    from skfolio.datasets import load_factors_dataset, load_sp500_dataset
    from skfolio.distribution import VineCopula
    from skfolio.model_selection import (
        CombinatorialPurgedCV,
        WalkForward,
        cross_val_predict,
    )
    from skfolio.moments import (
        DenoiseCovariance,
        DetoneCovariance,
        EWMu,
        GerberCovariance,
        ShrunkMu,
    )
    from skfolio.optimization import (
        MeanRisk,
        HierarchicalRiskParity,
        NestedClustersOptimization,
        ObjectiveFunction,
        RiskBudgeting,
    )
    from skfolio.pre_selection import SelectKExtremes
    from skfolio.preprocessing import prices_to_returns
    from skfolio.prior import (
        BlackLitterman,
        EmpiricalPrior,
        EntropyPooling,
        FactorModel,
        OpinionPooling,
        SyntheticData,
     )
    from skfolio.uncertainty_set import BootstrapMuUncertaintySet

Load Dataset
------------
.. code-block:: python

    prices = load_sp500_dataset()

Train/Test split
----------------
.. code-block:: python

    X = prices_to_returns(prices)
    X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)


Minimum Variance
----------------
.. code-block:: python

    model = MeanRisk()

Fit on Training Set
-------------------
.. code-block:: python

    model.fit(X_train)

    print(model.weights_)

Predict on Test Set
-------------------
.. code-block:: python

    portfolio = model.predict(X_test)

    print(portfolio.annualized_sharpe_ratio)
    print(portfolio.summary())



Maximum Sortino Ratio
---------------------
.. code-block:: python

    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        risk_measure=RiskMeasure.SEMI_VARIANCE,
    )


Denoised Covariance & Shrunk Expected Returns
---------------------------------------------
.. code-block:: python

    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        prior_estimator=EmpiricalPrior(
            mu_estimator=ShrunkMu(), covariance_estimator=DenoiseCovariance()
        ),
    )

Uncertainty Set on Expected Returns
-----------------------------------
.. code-block:: python

    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        mu_uncertainty_set_estimator=BootstrapMuUncertaintySet(),
    )


Weight Constraints & Transaction Costs
--------------------------------------
.. code-block:: python

    model = MeanRisk(
        min_weights={"AAPL": 0.10, "JPM": 0.05},
        max_weights=0.8,
        transaction_costs={"AAPL": 0.0001, "RRC": 0.0002},
        groups=[
            ["Equity"] * 3 + ["Fund"] * 5 + ["Bond"] * 12,
            ["US"] * 2 + ["Europe"] * 8 + ["Japan"] * 10,
        ],
        linear_constraints=[
            "Equity <= 0.5 * Bond",
            "US >= 0.1",
            "Europe >= 0.5 * Fund",
            "Japan <= 1",
        ],
    )
    model.fit(X_train)


Risk Parity on CVaR
-------------------
.. code-block:: python

    model = RiskBudgeting(risk_measure=RiskMeasure.CVAR)

Risk Parity & Gerber Covariance
-------------------------------
.. code-block:: python

    model = RiskBudgeting(
        prior_estimator=EmpiricalPrior(covariance_estimator=GerberCovariance())
    )

Nested Cluster Optimization with Cross-Validation and Parallelization
---------------------------------------------------------------------
.. code-block:: python

    model = NestedClustersOptimization(
        inner_estimator=MeanRisk(risk_measure=RiskMeasure.CVAR),
        outer_estimator=RiskBudgeting(risk_measure=RiskMeasure.VARIANCE),
        cv=KFold(),
        n_jobs=-1,
    )

Randomized Search of the L2 Norm
--------------------------------
.. code-block:: python

    randomized_search = RandomizedSearchCV(
        estimator=MeanRisk(),
        cv=WalkForward(train_size=252, test_size=60),
        param_distributions={
            "l2_coef": loguniform(1e-3, 1e-1),
        },
    )
    randomized_search.fit(X_train)

    best_model = randomized_search.best_estimator_

    print(best_model.weights_)


Grid Search on Embedded Parameters
----------------------------------
.. code-block:: python

    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        risk_measure=RiskMeasure.VARIANCE,
        prior_estimator=EmpiricalPrior(mu_estimator=EWMu(alpha=0.2)),
    )

    print(model.get_params(deep=True))

    gs = GridSearchCV(
        estimator=model,
        cv=KFold(n_splits=5, shuffle=False),
        n_jobs=-1,
        param_grid={
            "risk_measure": [
                RiskMeasure.VARIANCE,
                RiskMeasure.CVAR,
                RiskMeasure.VARIANCE.CDAR,
            ],
            "prior_estimator__mu_estimator__alpha": [0.05, 0.1, 0.2, 0.5],
        },
    )
    gs.fit(X)

    best_model = gs.best_estimator_

    print(best_model.weights_)


Black & Litterman Model
-----------------------
.. code-block:: python

    views = ["AAPL - BBY == 0.03 ", "CVX - KO == 0.04", "MSFT == 0.06 "]
    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        prior_estimator=BlackLitterman(views=views),
    )

Factor Model
------------
.. code-block:: python

    factor_prices = load_factors_dataset()

    X, factors = prices_to_returns(prices, factor_prices)
    X_train, X_test, factors_train, factors_test = train_test_split(
        X, factors, test_size=0.33, shuffle=False
    )

    model = MeanRisk(prior_estimator=FactorModel())
    model.fit(X_train, factors_train)

    print(model.weights_)

    portfolio = model.predict(X_test)

    print(portfolio.calmar_ratio)
    print(portfolio.summary())

Factor Model & Covariance Detoning
----------------------------------
.. code-block:: python

    model = MeanRisk(
        prior_estimator=FactorModel(
            factor_prior_estimator=EmpiricalPrior(covariance_estimator=DetoneCovariance())
        )
    )

Black & Litterman Factor Model
------------------------------
.. code-block:: python

    factor_views = ["MTUM - QUAL == 0.03 ", "VLUE == 0.06"]
    model = MeanRisk(
        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
        prior_estimator=FactorModel(
            factor_prior_estimator=BlackLitterman(views=factor_views),
        ),
    )

Pre-Selection Pipeline
----------------------
.. code-block:: python

    set_config(transform_output="pandas")
    model = Pipeline(
        [
            ("pre_selection", SelectKExtremes(k=10, highest=True)),
            ("optimization", MeanRisk()),
        ]
    )
    model.fit(X_train)

    portfolio = model.predict(X_test)




K-fold Cross-Validation
-----------------------
.. code-block:: python

    model = MeanRisk()
    mmp = cross_val_predict(model, X_test, cv=KFold(n_splits=5))
    # mmp is the predicted MultiPeriodPortfolio object composed of 5 Portfolios (1 per testing fold)

    mmp.plot_cumulative_returns()
    print(mmp.summary())


Combinatorial Purged Cross-Validation
-------------------------------------
.. code-block:: python

    model = MeanRisk()

    cv = CombinatorialPurgedCV(n_folds=10, n_test_folds=2)

    print(cv.summary(X_train))

    population = cross_val_predict(model, X_train, cv=cv)

    population.plot_distribution(
        measure_list=[RatioMeasure.SHARPE_RATIO, RatioMeasure.SORTINO_RATIO]
    )
    population.plot_cumulative_returns()
    print(population.summary())


Minimum CVaR Optimization on Synthetic Returns
----------------------------------------------
.. code-block:: python

    vine = VineCopula(log_transform=True, n_jobs=-1)
    prior = SyntheticData(distribution_estimator=vine, n_samples=2000)
    model = MeanRisk(risk_measure=RiskMeasure.CVAR, prior_estimator=prior)
    model.fit(X)
    print(model.weights_)


Stress Test
-----------
.. code-block:: python

    vine = VineCopula(log_transform=True, central_assets=["BAC"], n_jobs=-1)
    vine.fit(X)
    X_stressed = vine.sample(n_samples=10_000, conditioning = {"BAC": -0.2})
    ptf_stressed = model.predict(X_stressed)


Minimum CVaR Optimization on Synthetic Factors
----------------------------------------------
.. code-block:: python

    vine = VineCopula(central_assets=["QUAL"], log_transform=True, n_jobs=-1)
    factor_prior = SyntheticData(
        distribution_estimator=vine,
        n_samples=10_000,
        sample_args=dict(conditioning={"QUAL": -0.2}),
    )
    factor_model = FactorModel(factor_prior_estimator=factor_prior)
    model = MeanRisk(risk_measure=RiskMeasure.CVAR, prior_estimator=factor_model)
    model.fit(X, factors)
    print(model.weights_)


Factor Stress Test
------------------
.. code-block:: python

    factor_model.set_params(factor_prior_estimator__sample_args=dict(
        conditioning={"QUAL": -0.5}
    ))
    factor_model.fit(X, factors)
    stressed_dist = factor_model.return_distribution_
    stressed_ptf = model.predict(stressed_dist)

Entropy Pooling
---------------
.. code-block:: python

    entropy_pooling = EntropyPooling(
        mean_views=[
            "JPM == -0.002",
            "PG >= LLY",
            "BAC >= prior(BAC) * 1.2",
        ],
        cvar_views=[
            "GE == 0.08",
        ],
    )
    entropy_pooling.fit(X)
    print(entropy_pooling.relative_entropy_)
    print(entropy_pooling.effective_number_of_scenarios_)
    print(entropy_pooling.return_distribution_.sample_weight)

CVaR Hierarchical Risk Parity optimization on Entropy Pooling
-------------------------------------------------------------
.. code-block:: python

    entropy_pooling = EntropyPooling(cvar_views=["GE == 0.08"])
    model = HierarchicalRiskParity(
        risk_measure=RiskMeasure.CVAR,
        prior_estimator=entropy_pooling
    )
    model.fit(X)
    print(model.weights_)

Stress Test with Entropy Pooling on Factor Synthetic Data
---------------------------------------------------------
.. code-block:: python

    # Regular Vine Copula and sampling of 100,000 synthetic factor returns
    factor_synth = SyntheticData(
        n_samples=100_000,
        distribution_estimator=VineCopula(log_transform=True, n_jobs=-1, random_state=0)
    )

    # Entropy Pooling by imposing a CVaR-95% of 10% on the Quality factor
    factor_entropy_pooling = EntropyPooling(
        prior_estimator=factor_synth,
        cvar_views=["QUAL == 0.10"],
    )

    factor_entropy_pooling.fit(X, factors)

    # We retrieve the stressed distribution:
    stressed_dist = factor_model.return_distribution_

    # We stress-test our portfolio:
    stressed_ptf = model.predict(stressed_dist)

Opinion Pooling
---------------
.. code-block:: python

    # We consider two expert opinions, each generated via Entropy Pooling with
    # user-defined views.
    # We assign probabilities of 40% to Expert 1, 50% to Expert 2, and by default
    # the remaining 10% is allocated to the prior distribution:
    opinion_1 = EntropyPooling(cvar_views=["AMD == 0.10"])
    opinion_2 = EntropyPooling(
        mean_views=["AMD >= BAC", "JPM <= prior(JPM) * 0.8"],
        cvar_views=["GE == 0.12"],
    )

    opinion_pooling = OpinionPooling(
        estimators=[("opinion_1", opinion_1), ("opinion_2", opinion_2)],
        opinion_probabilities=[0.4, 0.5],
    )

    opinion_pooling.fit(X)


Recognition
~~~~~~~~~~~

We would like to thank all contributors to our direct dependencies, such as
`scikit-learn <https://github.com/scikit-learn/scikit-learn>`_ and `cvxpy <https://github.com/cvxpy/cvxpy>`_, as well as the contributors of the following resources that
served as sources of inspiration:

    * PyPortfolioOpt
    * Riskfolio-Lib
    * scikit-portfolio
    * microprediction
    * statsmodels
    * rsome
    * danielppalomar.com
    * gautier.marti.ai


Citation
~~~~~~~~

If you use `skfolio` in a scientific publication, we would appreciate citations:

**The library:**

.. code-block:: bibtex

        @software{skfolio,
          title     = {skfolio},
          author    = {Delatte, Hugo and Nicolini, Carlo and Manzi, Matteo},
          year      = {2024},
          doi       = {10.5281/zenodo.16148630},
          url       = {https://doi.org/10.5281/zenodo.16148630}
        }

The above uses the concept DOI, which always resolves to the latest release.
If you need precise reproducibility, especially for journals or conferences that require
it, you can cite the version-specific DOI for the exact release you used. To find it,
go to our `Zenodo project page <https://doi.org/10.5281/zenodo.16148630>`_, locate the
release you wish to reference (e.g. "v0.10.2"), and copy the DOI listed next to that
version.

**The paper:**

.. code-block:: bibtex

        @article{nicolini2025skfolio,
          title         = {skfolio: Portfolio Optimization in Python},
          author        = {Nicolini, Carlo and Manzi, Matteo and Delatte, Hugo},
          journal       = {arXiv preprint arXiv:2507.04176},
          year          = {2025},
          eprint        = {2507.04176},
          archivePrefix = {arXiv},
          url           = {https://arxiv.org/abs/2507.04176}
        }


            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "skfolio",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": "Hugo Delatte <delatte.hugo@gmail.com>, Matteo Manzi <matteomanzi09@gmail.com>, Carlo Nicolini <c.nicolini@ipazia.com>",
    "keywords": "portfolio, optimization, optimisation, finance, asset, allocation, quantitative, quant, investment, strategy, machine-learning, scikit-learn, data-mining, data-science",
    "author": null,
    "author_email": "Hugo Delatte <delatte.hugo@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/08/93/69068c6d1154381f26346d8198245fd29978b2c5afab458f21076fad63a4/skfolio-0.11.0.tar.gz",
    "platform": null,
    "description": ".. -*- mode: rst -*-\n\n|Licence| |Codecov| |Black| |PythonVersion| |PyPi| |CI/CD| |Downloads| |Ruff| |Contribution| |Website| |JupyterLite| |Discord| |DOI|\n\n.. |Licence| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg\n   :target: https://github.com/skfolio/skfolio/blob/main/LICENSE\n\n.. |Codecov| image:: https://codecov.io/gh/skfolio/skfolio/graph/badge.svg?token=KJ0SE4LHPV\n   :target: https://codecov.io/gh/skfolio/skfolio\n\n.. |PythonVersion| image:: https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue.svg\n   :target: https://pypi.org/project/skfolio/\n\n.. |PyPi| image:: https://img.shields.io/pypi/v/skfolio\n   :target: https://pypi.org/project/skfolio\n\n.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg\n   :target: https://github.com/psf/black\n\n.. |CI/CD| image:: https://img.shields.io/github/actions/workflow/status/skfolio/skfolio/release.yml.svg?logo=github\n   :target: https://github.com/skfolio/skfolio/raw/main/LICENSE\n\n.. |Downloads| image:: https://static.pepy.tech/badge/skfolio\n   :target: https://pepy.tech/project/skfolio\n\n.. |Ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n   :target: https://github.com/astral-sh/ruff\n\n.. |Contribution| image:: https://img.shields.io/badge/Contributions-Welcome-blue\n   :target: https://github.com/skfolio/skfolio/blob/main/CONTRIBUTING.md\n\n.. |Website| image:: https://img.shields.io/website.svg?down_color=red&down_message=down&up_color=53cc0d&up_message=up&url=https://skfolio.org\n   :target: https://skfolio.org\n\n.. |JupyterLite| image:: https://jupyterlite.rtfd.io/en/latest/_static/badge.svg\n   :target: https://skfolio.org/lite\n\n.. |Discord| image:: https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white\n   :target: https://discord.gg/Bu7EtNYugS\n\n.. |DOI| image:: https://zenodo.org/badge/731792488.svg\n   :target: https://doi.org/10.5281/zenodo.16148630\n\n.. |PythonMinVersion| replace:: 3.10\n.. |NumpyMinVersion| replace:: 1.23.4\n.. |ScipyMinVersion| replace:: 1.8.0\n.. |PandasMinVersion| replace:: 1.4.1\n.. |CvxpyBaseMinVersion| replace:: 1.5.0\n.. |ClarabelMinVersion| replace:: 0.9.0\n.. |SklearnMinVersion| replace:: 1.6.0\n.. |JoblibMinVersion| replace:: 1.3.2\n.. |PlotlyMinVersion| replace:: 5.22.0\n\n\n===============\n|icon|  skfolio\n===============\n.. |icon| image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/logo_animate.svg\n    :width: 100\n    :alt: skfolio documentation\n    :target: https://skfolio.org/\n\n\n**skfolio** is a Python library for portfolio optimization and risk management built on\ntop of scikit-learn. It offers a unified interface and tools compatible with\nscikit-learn to build, fine-tune, cross-validate and stress-test portfolio models.\n\nIt is distributed under the open-source 3-Clause BSD license.\n\n.. image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/expo.jpg\n    :target: https://skfolio.org/auto_examples/\n    :alt: examples\n\nImportant links\n~~~~~~~~~~~~~~~\n\n- Documentation: https://skfolio.org/\n- Examples: https://skfolio.org/auto_examples/\n- User Guide: https://skfolio.org/user_guide/\n- GitHub Repo: https://github.com/skfolio/skfolio/\n\nInstallation\n~~~~~~~~~~~~\n\n`skfolio` is available on PyPI and can be installed with::\n\n    pip install -U skfolio\n\n\nDependencies\n~~~~~~~~~~~~\n\n`skfolio` requires:\n\n- python (>= |PythonMinVersion|)\n- numpy (>= |NumpyMinVersion|)\n- scipy (>= |ScipyMinVersion|)\n- pandas (>= |PandasMinVersion|)\n- cvxpy-base (>= |CvxpyBaseMinVersion|)\n- clarabel (>= |ClarabelMinVersion|)\n- scikit-learn (>= |SklearnMinVersion|)\n- joblib (>= |JoblibMinVersion|)\n- plotly (>= |PlotlyMinVersion|)\n\nDocker\n~~~~~~\n\nYou can also spin up a reproducible JupyterLab environment using Docker:\n\nBuild the image::\n\n    docker build -t skfolio-jupyterlab .\n\nRun the container::\n\n    docker run -p 8888:8888 -v <path-to-your-folder-containing-data>:/app/data -it skfolio-jupyterlab\n\nBrowse:\n\nOpen localhost:8888/lab and start using `skfolio`\n\nKey Concepts\n~~~~~~~~~~~~\nSince the development of modern portfolio theory by Markowitz (1952), mean-variance\noptimization (MVO) has received considerable attention.\n\nUnfortunately, it faces a number of shortcomings, including high sensitivity to the\ninput parameters (expected returns and covariance), weight concentration, high turnover,\nand poor out-of-sample performance.\n\nIt is well-known that naive allocation (1/N, inverse-vol, etc.) tends to outperform\nMVO out-of-sample (DeMiguel, 2007).\n\nNumerous approaches have been developed to alleviate these shortcomings (shrinkage,\nadditional constraints, regularization, uncertainty set, higher moments, Bayesian\napproaches, coherent risk measures, left-tail risk optimization, distributionally robust\noptimization, factor model, risk-parity, hierarchical clustering, ensemble methods,\npre-selection, etc.).\n\nGiven the large number of methods, and the fact that they can be combined, there is a\nneed for a unified framework with a machine-learning approach to perform model\nselection, validation, and parameter tuning while mitigating the risk of data leakage\nand overfitting.\n\nThis framework is built on scikit-learn's API.\n\nAvailable models\n~~~~~~~~~~~~~~~~\n\n* Portfolio Optimization:\n    * Naive:\n        * Equal-Weighted\n        * Inverse-Volatility\n        * Random (Dirichlet)\n    * Convex:\n        * Mean-Risk\n        * Risk Budgeting\n        * Maximum Diversification\n        * Distributionally Robust CVaR\n    * Clustering:\n        * Hierarchical Risk Parity\n        * Hierarchical Equal Risk Contribution\n        * Nested Clusters Optimization\n    * Ensemble Methods:\n        * Stacking Optimization\n\n* Expected Returns Estimator:\n    * Empirical\n    * Exponentially Weighted\n    * Equilibrium\n    * Shrinkage\n\n* Covariance Estimator:\n    * Empirical\n    * Gerber\n    * Denoising\n    * Detoning\n    * Exponentially Weighted\n    * Ledoit-Wolf\n    * Oracle Approximating Shrinkage\n    * Shrunk Covariance\n    * Graphical Lasso CV\n    * Implied Covariance\n\n* Distance Estimator:\n    * Pearson Distance\n    * Kendall Distance\n    * Spearman Distance\n    * Covariance Distance (based on any of the above covariance estimators)\n    * Distance Correlation\n    * Variation of Information\n\n* Distribution Estimator:\n    * Univariate:\n        * Gaussian\n        * Student's t\n        * Johnson Su\n        * Normal Inverse Gaussian\n    * Bivariate Copula\n        * Gaussian Copula\n        * Student's t Copula\n        * Clayton Copula\n        * Gumbel Copula\n        * Joe Copula\n        * Independent Copula\n    * Multivariate\n        * Vine Copula (Regular, Centered, Clustered, Conditional Sampling)\n\n* Prior Estimator:\n    * Empirical\n    * Black & Litterman\n    * Factor Model\n    * Synthetic Data (Stress Test, Factor Stress Test)\n    * Entropy Pooling\n    * Opinion Pooling\n\n* Uncertainty Set Estimator:\n    * On Expected Returns:\n        * Empirical\n        * Circular Bootstrap\n    * On Covariance:\n        * Empirical\n        * Circular Bootstrap\n\n* Pre-Selection Transformer:\n    * Non-Dominated Selection\n    * Select K Extremes (Best or Worst)\n    * Drop Highly Correlated Assets\n    * Select Non-Expiring Assets\n    * Select Complete Assets (handle late inception, delisting, etc.)\n    * Drop Zero Variance\n\n* Cross-Validation and Model Selection:\n    * Compatible with all `sklearn` methods (KFold, etc.)\n    * Walk Forward\n    * Combinatorial Purged Cross-Validation\n    * Multiple Randomized Cross-Validation\n\n* Hyper-Parameter Tuning:\n    * Compatible with all `sklearn` methods (GridSearchCV, RandomizedSearchCV)\n\n* Risk Measures:\n    * Variance\n    * Semi-Variance\n    * Mean Absolute Deviation\n    * First Lower Partial Moment\n    * CVaR (Conditional Value at Risk)\n    * EVaR (Entropic Value at Risk)\n    * Worst Realization\n    * CDaR (Conditional Drawdown at Risk)\n    * Maximum Drawdown\n    * Average Drawdown\n    * EDaR (Entropic Drawdown at Risk)\n    * Ulcer Index\n    * Gini Mean Difference\n    * Value at Risk\n    * Drawdown at Risk\n    * Entropic Risk Measure\n    * Fourth Central Moment\n    * Fourth Lower Partial Moment\n    * Skew\n    * Kurtosis\n\n* Optimization Features:\n    * Minimize Risk\n    * Maximize Returns\n    * Maximize Utility\n    * Maximize Ratio\n    * Transaction Costs\n    * Management Fees\n    * L1 and L2 Regularization\n    * Weight Constraints\n    * Group Constraints\n    * Budget Constraints\n    * Tracking Error Constraints\n    * Turnover Constraints\n    * Cardinality and Group Cardinality Constraints\n    * Threshold (Long and Short) Constraints\n\nQuickstart\n~~~~~~~~~~\nThe code snippets below are designed to introduce the functionality of `skfolio` so you\ncan start using it quickly. It follows the same API as scikit-learn.\n\nImports\n-------\n.. code-block:: python\n\n    from sklearn import set_config\n    from sklearn.model_selection import (\n        GridSearchCV,\n        KFold,\n        RandomizedSearchCV,\n        train_test_split,\n    )\n    from sklearn.pipeline import Pipeline\n    from scipy.stats import loguniform\n\n    from skfolio import RatioMeasure, RiskMeasure\n    from skfolio.datasets import load_factors_dataset, load_sp500_dataset\n    from skfolio.distribution import VineCopula\n    from skfolio.model_selection import (\n        CombinatorialPurgedCV,\n        WalkForward,\n        cross_val_predict,\n    )\n    from skfolio.moments import (\n        DenoiseCovariance,\n        DetoneCovariance,\n        EWMu,\n        GerberCovariance,\n        ShrunkMu,\n    )\n    from skfolio.optimization import (\n        MeanRisk,\n        HierarchicalRiskParity,\n        NestedClustersOptimization,\n        ObjectiveFunction,\n        RiskBudgeting,\n    )\n    from skfolio.pre_selection import SelectKExtremes\n    from skfolio.preprocessing import prices_to_returns\n    from skfolio.prior import (\n        BlackLitterman,\n        EmpiricalPrior,\n        EntropyPooling,\n        FactorModel,\n        OpinionPooling,\n        SyntheticData,\n     )\n    from skfolio.uncertainty_set import BootstrapMuUncertaintySet\n\nLoad Dataset\n------------\n.. code-block:: python\n\n    prices = load_sp500_dataset()\n\nTrain/Test split\n----------------\n.. code-block:: python\n\n    X = prices_to_returns(prices)\n    X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)\n\n\nMinimum Variance\n----------------\n.. code-block:: python\n\n    model = MeanRisk()\n\nFit on Training Set\n-------------------\n.. code-block:: python\n\n    model.fit(X_train)\n\n    print(model.weights_)\n\nPredict on Test Set\n-------------------\n.. code-block:: python\n\n    portfolio = model.predict(X_test)\n\n    print(portfolio.annualized_sharpe_ratio)\n    print(portfolio.summary())\n\n\n\nMaximum Sortino Ratio\n---------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        risk_measure=RiskMeasure.SEMI_VARIANCE,\n    )\n\n\nDenoised Covariance & Shrunk Expected Returns\n---------------------------------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        prior_estimator=EmpiricalPrior(\n            mu_estimator=ShrunkMu(), covariance_estimator=DenoiseCovariance()\n        ),\n    )\n\nUncertainty Set on Expected Returns\n-----------------------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        mu_uncertainty_set_estimator=BootstrapMuUncertaintySet(),\n    )\n\n\nWeight Constraints & Transaction Costs\n--------------------------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        min_weights={\"AAPL\": 0.10, \"JPM\": 0.05},\n        max_weights=0.8,\n        transaction_costs={\"AAPL\": 0.0001, \"RRC\": 0.0002},\n        groups=[\n            [\"Equity\"] * 3 + [\"Fund\"] * 5 + [\"Bond\"] * 12,\n            [\"US\"] * 2 + [\"Europe\"] * 8 + [\"Japan\"] * 10,\n        ],\n        linear_constraints=[\n            \"Equity <= 0.5 * Bond\",\n            \"US >= 0.1\",\n            \"Europe >= 0.5 * Fund\",\n            \"Japan <= 1\",\n        ],\n    )\n    model.fit(X_train)\n\n\nRisk Parity on CVaR\n-------------------\n.. code-block:: python\n\n    model = RiskBudgeting(risk_measure=RiskMeasure.CVAR)\n\nRisk Parity & Gerber Covariance\n-------------------------------\n.. code-block:: python\n\n    model = RiskBudgeting(\n        prior_estimator=EmpiricalPrior(covariance_estimator=GerberCovariance())\n    )\n\nNested Cluster Optimization with Cross-Validation and Parallelization\n---------------------------------------------------------------------\n.. code-block:: python\n\n    model = NestedClustersOptimization(\n        inner_estimator=MeanRisk(risk_measure=RiskMeasure.CVAR),\n        outer_estimator=RiskBudgeting(risk_measure=RiskMeasure.VARIANCE),\n        cv=KFold(),\n        n_jobs=-1,\n    )\n\nRandomized Search of the L2 Norm\n--------------------------------\n.. code-block:: python\n\n    randomized_search = RandomizedSearchCV(\n        estimator=MeanRisk(),\n        cv=WalkForward(train_size=252, test_size=60),\n        param_distributions={\n            \"l2_coef\": loguniform(1e-3, 1e-1),\n        },\n    )\n    randomized_search.fit(X_train)\n\n    best_model = randomized_search.best_estimator_\n\n    print(best_model.weights_)\n\n\nGrid Search on Embedded Parameters\n----------------------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        risk_measure=RiskMeasure.VARIANCE,\n        prior_estimator=EmpiricalPrior(mu_estimator=EWMu(alpha=0.2)),\n    )\n\n    print(model.get_params(deep=True))\n\n    gs = GridSearchCV(\n        estimator=model,\n        cv=KFold(n_splits=5, shuffle=False),\n        n_jobs=-1,\n        param_grid={\n            \"risk_measure\": [\n                RiskMeasure.VARIANCE,\n                RiskMeasure.CVAR,\n                RiskMeasure.VARIANCE.CDAR,\n            ],\n            \"prior_estimator__mu_estimator__alpha\": [0.05, 0.1, 0.2, 0.5],\n        },\n    )\n    gs.fit(X)\n\n    best_model = gs.best_estimator_\n\n    print(best_model.weights_)\n\n\nBlack & Litterman Model\n-----------------------\n.. code-block:: python\n\n    views = [\"AAPL - BBY == 0.03 \", \"CVX - KO == 0.04\", \"MSFT == 0.06 \"]\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        prior_estimator=BlackLitterman(views=views),\n    )\n\nFactor Model\n------------\n.. code-block:: python\n\n    factor_prices = load_factors_dataset()\n\n    X, factors = prices_to_returns(prices, factor_prices)\n    X_train, X_test, factors_train, factors_test = train_test_split(\n        X, factors, test_size=0.33, shuffle=False\n    )\n\n    model = MeanRisk(prior_estimator=FactorModel())\n    model.fit(X_train, factors_train)\n\n    print(model.weights_)\n\n    portfolio = model.predict(X_test)\n\n    print(portfolio.calmar_ratio)\n    print(portfolio.summary())\n\nFactor Model & Covariance Detoning\n----------------------------------\n.. code-block:: python\n\n    model = MeanRisk(\n        prior_estimator=FactorModel(\n            factor_prior_estimator=EmpiricalPrior(covariance_estimator=DetoneCovariance())\n        )\n    )\n\nBlack & Litterman Factor Model\n------------------------------\n.. code-block:: python\n\n    factor_views = [\"MTUM - QUAL == 0.03 \", \"VLUE == 0.06\"]\n    model = MeanRisk(\n        objective_function=ObjectiveFunction.MAXIMIZE_RATIO,\n        prior_estimator=FactorModel(\n            factor_prior_estimator=BlackLitterman(views=factor_views),\n        ),\n    )\n\nPre-Selection Pipeline\n----------------------\n.. code-block:: python\n\n    set_config(transform_output=\"pandas\")\n    model = Pipeline(\n        [\n            (\"pre_selection\", SelectKExtremes(k=10, highest=True)),\n            (\"optimization\", MeanRisk()),\n        ]\n    )\n    model.fit(X_train)\n\n    portfolio = model.predict(X_test)\n\n\n\n\nK-fold Cross-Validation\n-----------------------\n.. code-block:: python\n\n    model = MeanRisk()\n    mmp = cross_val_predict(model, X_test, cv=KFold(n_splits=5))\n    # mmp is the predicted MultiPeriodPortfolio object composed of 5 Portfolios (1 per testing fold)\n\n    mmp.plot_cumulative_returns()\n    print(mmp.summary())\n\n\nCombinatorial Purged Cross-Validation\n-------------------------------------\n.. code-block:: python\n\n    model = MeanRisk()\n\n    cv = CombinatorialPurgedCV(n_folds=10, n_test_folds=2)\n\n    print(cv.summary(X_train))\n\n    population = cross_val_predict(model, X_train, cv=cv)\n\n    population.plot_distribution(\n        measure_list=[RatioMeasure.SHARPE_RATIO, RatioMeasure.SORTINO_RATIO]\n    )\n    population.plot_cumulative_returns()\n    print(population.summary())\n\n\nMinimum CVaR Optimization on Synthetic Returns\n----------------------------------------------\n.. code-block:: python\n\n    vine = VineCopula(log_transform=True, n_jobs=-1)\n    prior = SyntheticData(distribution_estimator=vine, n_samples=2000)\n    model = MeanRisk(risk_measure=RiskMeasure.CVAR, prior_estimator=prior)\n    model.fit(X)\n    print(model.weights_)\n\n\nStress Test\n-----------\n.. code-block:: python\n\n    vine = VineCopula(log_transform=True, central_assets=[\"BAC\"], n_jobs=-1)\n    vine.fit(X)\n    X_stressed = vine.sample(n_samples=10_000, conditioning = {\"BAC\": -0.2})\n    ptf_stressed = model.predict(X_stressed)\n\n\nMinimum CVaR Optimization on Synthetic Factors\n----------------------------------------------\n.. code-block:: python\n\n    vine = VineCopula(central_assets=[\"QUAL\"], log_transform=True, n_jobs=-1)\n    factor_prior = SyntheticData(\n        distribution_estimator=vine,\n        n_samples=10_000,\n        sample_args=dict(conditioning={\"QUAL\": -0.2}),\n    )\n    factor_model = FactorModel(factor_prior_estimator=factor_prior)\n    model = MeanRisk(risk_measure=RiskMeasure.CVAR, prior_estimator=factor_model)\n    model.fit(X, factors)\n    print(model.weights_)\n\n\nFactor Stress Test\n------------------\n.. code-block:: python\n\n    factor_model.set_params(factor_prior_estimator__sample_args=dict(\n        conditioning={\"QUAL\": -0.5}\n    ))\n    factor_model.fit(X, factors)\n    stressed_dist = factor_model.return_distribution_\n    stressed_ptf = model.predict(stressed_dist)\n\nEntropy Pooling\n---------------\n.. code-block:: python\n\n    entropy_pooling = EntropyPooling(\n        mean_views=[\n            \"JPM == -0.002\",\n            \"PG >= LLY\",\n            \"BAC >= prior(BAC) * 1.2\",\n        ],\n        cvar_views=[\n            \"GE == 0.08\",\n        ],\n    )\n    entropy_pooling.fit(X)\n    print(entropy_pooling.relative_entropy_)\n    print(entropy_pooling.effective_number_of_scenarios_)\n    print(entropy_pooling.return_distribution_.sample_weight)\n\nCVaR Hierarchical Risk Parity optimization on Entropy Pooling\n-------------------------------------------------------------\n.. code-block:: python\n\n    entropy_pooling = EntropyPooling(cvar_views=[\"GE == 0.08\"])\n    model = HierarchicalRiskParity(\n        risk_measure=RiskMeasure.CVAR,\n        prior_estimator=entropy_pooling\n    )\n    model.fit(X)\n    print(model.weights_)\n\nStress Test with Entropy Pooling on Factor Synthetic Data\n---------------------------------------------------------\n.. code-block:: python\n\n    # Regular Vine Copula and sampling of 100,000 synthetic factor returns\n    factor_synth = SyntheticData(\n        n_samples=100_000,\n        distribution_estimator=VineCopula(log_transform=True, n_jobs=-1, random_state=0)\n    )\n\n    # Entropy Pooling by imposing a CVaR-95% of 10% on the Quality factor\n    factor_entropy_pooling = EntropyPooling(\n        prior_estimator=factor_synth,\n        cvar_views=[\"QUAL == 0.10\"],\n    )\n\n    factor_entropy_pooling.fit(X, factors)\n\n    # We retrieve the stressed distribution:\n    stressed_dist = factor_model.return_distribution_\n\n    # We stress-test our portfolio:\n    stressed_ptf = model.predict(stressed_dist)\n\nOpinion Pooling\n---------------\n.. code-block:: python\n\n    # We consider two expert opinions, each generated via Entropy Pooling with\n    # user-defined views.\n    # We assign probabilities of 40% to Expert 1, 50% to Expert 2, and by default\n    # the remaining 10% is allocated to the prior distribution:\n    opinion_1 = EntropyPooling(cvar_views=[\"AMD == 0.10\"])\n    opinion_2 = EntropyPooling(\n        mean_views=[\"AMD >= BAC\", \"JPM <= prior(JPM) * 0.8\"],\n        cvar_views=[\"GE == 0.12\"],\n    )\n\n    opinion_pooling = OpinionPooling(\n        estimators=[(\"opinion_1\", opinion_1), (\"opinion_2\", opinion_2)],\n        opinion_probabilities=[0.4, 0.5],\n    )\n\n    opinion_pooling.fit(X)\n\n\nRecognition\n~~~~~~~~~~~\n\nWe would like to thank all contributors to our direct dependencies, such as\n`scikit-learn <https://github.com/scikit-learn/scikit-learn>`_ and `cvxpy <https://github.com/cvxpy/cvxpy>`_, as well as the contributors of the following resources that\nserved as sources of inspiration:\n\n    * PyPortfolioOpt\n    * Riskfolio-Lib\n    * scikit-portfolio\n    * microprediction\n    * statsmodels\n    * rsome\n    * danielppalomar.com\n    * gautier.marti.ai\n\n\nCitation\n~~~~~~~~\n\nIf you use `skfolio` in a scientific publication, we would appreciate citations:\n\n**The library:**\n\n.. code-block:: bibtex\n\n        @software{skfolio,\n          title     = {skfolio},\n          author    = {Delatte, Hugo and Nicolini, Carlo and Manzi, Matteo},\n          year      = {2024},\n          doi       = {10.5281/zenodo.16148630},\n          url       = {https://doi.org/10.5281/zenodo.16148630}\n        }\n\nThe above uses the concept DOI, which always resolves to the latest release.\nIf you need precise reproducibility, especially for journals or conferences that require\nit, you can cite the version-specific DOI for the exact release you used. To find it,\ngo to our `Zenodo project page <https://doi.org/10.5281/zenodo.16148630>`_, locate the\nrelease you wish to reference (e.g. \"v0.10.2\"), and copy the DOI listed next to that\nversion.\n\n**The paper:**\n\n.. code-block:: bibtex\n\n        @article{nicolini2025skfolio,\n          title         = {skfolio: Portfolio Optimization in Python},\n          author        = {Nicolini, Carlo and Manzi, Matteo and Delatte, Hugo},\n          journal       = {arXiv preprint arXiv:2507.04176},\n          year          = {2025},\n          eprint        = {2507.04176},\n          archivePrefix = {arXiv},\n          url           = {https://arxiv.org/abs/2507.04176}\n        }\n\n",
    "bugtrack_url": null,
    "license": "BSD 3-Clause License\n        \n        Copyright (c) 2007-2023 The skfolio developers.\n        All rights reserved.\n        \n        Redistribution and use in source and binary forms, with or without\n        modification, are permitted provided that the following conditions are met:\n        \n        * Redistributions of source code must retain the above copyright notice, this\n          list of conditions and the following disclaimer.\n        \n        * Redistributions in binary form must reproduce the above copyright notice,\n          this list of conditions and the following disclaimer in the documentation\n          and/or other materials provided with the distribution.\n        \n        * Neither the name of the copyright holder nor the names of its\n          contributors may be used to endorse or promote products derived from\n          this software without specific prior written permission.\n        \n        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n        AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n        IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n        FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n        DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n        SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n        CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n        OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n        OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
    "summary": "Portfolio optimization built on top of scikit-learn",
    "version": "0.11.0",
    "project_urls": {
        "API Reference": "https://www.skfolio.org/api_reference.html",
        "Documentation": "https://www.skfolio.org",
        "Repository": "https://github.com/skfolio/skfolio",
        "Tutorials": "https://www.skfolio.org"
    },
    "split_keywords": [
        "portfolio",
        " optimization",
        " optimisation",
        " finance",
        " asset",
        " allocation",
        " quantitative",
        " quant",
        " investment",
        " strategy",
        " machine-learning",
        " scikit-learn",
        " data-mining",
        " data-science"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "59784d72902b019a629241cc22166f033f83238c2903d7012e11c066d9fb6e13",
                "md5": "5f0856f1011700983c5824fdb051a634",
                "sha256": "a197be8692eb5a06d1acf3abd348d3ec458c6571758cfff03b14cacd8c36401b"
            },
            "downloads": -1,
            "filename": "skfolio-0.11.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5f0856f1011700983c5824fdb051a634",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 849982,
            "upload_time": "2025-07-26T20:36:27",
            "upload_time_iso_8601": "2025-07-26T20:36:27.669192Z",
            "url": "https://files.pythonhosted.org/packages/59/78/4d72902b019a629241cc22166f033f83238c2903d7012e11c066d9fb6e13/skfolio-0.11.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "089369068c6d1154381f26346d8198245fd29978b2c5afab458f21076fad63a4",
                "md5": "82f6ddab792d09d20a41069abf9df7e8",
                "sha256": "e8d499550010bcc0692ad0f0b360c70ca5c180cbcd6acdaa0c0fcec35b1b3682"
            },
            "downloads": -1,
            "filename": "skfolio-0.11.0.tar.gz",
            "has_sig": false,
            "md5_digest": "82f6ddab792d09d20a41069abf9df7e8",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 752905,
            "upload_time": "2025-07-26T20:36:29",
            "upload_time_iso_8601": "2025-07-26T20:36:29.785857Z",
            "url": "https://files.pythonhosted.org/packages/08/93/69068c6d1154381f26346d8198245fd29978b2c5afab458f21076fad63a4/skfolio-0.11.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-26 20:36:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "skfolio",
    "github_project": "skfolio",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "skfolio"
}
        
Elapsed time: 1.93220s