skfolio 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- skfolio-0.0.1/LICENSE +29 -0
- skfolio-0.0.1/MANIFEST.in +1 -0
- skfolio-0.0.1/PKG-INFO +568 -0
- skfolio-0.0.1/README.rst +496 -0
- skfolio-0.0.1/pyproject.toml +109 -0
- skfolio-0.0.1/setup.cfg +4 -0
- skfolio-0.0.1/src/skfolio/__init__.py +29 -0
- skfolio-0.0.1/src/skfolio/cluster/__init__.py +8 -0
- skfolio-0.0.1/src/skfolio/cluster/_hierarchical.py +387 -0
- skfolio-0.0.1/src/skfolio/datasets/__init__.py +20 -0
- skfolio-0.0.1/src/skfolio/datasets/_base.py +389 -0
- skfolio-0.0.1/src/skfolio/datasets/data/__init__.py +0 -0
- skfolio-0.0.1/src/skfolio/datasets/data/factors_dataset.csv.gz +0 -0
- skfolio-0.0.1/src/skfolio/datasets/data/sp500_dataset.csv.gz +0 -0
- skfolio-0.0.1/src/skfolio/datasets/data/sp500_index.csv.gz +0 -0
- skfolio-0.0.1/src/skfolio/distance/__init__.py +26 -0
- skfolio-0.0.1/src/skfolio/distance/_base.py +55 -0
- skfolio-0.0.1/src/skfolio/distance/_distance.py +574 -0
- skfolio-0.0.1/src/skfolio/exceptions.py +30 -0
- skfolio-0.0.1/src/skfolio/measures/__init__.py +76 -0
- skfolio-0.0.1/src/skfolio/measures/_enums.py +355 -0
- skfolio-0.0.1/src/skfolio/measures/_measures.py +607 -0
- skfolio-0.0.1/src/skfolio/metrics/__init__.py +3 -0
- skfolio-0.0.1/src/skfolio/metrics/_scorer.py +121 -0
- skfolio-0.0.1/src/skfolio/model_selection/__init__.py +18 -0
- skfolio-0.0.1/src/skfolio/model_selection/_combinatorial.py +407 -0
- skfolio-0.0.1/src/skfolio/model_selection/_validation.py +194 -0
- skfolio-0.0.1/src/skfolio/model_selection/_walk_forward.py +221 -0
- skfolio-0.0.1/src/skfolio/moments/__init__.py +41 -0
- skfolio-0.0.1/src/skfolio/moments/covariance/__init__.py +29 -0
- skfolio-0.0.1/src/skfolio/moments/covariance/_base.py +101 -0
- skfolio-0.0.1/src/skfolio/moments/covariance/_covariance.py +1108 -0
- skfolio-0.0.1/src/skfolio/moments/expected_returns/__init__.py +21 -0
- skfolio-0.0.1/src/skfolio/moments/expected_returns/_base.py +31 -0
- skfolio-0.0.1/src/skfolio/moments/expected_returns/_expected_returns.py +415 -0
- skfolio-0.0.1/src/skfolio/optimization/__init__.py +36 -0
- skfolio-0.0.1/src/skfolio/optimization/_base.py +147 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/__init__.py +13 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/_nco.py +348 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/hierarchical/__init__.py +13 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/hierarchical/_base.py +440 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/hierarchical/_herc.py +406 -0
- skfolio-0.0.1/src/skfolio/optimization/cluster/hierarchical/_hrp.py +368 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/__init__.py +16 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/_base.py +1944 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/_distributionally_robust.py +392 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/_maximum_diversification.py +417 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/_mean_risk.py +974 -0
- skfolio-0.0.1/src/skfolio/optimization/convex/_risk_budgeting.py +560 -0
- skfolio-0.0.1/src/skfolio/optimization/ensemble/__init__.py +6 -0
- skfolio-0.0.1/src/skfolio/optimization/ensemble/_base.py +87 -0
- skfolio-0.0.1/src/skfolio/optimization/ensemble/_stacking.py +326 -0
- skfolio-0.0.1/src/skfolio/optimization/naive/__init__.py +3 -0
- skfolio-0.0.1/src/skfolio/optimization/naive/_naive.py +173 -0
- skfolio-0.0.1/src/skfolio/population/__init__.py +3 -0
- skfolio-0.0.1/src/skfolio/population/_population.py +883 -0
- skfolio-0.0.1/src/skfolio/portfolio/__init__.py +13 -0
- skfolio-0.0.1/src/skfolio/portfolio/_base.py +1096 -0
- skfolio-0.0.1/src/skfolio/portfolio/_multi_period_portfolio.py +610 -0
- skfolio-0.0.1/src/skfolio/portfolio/_portfolio.py +842 -0
- skfolio-0.0.1/src/skfolio/pre_selection/__init__.py +7 -0
- skfolio-0.0.1/src/skfolio/pre_selection/_pre_selection.py +342 -0
- skfolio-0.0.1/src/skfolio/preprocessing/__init__.py +3 -0
- skfolio-0.0.1/src/skfolio/preprocessing/_returns.py +114 -0
- skfolio-0.0.1/src/skfolio/prior/__init__.py +18 -0
- skfolio-0.0.1/src/skfolio/prior/_base.py +63 -0
- skfolio-0.0.1/src/skfolio/prior/_black_litterman.py +238 -0
- skfolio-0.0.1/src/skfolio/prior/_empirical.py +163 -0
- skfolio-0.0.1/src/skfolio/prior/_factor_model.py +268 -0
- skfolio-0.0.1/src/skfolio/typing.py +50 -0
- skfolio-0.0.1/src/skfolio/uncertainty_set/__init__.py +23 -0
- skfolio-0.0.1/src/skfolio/uncertainty_set/_base.py +108 -0
- skfolio-0.0.1/src/skfolio/uncertainty_set/_bootstrap.py +281 -0
- skfolio-0.0.1/src/skfolio/uncertainty_set/_empirical.py +237 -0
- skfolio-0.0.1/src/skfolio/utils/__init__.py +0 -0
- skfolio-0.0.1/src/skfolio/utils/bootstrap.py +115 -0
- skfolio-0.0.1/src/skfolio/utils/equations.py +350 -0
- skfolio-0.0.1/src/skfolio/utils/sorting.py +117 -0
- skfolio-0.0.1/src/skfolio/utils/stats.py +466 -0
- skfolio-0.0.1/src/skfolio/utils/tools.py +567 -0
- skfolio-0.0.1/src/skfolio.egg-info/PKG-INFO +568 -0
- skfolio-0.0.1/src/skfolio.egg-info/SOURCES.txt +83 -0
- skfolio-0.0.1/src/skfolio.egg-info/dependency_links.txt +1 -0
- skfolio-0.0.1/src/skfolio.egg-info/requires.txt +14 -0
- skfolio-0.0.1/src/skfolio.egg-info/top_level.txt +1 -0
skfolio-0.0.1/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2007-2023 The skfolio developers.
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
* Neither the name of the copyright holder nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@@ -0,0 +1 @@
|
|
1
|
+
recursive-include src/skfolio/datasets *.csv.gz
|
skfolio-0.0.1/PKG-INFO
ADDED
@@ -0,0 +1,568 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: skfolio
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Portfolio optimization built on scikit-learn's API
|
5
|
+
Author-email: Hugo Delatte <delatte.hugo@gmail.com>
|
6
|
+
Maintainer-email: Hugo Delatte <delatte.hugo@gmail.com>
|
7
|
+
License: BSD 3-Clause License
|
8
|
+
|
9
|
+
Copyright (c) 2007-2023 The skfolio developers.
|
10
|
+
All rights reserved.
|
11
|
+
|
12
|
+
Redistribution and use in source and binary forms, with or without
|
13
|
+
modification, are permitted provided that the following conditions are met:
|
14
|
+
|
15
|
+
* Redistributions of source code must retain the above copyright notice, this
|
16
|
+
list of conditions and the following disclaimer.
|
17
|
+
|
18
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
19
|
+
this list of conditions and the following disclaimer in the documentation
|
20
|
+
and/or other materials provided with the distribution.
|
21
|
+
|
22
|
+
* Neither the name of the copyright holder nor the names of its
|
23
|
+
contributors may be used to endorse or promote products derived from
|
24
|
+
this software without specific prior written permission.
|
25
|
+
|
26
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
27
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
28
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
29
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
30
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
31
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
32
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
33
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
34
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
35
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
36
|
+
Project-URL: API Reference, https://www.skfolio.org/api_reference.html
|
37
|
+
Project-URL: Documentation, https://www.skfolio.org
|
38
|
+
Project-URL: Tutorials, https://www.skfolio.org
|
39
|
+
Project-URL: Repository, https://github.com/skfolio/skfolio
|
40
|
+
Keywords: portfolio,optimization,optimisation,finance,asset,allocation,quantitative,quant,investment,startegy,machine-learning,scikit-learn,data-mining,data-science
|
41
|
+
Classifier: Intended Audience :: Developers
|
42
|
+
Classifier: Intended Audience :: Science/Research
|
43
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
44
|
+
Classifier: License :: OSI Approved :: BSD License
|
45
|
+
Classifier: Operating System :: Unix
|
46
|
+
Classifier: Operating System :: Microsoft :: Windows
|
47
|
+
Classifier: Operating System :: MacOS
|
48
|
+
Classifier: Programming Language :: Python
|
49
|
+
Classifier: Programming Language :: Python :: 3
|
50
|
+
Classifier: Programming Language :: Python :: 3.10
|
51
|
+
Classifier: Programming Language :: Python :: 3.11
|
52
|
+
Classifier: Programming Language :: Python :: 3.12
|
53
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
54
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
55
|
+
Classifier: Topic :: Software Development
|
56
|
+
Requires-Python: >=3.10
|
57
|
+
Description-Content-Type: text/x-rst
|
58
|
+
License-File: LICENSE
|
59
|
+
Requires-Dist: numpy>=1.26.2
|
60
|
+
Requires-Dist: scipy>=1.11.4
|
61
|
+
Requires-Dist: pandas>=2.1.4
|
62
|
+
Requires-Dist: cvxpy>=1.4.1
|
63
|
+
Requires-Dist: joblib>=1.3.2
|
64
|
+
Requires-Dist: scikit-learn>=1.3.2
|
65
|
+
Requires-Dist: plotly>=5.18.0
|
66
|
+
Provides-Extra: dev
|
67
|
+
Requires-Dist: pytest; extra == "dev"
|
68
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
69
|
+
Requires-Dist: pydata-sphinx-theme; extra == "dev"
|
70
|
+
Requires-Dist: Sphinx>=7.2.6; extra == "dev"
|
71
|
+
Requires-Dist: sphinx-gallery; extra == "dev"
|
72
|
+
|
73
|
+
.. -*- mode: rst -*-
|
74
|
+
|
75
|
+
|Licence|_ |Codecov|_ |Black|_ |PythonVersion|_ |PyPi|_ |CI/CD|_
|
76
|
+
|
77
|
+
.. |Licence| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
|
78
|
+
.. _Licence: https://github.com/skfolio/skfolio/blob/main/LICENSE
|
79
|
+
|
80
|
+
.. |Codecov| image:: https://codecov.io/gh/scikit-learn/scikit-learn/branch/main/graph/badge.svg?token=Pk8G9gg3y9
|
81
|
+
.. _Codecov: https://codecov.io/gh/scikit-learn/scikit-learn
|
82
|
+
|
83
|
+
.. |PythonVersion| image:: https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10-blue
|
84
|
+
.. _PythonVersion: https://pypi.org/project/scikit-learn/
|
85
|
+
|
86
|
+
.. |PyPi| image:: https://img.shields.io/pypi/v/scikit-learn
|
87
|
+
.. _PyPi: https://pypi.org/project/scikit-learn
|
88
|
+
|
89
|
+
.. |Black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
90
|
+
.. _Black: https://github.com/psf/black
|
91
|
+
|
92
|
+
.. |CI/CD| image:: https://img.shields.io/github/actions/workflow/status/sktime/sktime/wheels.yml?logo=github
|
93
|
+
.. _CI/CD: https://github.com/skfolio/skfolio/blob/main/LICENSE
|
94
|
+
|
95
|
+
|
96
|
+
.. |PythonMinVersion| replace:: 3.10
|
97
|
+
.. |NumpyMinVersion| replace:: 1.26
|
98
|
+
.. |ScipyMinVersion| replace:: 1.11
|
99
|
+
.. |PandasMinVersion| replace:: 2.1
|
100
|
+
.. |NumbaMinVersion| replace:: 0.58
|
101
|
+
.. |CvxpyMinVersion| replace:: 1.4
|
102
|
+
.. |SklearnMinVersion| replace:: 1.3
|
103
|
+
.. |JoblibMinVersion| replace:: 1.3
|
104
|
+
.. |PlotlyMinVersion| replace:: 5.18
|
105
|
+
|
106
|
+
|
107
|
+
===============
|
108
|
+
|icon| skfolio
|
109
|
+
===============
|
110
|
+
.. |icon| image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/logo.ico
|
111
|
+
:width: 100
|
112
|
+
:target: https://skfolio.org/
|
113
|
+
|
114
|
+
|
115
|
+
**skfolio** is a Python library for portfolio optimization built on top of scikit-learn.
|
116
|
+
It provides a unified interface and `sklearn` compatible tools to build, tune and
|
117
|
+
cross-validate portfolio models. It is distributed under the 3-Clause BSD license.
|
118
|
+
|
119
|
+
.. image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/expo.jpg
|
120
|
+
|
121
|
+
Important links
|
122
|
+
~~~~~~~~~~~~~~~
|
123
|
+
|
124
|
+
- Documentation: https://skfolio.org
|
125
|
+
- Tutorials: https://skfolio.org
|
126
|
+
- Repository: https://github.com/skfolio/skfolio
|
127
|
+
|
128
|
+
Installation
|
129
|
+
~~~~~~~~~~~~
|
130
|
+
|
131
|
+
The easiest way to install skfolio is using ``pip``::
|
132
|
+
|
133
|
+
pip install -U skfolio
|
134
|
+
|
135
|
+
or ``conda``::
|
136
|
+
|
137
|
+
conda install -c conda-forge skfolio
|
138
|
+
|
139
|
+
|
140
|
+
Dependencies
|
141
|
+
~~~~~~~~~~~~
|
142
|
+
|
143
|
+
sklearn requires:
|
144
|
+
|
145
|
+
- python (>= |PythonMinVersion|)
|
146
|
+
- numpy (>= |NumpyMinVersion|)
|
147
|
+
- scipy (>= |ScipyMinVersion|)
|
148
|
+
- pandas (>= |PandasMinVersion|)
|
149
|
+
- cvxpy (>= |CvxpyMinVersion|)
|
150
|
+
- scikit-learn (>= |SklearnMinVersion|)
|
151
|
+
- joblib (>= |JoblibMinVersion|)
|
152
|
+
- plotly (>= |PlotlyMinVersion|)
|
153
|
+
|
154
|
+
Key Concepts
|
155
|
+
~~~~~~~~~~~~
|
156
|
+
Since the development of modern portfolio theory by Markowitz (1952), mean-variance optimization (MVO)
|
157
|
+
has received considerable attention. Unfortunately it faces a number of shortcomings including high sensitivity to the
|
158
|
+
input parameters (expected returns and covariance), weight concentration, high turnover and poor out-of-sample
|
159
|
+
performance.
|
160
|
+
It is well known that naive allocation (1/N, inverse-vol, ...) tend to outperform MVO out-of-sample (DeMiguel, 2007).
|
161
|
+
|
162
|
+
Numerous approaches have been developed to alleviate these shortcomings (shrinkage, bayesian approaches,
|
163
|
+
additional constraints, regularization, uncertainty set, higher moments, coherent risk measures,
|
164
|
+
left-tail risk optimization, distributionally robust optimization, factor model, risk-parity, hierarchical clustering,
|
165
|
+
ensemble methods...)
|
166
|
+
|
167
|
+
With this large number of methods, added to the fact that they can be composed together there is the need for an
|
168
|
+
unified framework to perform model selection, validation and parameter tuning while reducing the risk of data leakage
|
169
|
+
and overfitting. This framework is build on scikit-learn's API.
|
170
|
+
|
171
|
+
Available models
|
172
|
+
~~~~~~~~~~~~~~~~
|
173
|
+
The current release contains:
|
174
|
+
|
175
|
+
* Optimization estimators:
|
176
|
+
* Naive:
|
177
|
+
* Equal-Weighted
|
178
|
+
* Inverse-Volatility
|
179
|
+
* Random (dirichlet)
|
180
|
+
* Convex:
|
181
|
+
* Mean-Risk
|
182
|
+
* Risk Budgeting
|
183
|
+
* Maximum Diversification
|
184
|
+
* Distributionally Robust CVaR
|
185
|
+
* Clustering:
|
186
|
+
* Hierarchical Risk Parity
|
187
|
+
* Hierarchical Equal Risk Contribution
|
188
|
+
* Nested Clusters Optimization
|
189
|
+
* Ensemble methods:
|
190
|
+
* Stacking Optimization
|
191
|
+
|
192
|
+
* Moment estimators:
|
193
|
+
* Expected Returns:
|
194
|
+
* Empirical
|
195
|
+
* Exponentially Weighted
|
196
|
+
* Equilibrium
|
197
|
+
* Shrinkage (James-Stein, Bayes-Stein, ...)
|
198
|
+
* Covariance:
|
199
|
+
* Empirical
|
200
|
+
* Gerber
|
201
|
+
* Denoising
|
202
|
+
* Denoting
|
203
|
+
* Exponentially Weighted
|
204
|
+
* Ledoit-Wolf
|
205
|
+
* Oracle Approximating Shrinkage
|
206
|
+
* Shrunk Covariance
|
207
|
+
* Graphical lasso CV
|
208
|
+
|
209
|
+
* Distance estimator:
|
210
|
+
* Pearson Distance
|
211
|
+
* Kendall Distance
|
212
|
+
* Spearman Distance
|
213
|
+
* Covariance Distance (based on any of the above covariance estimators)
|
214
|
+
* Distance Correlation
|
215
|
+
* Variation of Information
|
216
|
+
|
217
|
+
* Prior estimators:
|
218
|
+
* Empirical
|
219
|
+
* Black & Litterman
|
220
|
+
* Factor Model
|
221
|
+
|
222
|
+
* Uncertainty Set estimators:
|
223
|
+
* On Expected Returns:
|
224
|
+
* Empirical
|
225
|
+
* Circular Bootstrap
|
226
|
+
* On Covariance:
|
227
|
+
* Empirical
|
228
|
+
* Circular bootstrap
|
229
|
+
|
230
|
+
* Pre-Selection transformers:
|
231
|
+
* Non-Dominated Selection
|
232
|
+
* Select K Extremes (Best or Worst)
|
233
|
+
* Drop Highly Correlated Assets
|
234
|
+
|
235
|
+
* Cross-Validation and Model Selection:
|
236
|
+
* Compatible with all `sklearn` methods (KFold, ...)
|
237
|
+
* Walk Forward
|
238
|
+
* Combinatorial Purged Cross-validation
|
239
|
+
|
240
|
+
* Hyper-Parameter Tuning:
|
241
|
+
* Compatible with all `sklearn` methods (GridSearchCV, RandomizedSearchCV, ...)
|
242
|
+
|
243
|
+
* Risk Measures:
|
244
|
+
* Variance
|
245
|
+
* Semi-Variance
|
246
|
+
* Mean Absolute Deviation
|
247
|
+
* First Lower Partial Moment
|
248
|
+
* CVaR (Conditional Value at Risk)
|
249
|
+
* EVaR (Entropic Value at Risk)
|
250
|
+
* Worst Realization
|
251
|
+
* CDaR (Conditional Drawdown at Risk)
|
252
|
+
* Maximum Drawdown
|
253
|
+
* Average Drawdown
|
254
|
+
* EDaR (Entropic Drawdown at Risk)
|
255
|
+
* Ulcer Index
|
256
|
+
* Gini Mean Difference
|
257
|
+
* Value at Risk
|
258
|
+
* Drawdown at Risk
|
259
|
+
* Entropic Risk Measure
|
260
|
+
* Fourth Central Moment
|
261
|
+
* Fourth Lower Partial Moment
|
262
|
+
* Skew
|
263
|
+
* Kurtosis
|
264
|
+
|
265
|
+
Quickstart
|
266
|
+
~~~~~~~~~~
|
267
|
+
The code snippets below are designed to introduce ``skfolio``'s functionality so you can start using it quickly.
|
268
|
+
|
269
|
+
Preparing the data
|
270
|
+
------------------
|
271
|
+
.. code-block:: python
|
272
|
+
|
273
|
+
from sklearn import set_config
|
274
|
+
from sklearn.model_selection import (
|
275
|
+
GridSearchCV,
|
276
|
+
KFold,
|
277
|
+
RandomizedSearchCV,
|
278
|
+
train_test_split,
|
279
|
+
)
|
280
|
+
from sklearn.pipeline import Pipeline
|
281
|
+
from scipy.stats import loguniform
|
282
|
+
|
283
|
+
from skfolio import RatioMeasure, RiskMeasure
|
284
|
+
from skfolio.datasets import load_factors_dataset, load_sp500_dataset
|
285
|
+
from skfolio.model_selection import (
|
286
|
+
CombinatorialPurgedCV,
|
287
|
+
WalkForward,
|
288
|
+
cross_val_predict,
|
289
|
+
)
|
290
|
+
from skfolio.moments import (
|
291
|
+
DenoiseCovariance,
|
292
|
+
DenoteCovariance,
|
293
|
+
EWMu,
|
294
|
+
GerberCovariance,
|
295
|
+
ShrunkMu,
|
296
|
+
)
|
297
|
+
from skfolio.optimization import (
|
298
|
+
MeanRisk,
|
299
|
+
NestedClustersOptimization,
|
300
|
+
ObjectiveFunction,
|
301
|
+
RiskBudgeting,
|
302
|
+
)
|
303
|
+
from skfolio.pre_selection import SelectKExtremes
|
304
|
+
from skfolio.preprocessing import prices_to_returns
|
305
|
+
from skfolio.prior import BlackLitterman, EmpiricalPrior, FactorModel
|
306
|
+
from skfolio.uncertainty_set import BootstrapMuUncertaintySet
|
307
|
+
|
308
|
+
prices = load_sp500_dataset()
|
309
|
+
|
310
|
+
X = prices_to_returns(prices)
|
311
|
+
X_train, X_test = train_test_split(X, test_size=0.33, shuffle=False)
|
312
|
+
|
313
|
+
|
314
|
+
Minimum Variance
|
315
|
+
----------------
|
316
|
+
.. code-block:: python
|
317
|
+
|
318
|
+
model = MeanRisk()
|
319
|
+
|
320
|
+
Fit on training set
|
321
|
+
-------------------
|
322
|
+
.. code-block:: python
|
323
|
+
|
324
|
+
model.fit(X_train)
|
325
|
+
print(model.weights_)
|
326
|
+
|
327
|
+
Predict on test set
|
328
|
+
-------------------
|
329
|
+
.. code-block:: python
|
330
|
+
|
331
|
+
portfolio = model.predict(X_test)
|
332
|
+
print(portfolio.annualized_sharpe_ratio)
|
333
|
+
print(portfolio.summary())
|
334
|
+
|
335
|
+
|
336
|
+
|
337
|
+
Maximum Sortino Ratio
|
338
|
+
---------------------
|
339
|
+
.. code-block:: python
|
340
|
+
|
341
|
+
model = MeanRisk(
|
342
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
343
|
+
risk_measure=RiskMeasure.SEMI_VARIANCE,
|
344
|
+
)
|
345
|
+
|
346
|
+
|
347
|
+
Denoised Covariance & Shrunk Expected Returns
|
348
|
+
---------------------------------------------
|
349
|
+
.. code-block:: python
|
350
|
+
|
351
|
+
model = MeanRisk(
|
352
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
353
|
+
prior_estimator=EmpiricalPrior(
|
354
|
+
mu_estimator=ShrunkMu(), covariance_estimator=DenoiseCovariance()
|
355
|
+
),
|
356
|
+
)
|
357
|
+
|
358
|
+
Uncertainty Set on Expected Returns
|
359
|
+
-----------------------------------
|
360
|
+
.. code-block:: python
|
361
|
+
|
362
|
+
model = MeanRisk(
|
363
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
364
|
+
mu_uncertainty_set_estimator=BootstrapMuUncertaintySet(),
|
365
|
+
)
|
366
|
+
|
367
|
+
|
368
|
+
Weight Constraints & Transaction Costs
|
369
|
+
--------------------------------------
|
370
|
+
.. code-block:: python
|
371
|
+
|
372
|
+
model = MeanRisk(
|
373
|
+
min_weights={"AAPL": 0.10, "JPM": 0.05},
|
374
|
+
max_weights=0.8,
|
375
|
+
transaction_costs={"AAPL": 0.0001, "RRC": 0.0002},
|
376
|
+
groups=[
|
377
|
+
["Equity"] * 3 + ["Fund"] * 5 + ["Bond"] * 12,
|
378
|
+
["US"] * 2 + ["Europe"] * 8 + ["Japan"] * 10,
|
379
|
+
],
|
380
|
+
linear_constraints=[
|
381
|
+
"Equity <= 0.5 * Bond",
|
382
|
+
"US >= 0.1",
|
383
|
+
"Europe >= 0.5 * Fund",
|
384
|
+
"Japan <= 1",
|
385
|
+
],
|
386
|
+
)
|
387
|
+
model.fit(X_train)
|
388
|
+
|
389
|
+
|
390
|
+
Risk Parity on CVaR
|
391
|
+
-------------------
|
392
|
+
.. code-block:: python
|
393
|
+
|
394
|
+
model = RiskBudgeting(risk_measure=RiskMeasure.CVAR)
|
395
|
+
|
396
|
+
Risk Parity & Gerber Covariance
|
397
|
+
-------------------------------
|
398
|
+
.. code-block:: python
|
399
|
+
|
400
|
+
model = RiskBudgeting(
|
401
|
+
prior_estimator=EmpiricalPrior(covariance_estimator=GerberCovariance())
|
402
|
+
)
|
403
|
+
|
404
|
+
Nested Cluster Optimization with cross-validation and parallelization
|
405
|
+
---------------------------------------------------------------------
|
406
|
+
.. code-block:: python
|
407
|
+
|
408
|
+
model = NestedClustersOptimization(
|
409
|
+
inner_estimator=MeanRisk(risk_measure=RiskMeasure.CVAR),
|
410
|
+
outer_estimator=RiskBudgeting(risk_measure=RiskMeasure.VARIANCE),
|
411
|
+
cv=KFold(),
|
412
|
+
n_jobs=-1,
|
413
|
+
)
|
414
|
+
|
415
|
+
Randomized Search of the L2 Norm
|
416
|
+
--------------------------------
|
417
|
+
.. code-block:: python
|
418
|
+
|
419
|
+
randomized_search = RandomizedSearchCV(
|
420
|
+
estimator=MeanRisk(),
|
421
|
+
cv=WalkForward(train_size=255, test_size=60),
|
422
|
+
param_distributions={
|
423
|
+
"l2_coef": loguniform(1e-3, 1e-1),
|
424
|
+
},
|
425
|
+
)
|
426
|
+
randomized_search.fit(X_train)
|
427
|
+
best_model = randomized_search.best_estimator_
|
428
|
+
print(best_model.weights_)
|
429
|
+
|
430
|
+
|
431
|
+
Grid Search on embedded parameters
|
432
|
+
----------------------------------
|
433
|
+
.. code-block:: python
|
434
|
+
|
435
|
+
model = MeanRisk(
|
436
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
437
|
+
risk_measure=RiskMeasure.VARIANCE,
|
438
|
+
prior_estimator=EmpiricalPrior(mu_estimator=EWMu(alpha=0.2)),
|
439
|
+
)
|
440
|
+
|
441
|
+
print(model.get_params(deep=True))
|
442
|
+
|
443
|
+
gs = GridSearchCV(
|
444
|
+
estimator=model,
|
445
|
+
cv=KFold(n_splits=5, shuffle=False),
|
446
|
+
n_jobs=-1,
|
447
|
+
param_grid={
|
448
|
+
"risk_measure": [
|
449
|
+
RiskMeasure.VARIANCE,
|
450
|
+
RiskMeasure.CVAR,
|
451
|
+
RiskMeasure.VARIANCE.CDAR,
|
452
|
+
],
|
453
|
+
"prior_estimator__mu_estimator__alpha": [0.05, 0.1, 0.2, 0.5],
|
454
|
+
},
|
455
|
+
)
|
456
|
+
gs.fit(X)
|
457
|
+
best_model = gs.best_estimator_
|
458
|
+
print(best_model.weights_)
|
459
|
+
|
460
|
+
|
461
|
+
Black & Litterman Model
|
462
|
+
-----------------------
|
463
|
+
.. code-block:: python
|
464
|
+
|
465
|
+
views = ["AAPL - BBY == 0.03 ", "CVX - KO == 0.04", "MSFT == 0.06 "]
|
466
|
+
model = MeanRisk(
|
467
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
468
|
+
prior_estimator=BlackLitterman(views=views),
|
469
|
+
)
|
470
|
+
|
471
|
+
Factor Model
|
472
|
+
------------
|
473
|
+
.. code-block:: python
|
474
|
+
|
475
|
+
factor_prices = load_factors_dataset()
|
476
|
+
|
477
|
+
X, y = prices_to_returns(prices, factor_prices)
|
478
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, shuffle=False)
|
479
|
+
|
480
|
+
model = MeanRisk(prior_estimator=FactorModel())
|
481
|
+
model.fit(X_train, y_train)
|
482
|
+
|
483
|
+
print(model.weights_)
|
484
|
+
portfolio = model.predict(X_test)
|
485
|
+
print(portfolio.calmar_ratio)
|
486
|
+
print(portfolio.summary())
|
487
|
+
|
488
|
+
|
489
|
+
Factor Model & Covariance Detoning
|
490
|
+
----------------------------------
|
491
|
+
.. code-block:: python
|
492
|
+
|
493
|
+
model = MeanRisk(
|
494
|
+
prior_estimator=FactorModel(
|
495
|
+
factor_prior_estimator=EmpiricalPrior(covariance_estimator=DenoteCovariance())
|
496
|
+
)
|
497
|
+
)
|
498
|
+
|
499
|
+
Black & Litterman Factor Model
|
500
|
+
------------------------------
|
501
|
+
.. code-block:: python
|
502
|
+
|
503
|
+
factor_views = ["MTUM - QUAL == 0.03 ", "SIZE - TLT == 0.04", "VLUE == 0.06"]
|
504
|
+
model = MeanRisk(
|
505
|
+
objective_function=ObjectiveFunction.MAXIMIZE_RATIO,
|
506
|
+
prior_estimator=FactorModel(
|
507
|
+
factor_prior_estimator=BlackLitterman(views=factor_views),
|
508
|
+
),
|
509
|
+
)
|
510
|
+
|
511
|
+
Pre-Selection Pipeline
|
512
|
+
----------------------
|
513
|
+
.. code-block:: python
|
514
|
+
|
515
|
+
set_config(transform_output="pandas")
|
516
|
+
model = Pipeline(
|
517
|
+
[
|
518
|
+
("pre_selection", SelectKExtremes(k=10, highest=True)),
|
519
|
+
("optimization", MeanRisk()),
|
520
|
+
]
|
521
|
+
)
|
522
|
+
model.fit(X_train)
|
523
|
+
portfolio = model.predict(X_test)
|
524
|
+
|
525
|
+
|
526
|
+
|
527
|
+
|
528
|
+
K-fold Cross-Validation
|
529
|
+
-----------------------
|
530
|
+
.. code-block:: python
|
531
|
+
|
532
|
+
model = MeanRisk()
|
533
|
+
mmp = cross_val_predict(model, X_test, cv=KFold(n_splits=5))
|
534
|
+
# mmp is the predicted MultiPeriodPortfolio object composed of 5 Portfolios (1 per testing fold)
|
535
|
+
mmp.plot_cumulative_returns()
|
536
|
+
print(mmp.summary()
|
537
|
+
|
538
|
+
|
539
|
+
Combinatorial Purged Cross-Validation
|
540
|
+
-------------------------------------
|
541
|
+
.. code-block:: python
|
542
|
+
|
543
|
+
model = MeanRisk()
|
544
|
+
cv = CombinatorialPurgedCV(n_folds=10, n_test_folds=2)
|
545
|
+
print(cv.get_summary(X_train))
|
546
|
+
population = cross_val_predict(model, X_train, cv=cv)
|
547
|
+
population.plot_distribution(
|
548
|
+
measure_list=[RatioMeasure.SHARPE_RATIO, RatioMeasure.SORTINO_RATIO]
|
549
|
+
)
|
550
|
+
population.plot_cumulative_returns()
|
551
|
+
print(population.summary())
|
552
|
+
|
553
|
+
|
554
|
+
|
555
|
+
Citation
|
556
|
+
~~~~~~~~
|
557
|
+
|
558
|
+
If you use scikit-learn in a scientific publication, we would appreciate citations:
|
559
|
+
|
560
|
+
Bibtex entry::
|
561
|
+
|
562
|
+
@misc{riskfolio,
|
563
|
+
author = {Hugo Delatte},
|
564
|
+
title = {skfolio},
|
565
|
+
year = {2023},
|
566
|
+
url = {https://github.com/skfolio/skfolio}
|
567
|
+
|
568
|
+
|