skfolio 0.0.10__py3-none-any.whl → 0.1.0__py3-none-any.whl
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/cluster/_hierarchical.py +5 -4
- skfolio/datasets/_base.py +5 -0
- skfolio/distance/_base.py +1 -0
- skfolio/distance/_distance.py +1 -0
- skfolio/exceptions.py +1 -0
- skfolio/measures/_enums.py +1 -0
- skfolio/measures/_measures.py +28 -0
- skfolio/metrics/_scorer.py +5 -0
- skfolio/model_selection/_combinatorial.py +5 -0
- skfolio/model_selection/_validation.py +5 -0
- skfolio/model_selection/_walk_forward.py +6 -1
- skfolio/moments/covariance/_base.py +7 -0
- skfolio/moments/covariance/_covariance.py +7 -0
- skfolio/moments/expected_returns/_base.py +4 -0
- skfolio/moments/expected_returns/_expected_returns.py +5 -0
- skfolio/optimization/_base.py +8 -0
- skfolio/optimization/cluster/_nco.py +5 -0
- skfolio/optimization/cluster/hierarchical/_base.py +4 -0
- skfolio/optimization/cluster/hierarchical/_herc.py +3 -1
- skfolio/optimization/cluster/hierarchical/_hrp.py +4 -0
- skfolio/optimization/convex/_base.py +4 -1
- skfolio/optimization/convex/_distributionally_robust.py +1 -0
- skfolio/optimization/convex/_maximum_diversification.py +2 -1
- skfolio/optimization/convex/_mean_risk.py +5 -2
- skfolio/optimization/convex/_risk_budgeting.py +3 -0
- skfolio/optimization/ensemble/_base.py +4 -0
- skfolio/optimization/ensemble/_stacking.py +4 -0
- skfolio/population/_population.py +1 -0
- skfolio/portfolio/_base.py +9 -9
- skfolio/portfolio/_multi_period_portfolio.py +9 -5
- skfolio/portfolio/_portfolio.py +3 -2
- skfolio/pre_selection/_pre_selection.py +1 -0
- skfolio/preprocessing/_returns.py +2 -1
- skfolio/prior/_base.py +1 -0
- skfolio/prior/_black_litterman.py +4 -0
- skfolio/prior/_empirical.py +2 -0
- skfolio/prior/_factor_model.py +5 -0
- skfolio/typing.py +1 -0
- skfolio/uncertainty_set/_base.py +1 -0
- skfolio/uncertainty_set/_bootstrap.py +5 -0
- skfolio/uncertainty_set/_empirical.py +5 -0
- skfolio/utils/bootstrap.py +3 -0
- skfolio/utils/equations.py +1 -0
- skfolio/utils/fixes/__init__.py +3 -0
- skfolio/utils/fixes/_dendrogram.py +389 -0
- skfolio/utils/sorting.py +1 -0
- skfolio/utils/stats.py +4 -1
- skfolio/utils/tools.py +4 -0
- {skfolio-0.0.10.dist-info → skfolio-0.1.0.dist-info}/METADATA +18 -7
- skfolio-0.1.0.dist-info/RECORD +81 -0
- skfolio-0.0.10.dist-info/RECORD +0 -79
- {skfolio-0.0.10.dist-info → skfolio-0.1.0.dist-info}/LICENSE +0 -0
- {skfolio-0.0.10.dist-info → skfolio-0.1.0.dist-info}/WHEEL +0 -0
- {skfolio-0.0.10.dist-info → skfolio-0.1.0.dist-info}/top_level.txt +0 -0
skfolio/prior/_factor_model.py
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
"""Factor Model estimator"""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
6
|
+
# Implementation derived from:
|
7
|
+
# Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
|
8
|
+
# scikit-learn, Copyright (c) 2007-2010 David Cournapeau, Fabian Pedregosa, Olivier
|
9
|
+
# Grisel Licensed under BSD 3 clause.
|
5
10
|
|
6
11
|
from abc import ABC, abstractmethod
|
7
12
|
|
skfolio/typing.py
CHANGED
skfolio/uncertainty_set/_base.py
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
"""Bootstrap Uncertainty Set estimators."""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
6
|
+
# Implementation derived from:
|
7
|
+
# Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
|
8
|
+
# scikit-learn, Copyright (c) 2007-2010 David Cournapeau, Fabian Pedregosa, Olivier
|
9
|
+
# Grisel Licensed under BSD 3 clause.
|
5
10
|
|
6
11
|
import numpy as np
|
7
12
|
import numpy.typing as npt
|
@@ -1,7 +1,12 @@
|
|
1
1
|
"""Empirical Uncertainty Set estimators."""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
6
|
+
# Implementation derived from:
|
7
|
+
# Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
|
8
|
+
# scikit-learn, Copyright (c) 2007-2010 David Cournapeau, Fabian Pedregosa, Olivier
|
9
|
+
# Grisel Licensed under BSD 3 clause.
|
5
10
|
|
6
11
|
import numpy as np
|
7
12
|
import numpy.typing as npt
|
skfolio/utils/bootstrap.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
"""Bootstrap module."""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
6
|
+
# Implementation derived from:
|
7
|
+
# Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
|
5
8
|
|
6
9
|
import numpy as np
|
7
10
|
|
skfolio/utils/equations.py
CHANGED
@@ -0,0 +1,389 @@
|
|
1
|
+
"""Compatibility fixes for plotly"""
|
2
|
+
|
3
|
+
# Fixes of the create_dendrogram plotly function until
|
4
|
+
# https://github.com/plotly/plotly.py/pull/4487 is corrected
|
5
|
+
|
6
|
+
from collections import OrderedDict
|
7
|
+
|
8
|
+
import numpy as np
|
9
|
+
import scipy.cluster.hierarchy as sch
|
10
|
+
import scipy.spatial as scs
|
11
|
+
from plotly import exceptions
|
12
|
+
from plotly.graph_objs import graph_objs
|
13
|
+
|
14
|
+
|
15
|
+
def create_dendrogram(
|
16
|
+
X,
|
17
|
+
orientation="bottom",
|
18
|
+
labels=None,
|
19
|
+
colorscale=None,
|
20
|
+
distfun=None,
|
21
|
+
linkagefun=lambda x: sch.linkage(x, "complete"),
|
22
|
+
hovertext=None,
|
23
|
+
color_threshold=None,
|
24
|
+
):
|
25
|
+
"""
|
26
|
+
Function that returns a dendrogram Plotly figure object. This is a thin
|
27
|
+
wrapper around scipy.cluster.hierarchy.dendrogram.
|
28
|
+
|
29
|
+
See also https://dash.plot.ly/dash-bio/clustergram.
|
30
|
+
|
31
|
+
:param (ndarray) X: Matrix of observations as array of arrays
|
32
|
+
:param (str) orientation: 'top', 'right', 'bottom', or 'left'
|
33
|
+
:param (list) labels: List of axis category labels(observation labels)
|
34
|
+
:param (list) colorscale: Optional colorscale for the dendrogram tree.
|
35
|
+
Requires 8 colors to be specified, the 7th of
|
36
|
+
which is ignored. With scipy>=1.5.0, the 2nd, 3rd
|
37
|
+
and 6th are used twice as often as the others.
|
38
|
+
Given a shorter list, the missing values are
|
39
|
+
replaced with defaults and with a longer list the
|
40
|
+
extra values are ignored.
|
41
|
+
:param (function) distfun: Function to compute the pairwise distance from
|
42
|
+
the observations
|
43
|
+
:param (function) linkagefun: Function to compute the linkage matrix from
|
44
|
+
the pairwise distances
|
45
|
+
:param (list[list]) hovertext: List of hovertext for constituent traces of dendrogram
|
46
|
+
clusters
|
47
|
+
:param (double) color_threshold: Value at which the separation of clusters will be made
|
48
|
+
|
49
|
+
Example 1: Simple bottom oriented dendrogram
|
50
|
+
|
51
|
+
>>> from plotly.figure_factory import create_dendrogram
|
52
|
+
|
53
|
+
>>> import numpy as np
|
54
|
+
|
55
|
+
>>> X = np.random.rand(10,10)
|
56
|
+
>>> fig = create_dendrogram(X)
|
57
|
+
>>> fig.show()
|
58
|
+
|
59
|
+
Example 2: Dendrogram to put on the left of the heatmap
|
60
|
+
|
61
|
+
>>> from plotly.figure_factory import create_dendrogram
|
62
|
+
|
63
|
+
>>> import numpy as np
|
64
|
+
|
65
|
+
>>> X = np.random.rand(5,5)
|
66
|
+
>>> names = ['Jack', 'Oxana', 'John', 'Chelsea', 'Mark']
|
67
|
+
>>> dendro = create_dendrogram(X, orientation='right', labels=names)
|
68
|
+
>>> dendro.update_layout({'width':700, 'height':500}) # doctest: +SKIP
|
69
|
+
>>> dendro.show()
|
70
|
+
|
71
|
+
Example 3: Dendrogram with Pandas
|
72
|
+
|
73
|
+
>>> from plotly.figure_factory import create_dendrogram
|
74
|
+
|
75
|
+
>>> import numpy as np
|
76
|
+
>>> import pandas as pd
|
77
|
+
|
78
|
+
>>> Index= ['A','B','C','D','E','F','G','H','I','J']
|
79
|
+
>>> df = pd.DataFrame(abs(np.random.randn(10, 10)), index=Index)
|
80
|
+
>>> fig = create_dendrogram(df, labels=Index)
|
81
|
+
>>> fig.show()
|
82
|
+
"""
|
83
|
+
|
84
|
+
s = X.shape
|
85
|
+
if len(s) != 2:
|
86
|
+
exceptions.PlotlyError("X should be 2-dimensional array.")
|
87
|
+
|
88
|
+
if distfun is None:
|
89
|
+
distfun = scs.distance.pdist
|
90
|
+
|
91
|
+
dendrogram = _Dendrogram(
|
92
|
+
X,
|
93
|
+
orientation,
|
94
|
+
labels,
|
95
|
+
colorscale,
|
96
|
+
distfun=distfun,
|
97
|
+
linkagefun=linkagefun,
|
98
|
+
hovertext=hovertext,
|
99
|
+
color_threshold=color_threshold,
|
100
|
+
)
|
101
|
+
|
102
|
+
return graph_objs.Figure(data=dendrogram.data, layout=dendrogram.layout)
|
103
|
+
|
104
|
+
|
105
|
+
class _Dendrogram:
|
106
|
+
"""Refer to FigureFactory.create_dendrogram() for docstring."""
|
107
|
+
|
108
|
+
def __init__(
|
109
|
+
self,
|
110
|
+
X,
|
111
|
+
orientation="bottom",
|
112
|
+
labels=None,
|
113
|
+
colorscale=None,
|
114
|
+
width=np.inf,
|
115
|
+
height=np.inf,
|
116
|
+
xaxis="xaxis",
|
117
|
+
yaxis="yaxis",
|
118
|
+
distfun=None,
|
119
|
+
linkagefun=lambda x: sch.linkage(x, "complete"),
|
120
|
+
hovertext=None,
|
121
|
+
color_threshold=None,
|
122
|
+
):
|
123
|
+
self.orientation = orientation
|
124
|
+
self.labels = labels
|
125
|
+
self.xaxis = xaxis
|
126
|
+
self.yaxis = yaxis
|
127
|
+
self.data = []
|
128
|
+
self.leaves = []
|
129
|
+
self.sign = {self.xaxis: 1, self.yaxis: 1}
|
130
|
+
self.layout = {self.xaxis: {}, self.yaxis: {}}
|
131
|
+
|
132
|
+
if self.orientation in ["left", "bottom"]:
|
133
|
+
self.sign[self.xaxis] = 1
|
134
|
+
else:
|
135
|
+
self.sign[self.xaxis] = -1
|
136
|
+
|
137
|
+
if self.orientation in ["right", "bottom"]:
|
138
|
+
self.sign[self.yaxis] = 1
|
139
|
+
else:
|
140
|
+
self.sign[self.yaxis] = -1
|
141
|
+
|
142
|
+
if distfun is None:
|
143
|
+
distfun = scs.distance.pdist
|
144
|
+
|
145
|
+
(dd_traces, xvals, yvals, ordered_labels, leaves) = self.get_dendrogram_traces(
|
146
|
+
X, colorscale, distfun, linkagefun, hovertext, color_threshold
|
147
|
+
)
|
148
|
+
|
149
|
+
self.labels = ordered_labels
|
150
|
+
self.leaves = leaves
|
151
|
+
yvals_flat = yvals.flatten()
|
152
|
+
xvals_flat = xvals.flatten()
|
153
|
+
|
154
|
+
self.zero_vals = []
|
155
|
+
|
156
|
+
for i in range(len(yvals_flat)):
|
157
|
+
if yvals_flat[i] == 0.0 and xvals_flat[i] not in self.zero_vals:
|
158
|
+
self.zero_vals.append(xvals_flat[i])
|
159
|
+
|
160
|
+
if len(self.zero_vals) > len(yvals) + 1:
|
161
|
+
# If the length of zero_vals is larger than the length of yvals,
|
162
|
+
# it means that there are wrong vals because of the identicial samples.
|
163
|
+
# Three and more identicial samples will make the yvals of spliting
|
164
|
+
# center into 0 and it will accidentally take it as leaves.
|
165
|
+
l_border = int(min(self.zero_vals))
|
166
|
+
r_border = int(max(self.zero_vals))
|
167
|
+
correct_leaves_pos = range(
|
168
|
+
l_border, r_border + 1, int((r_border - l_border) / len(yvals))
|
169
|
+
)
|
170
|
+
# Regenerating the leaves pos from the self.zero_vals with equally intervals.
|
171
|
+
self.zero_vals = [v for v in correct_leaves_pos]
|
172
|
+
|
173
|
+
self.zero_vals.sort()
|
174
|
+
self.layout = self.set_figure_layout(width, height)
|
175
|
+
self.data = dd_traces
|
176
|
+
|
177
|
+
def get_color_dict(self, colorscale):
|
178
|
+
"""
|
179
|
+
Returns colorscale used for dendrogram tree clusters.
|
180
|
+
|
181
|
+
:param (list) colorscale: Colors to use for the plot in rgb format.
|
182
|
+
:rtype (dict): A dict of default colors mapped to the user colorscale.
|
183
|
+
|
184
|
+
"""
|
185
|
+
|
186
|
+
# These are the color codes returned for dendrograms
|
187
|
+
# We're replacing them with nicer colors
|
188
|
+
# This list is the colors that can be used by dendrogram, which were
|
189
|
+
# determined as the combination of the default above_threshold_color and
|
190
|
+
# the default color palette (see scipy/cluster/hierarchy.py)
|
191
|
+
d = {
|
192
|
+
"r": "red",
|
193
|
+
"g": "green",
|
194
|
+
"b": "blue",
|
195
|
+
"c": "cyan",
|
196
|
+
"m": "magenta",
|
197
|
+
"y": "yellow",
|
198
|
+
"k": "black",
|
199
|
+
# palette in scipy/cluster/hierarchy.py
|
200
|
+
"w": "white",
|
201
|
+
}
|
202
|
+
default_colors = OrderedDict(sorted(d.items(), key=lambda t: t[0]))
|
203
|
+
|
204
|
+
if colorscale is None:
|
205
|
+
rgb_colorscale = [
|
206
|
+
"rgb(0,116,217)", # blue
|
207
|
+
"rgb(35,205,205)", # cyan
|
208
|
+
"rgb(61,153,112)", # green
|
209
|
+
"rgb(40,35,35)", # black
|
210
|
+
"rgb(133,20,75)", # magenta
|
211
|
+
"rgb(255,65,54)", # red
|
212
|
+
"rgb(255,255,255)", # white
|
213
|
+
"rgb(255,220,0)", # yellow
|
214
|
+
]
|
215
|
+
else:
|
216
|
+
rgb_colorscale = colorscale
|
217
|
+
|
218
|
+
for i in range(len(default_colors.keys())):
|
219
|
+
k = list(default_colors.keys())[i] # PY3 won't index keys
|
220
|
+
if i < len(rgb_colorscale):
|
221
|
+
default_colors[k] = rgb_colorscale[i]
|
222
|
+
|
223
|
+
# add support for cyclic format colors as introduced in scipy===1.5.0
|
224
|
+
# before this, the colors were named 'r', 'b', 'y' etc., now they are
|
225
|
+
# named 'C0', 'C1', etc. To keep the colors consistent regardless of the
|
226
|
+
# scipy version, we try as much as possible to map the new colors to the
|
227
|
+
# old colors
|
228
|
+
# this mapping was found by inpecting scipy/cluster/hierarchy.py (see
|
229
|
+
# comment above).
|
230
|
+
new_old_color_map = [
|
231
|
+
("C0", "b"),
|
232
|
+
("C1", "g"),
|
233
|
+
("C2", "r"),
|
234
|
+
("C3", "c"),
|
235
|
+
("C4", "m"),
|
236
|
+
("C5", "y"),
|
237
|
+
("C6", "k"),
|
238
|
+
("C7", "g"),
|
239
|
+
("C8", "r"),
|
240
|
+
("C9", "c"),
|
241
|
+
]
|
242
|
+
for nc, oc in new_old_color_map:
|
243
|
+
try:
|
244
|
+
default_colors[nc] = default_colors[oc]
|
245
|
+
except KeyError:
|
246
|
+
# it could happen that the old color isn't found (if a custom
|
247
|
+
# colorscale was specified), in this case we set it to an
|
248
|
+
# arbitrary default.
|
249
|
+
default_colors[nc] = "rgb(0,116,217)"
|
250
|
+
|
251
|
+
return default_colors
|
252
|
+
|
253
|
+
def set_axis_layout(self, axis_key):
|
254
|
+
"""
|
255
|
+
Sets and returns default axis object for dendrogram figure.
|
256
|
+
|
257
|
+
:param (str) axis_key: E.g., 'xaxis', 'xaxis1', 'yaxis', yaxis1', etc.
|
258
|
+
:rtype (dict): An axis_key dictionary with set parameters.
|
259
|
+
|
260
|
+
"""
|
261
|
+
axis_defaults = {
|
262
|
+
"type": "linear",
|
263
|
+
"ticks": "outside",
|
264
|
+
"mirror": "allticks",
|
265
|
+
"rangemode": "tozero",
|
266
|
+
"showticklabels": True,
|
267
|
+
"zeroline": False,
|
268
|
+
"showgrid": False,
|
269
|
+
"showline": True,
|
270
|
+
}
|
271
|
+
|
272
|
+
if len(self.labels) != 0:
|
273
|
+
axis_key_labels = self.xaxis
|
274
|
+
if self.orientation in ["left", "right"]:
|
275
|
+
axis_key_labels = self.yaxis
|
276
|
+
if axis_key_labels not in self.layout:
|
277
|
+
self.layout[axis_key_labels] = {}
|
278
|
+
self.layout[axis_key_labels]["tickvals"] = [
|
279
|
+
zv * self.sign[axis_key] for zv in self.zero_vals
|
280
|
+
]
|
281
|
+
self.layout[axis_key_labels]["ticktext"] = self.labels
|
282
|
+
self.layout[axis_key_labels]["tickmode"] = "array"
|
283
|
+
|
284
|
+
self.layout[axis_key].update(axis_defaults)
|
285
|
+
|
286
|
+
return self.layout[axis_key]
|
287
|
+
|
288
|
+
def set_figure_layout(self, width, height):
|
289
|
+
"""
|
290
|
+
Sets and returns default layout object for dendrogram figure.
|
291
|
+
|
292
|
+
"""
|
293
|
+
self.layout.update({
|
294
|
+
"showlegend": False,
|
295
|
+
"autosize": False,
|
296
|
+
"hovermode": "closest",
|
297
|
+
"width": width,
|
298
|
+
"height": height,
|
299
|
+
})
|
300
|
+
|
301
|
+
self.set_axis_layout(self.xaxis)
|
302
|
+
self.set_axis_layout(self.yaxis)
|
303
|
+
|
304
|
+
return self.layout
|
305
|
+
|
306
|
+
def get_dendrogram_traces(
|
307
|
+
self, X, colorscale, distfun, linkagefun, hovertext, color_threshold
|
308
|
+
):
|
309
|
+
"""
|
310
|
+
Calculates all the elements needed for plotting a dendrogram.
|
311
|
+
|
312
|
+
:param (ndarray) X: Matrix of observations as array of arrays
|
313
|
+
:param (list) colorscale: Color scale for dendrogram tree clusters
|
314
|
+
:param (function) distfun: Function to compute the pairwise distance
|
315
|
+
from the observations
|
316
|
+
:param (function) linkagefun: Function to compute the linkage matrix
|
317
|
+
from the pairwise distances
|
318
|
+
:param (list) hovertext: List of hovertext for constituent traces of dendrogram
|
319
|
+
:rtype (tuple): Contains all the traces in the following order:
|
320
|
+
(a) trace_list: List of Plotly trace objects for dendrogram tree
|
321
|
+
(b) icoord: All X points of the dendrogram tree as array of arrays
|
322
|
+
with length 4
|
323
|
+
(c) dcoord: All Y points of the dendrogram tree as array of arrays
|
324
|
+
with length 4
|
325
|
+
(d) ordered_labels: leaf labels in the order they are going to
|
326
|
+
appear on the plot
|
327
|
+
(e) P['leaves']: left-to-right traversal of the leaves
|
328
|
+
|
329
|
+
"""
|
330
|
+
d = distfun(X)
|
331
|
+
Z = linkagefun(d)
|
332
|
+
P = sch.dendrogram(
|
333
|
+
Z,
|
334
|
+
orientation=self.orientation,
|
335
|
+
labels=self.labels,
|
336
|
+
no_plot=True,
|
337
|
+
color_threshold=color_threshold,
|
338
|
+
)
|
339
|
+
|
340
|
+
icoord = np.array(P["icoord"])
|
341
|
+
dcoord = np.array(P["dcoord"])
|
342
|
+
ordered_labels = np.array(P["ivl"])
|
343
|
+
color_list = np.array(P["color_list"])
|
344
|
+
colors = self.get_color_dict(colorscale)
|
345
|
+
|
346
|
+
trace_list = []
|
347
|
+
|
348
|
+
for i in range(len(icoord)):
|
349
|
+
# xs and ys are arrays of 4 points that make up the '∩' shapes
|
350
|
+
# of the dendrogram tree
|
351
|
+
if self.orientation in ["top", "bottom"]:
|
352
|
+
xs = icoord[i]
|
353
|
+
else:
|
354
|
+
xs = dcoord[i]
|
355
|
+
|
356
|
+
if self.orientation in ["top", "bottom"]:
|
357
|
+
ys = dcoord[i]
|
358
|
+
else:
|
359
|
+
ys = icoord[i]
|
360
|
+
color_key = color_list[i]
|
361
|
+
hovertext_label = None
|
362
|
+
if hovertext:
|
363
|
+
hovertext_label = hovertext[i]
|
364
|
+
trace = dict(
|
365
|
+
type="scatter",
|
366
|
+
x=np.multiply(self.sign[self.xaxis], xs),
|
367
|
+
y=np.multiply(self.sign[self.yaxis], ys),
|
368
|
+
mode="lines",
|
369
|
+
marker=dict(color=colors[color_key]),
|
370
|
+
text=hovertext_label,
|
371
|
+
hoverinfo="text",
|
372
|
+
)
|
373
|
+
|
374
|
+
try:
|
375
|
+
x_index = int(self.xaxis[-1])
|
376
|
+
except ValueError:
|
377
|
+
x_index = ""
|
378
|
+
|
379
|
+
try:
|
380
|
+
y_index = int(self.yaxis[-1])
|
381
|
+
except ValueError:
|
382
|
+
y_index = ""
|
383
|
+
|
384
|
+
trace["xaxis"] = "x" + x_index
|
385
|
+
trace["yaxis"] = "y" + y_index
|
386
|
+
|
387
|
+
trace_list.append(trace)
|
388
|
+
|
389
|
+
return trace_list, icoord, dcoord, ordered_labels, P["leaves"]
|
skfolio/utils/sorting.py
CHANGED
skfolio/utils/stats.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
"""Tools module"""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
5
|
-
|
6
|
+
# Implementation derived from:
|
7
|
+
# Riskfolio-Lib, Copyright (c) 2020-2023, Dany Cajas, Licensed under BSD 3 clause.
|
8
|
+
# Statsmodels, Copyright (C) 2006, Jonathan E. Taylor, Licensed under BSD 3 clause.
|
6
9
|
|
7
10
|
from enum import auto
|
8
11
|
|
skfolio/utils/tools.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
"""Tools module"""
|
2
2
|
|
3
|
+
# Copyright (c) 2023
|
3
4
|
# Author: Hugo Delatte <delatte.hugo@gmail.com>
|
4
5
|
# License: BSD 3 clause
|
6
|
+
# Implementation derived from:
|
7
|
+
# scikit-learn, Copyright (c) 2007-2010 David Cournapeau, Fabian Pedregosa, Olivier
|
8
|
+
# Grisel Licensed under BSD 3 clause.
|
5
9
|
|
6
10
|
from collections.abc import Callable, Iterator
|
7
11
|
from enum import Enum
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: skfolio
|
3
|
-
Version: 0.0
|
3
|
+
Version: 0.1.0
|
4
4
|
Summary: Portfolio optimization built on top of scikit-learn
|
5
5
|
Author-email: Hugo Delatte <delatte.hugo@gmail.com>
|
6
6
|
Maintainer-email: Hugo Delatte <delatte.hugo@gmail.com>
|
@@ -37,7 +37,7 @@ Project-URL: API Reference, https://www.skfolio.org/api_reference.html
|
|
37
37
|
Project-URL: Documentation, https://www.skfolio.org
|
38
38
|
Project-URL: Tutorials, https://www.skfolio.org
|
39
39
|
Project-URL: Repository, https://github.com/skfolio/skfolio
|
40
|
-
Keywords: portfolio,optimization,optimisation,finance,asset,allocation,quantitative,quant,investment,
|
40
|
+
Keywords: portfolio,optimization,optimisation,finance,asset,allocation,quantitative,quant,investment,strategy,machine-learning,scikit-learn,data-mining,data-science
|
41
41
|
Classifier: Intended Audience :: Developers
|
42
42
|
Classifier: Intended Audience :: Science/Research
|
43
43
|
Classifier: Intended Audience :: Financial and Insurance Industry
|
@@ -85,12 +85,12 @@ Requires-Dist: ruff ; extra == 'tests'
|
|
85
85
|
|
86
86
|
.. -*- mode: rst -*-
|
87
87
|
|
88
|
-
|Licence|_ |Codecov|_ |Black|_ |PythonVersion|_ |PyPi|_ |CI/CD|_
|
88
|
+
|Licence|_ |Codecov|_ |Black|_ |PythonVersion|_ |PyPi|_ |CI/CD|_ |Downloads|_ |Ruff|_ |Contribution|_ |Website|_
|
89
89
|
|
90
90
|
.. |Licence| image:: https://img.shields.io/badge/License-BSD%203--Clause-blue.svg
|
91
91
|
.. _Licence: https://github.com/skfolio/skfolio/blob/main/LICENSE
|
92
92
|
|
93
|
-
.. |Codecov| image:: https://codecov.io/gh/skfolio/skfolio/
|
93
|
+
.. |Codecov| image:: https://codecov.io/gh/skfolio/skfolio/graph/badge.svg?token=KJ0SE4LHPV
|
94
94
|
.. _Codecov: https://codecov.io/gh/skfolio/skfolio
|
95
95
|
|
96
96
|
.. |PythonVersion| image:: https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12-blue
|
@@ -105,6 +105,17 @@ Requires-Dist: ruff ; extra == 'tests'
|
|
105
105
|
.. |CI/CD| image:: https://img.shields.io/github/actions/workflow/status/skfolio/skfolio/release.yml?logo=github
|
106
106
|
.. _CI/CD: https://github.com/skfolio/skfolio/raw/main/LICENSE
|
107
107
|
|
108
|
+
.. |Downloads| image:: https://static.pepy.tech/badge/skfolio
|
109
|
+
.. _Downloads: https://pepy.tech/project/skfolio
|
110
|
+
|
111
|
+
.. |Ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
112
|
+
.. _Ruff: https://github.com/astral-sh/ruff
|
113
|
+
|
114
|
+
.. |Contribution| image:: https://img.shields.io/badge/Contributions-Welcome-blue
|
115
|
+
.. _Contribution: https://github.com/skfolio/skfolio/blob/main/CONTRIBUTING.md
|
116
|
+
|
117
|
+
.. |Website| image:: https://img.shields.io/website-up-down-53cc0d-red/http/skfolio.org
|
118
|
+
.. _Website: https://skfolio.org
|
108
119
|
|
109
120
|
.. |PythonMinVersion| replace:: 3.10
|
110
121
|
.. |NumpyMinVersion| replace:: 1.23.4
|
@@ -119,7 +130,7 @@ Requires-Dist: ruff ; extra == 'tests'
|
|
119
130
|
===============
|
120
131
|
|icon| skfolio
|
121
132
|
===============
|
122
|
-
.. |icon| image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/
|
133
|
+
.. |icon| image:: https://raw.githubusercontent.com/skfolio/skfolio/master/docs/_static/logo_animate.svg
|
123
134
|
:width: 100
|
124
135
|
:alt: skfolio documentation
|
125
136
|
:target: https://skfolio.org/
|
@@ -465,7 +476,7 @@ Randomized Search of the L2 Norm
|
|
465
476
|
|
466
477
|
randomized_search = RandomizedSearchCV(
|
467
478
|
estimator=MeanRisk(),
|
468
|
-
cv=WalkForward(train_size=
|
479
|
+
cv=WalkForward(train_size=252, test_size=60),
|
469
480
|
param_distributions={
|
470
481
|
"l2_coef": loguniform(1e-3, 1e-1),
|
471
482
|
},
|
@@ -634,7 +645,7 @@ If you use `skfolio` in a scientific publication, we would appreciate citations:
|
|
634
645
|
Bibtex entry::
|
635
646
|
|
636
647
|
@misc{skfolio,
|
637
|
-
author = {Hugo Delatte},
|
648
|
+
author = {Hugo Delatte, Carlo Nicolini},
|
638
649
|
title = {skfolio},
|
639
650
|
year = {2023},
|
640
651
|
url = {https://github.com/skfolio/skfolio}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
skfolio/__init__.py,sha256=5pn5LpTz6v2j2sxGkY97cVRrSPsN3Yav9b6Uw08boEI,618
|
2
|
+
skfolio/exceptions.py,sha256=-XniKql9QHgfitMgHsE9UXWVPdjWpNGO2dVk2SsdPWE,662
|
3
|
+
skfolio/typing.py,sha256=yEZiCZ6UIyfYUqtfj9Kf2KA9mrjUbmxyzpH9uqVboJs,1378
|
4
|
+
skfolio/cluster/__init__.py,sha256=4g-PFB_ld9BhiQ1ZPvvAorpFbRwd_p_DkeRlulDv2Hk,251
|
5
|
+
skfolio/cluster/_hierarchical.py,sha256=SoISGgdyq4Rgqq1_TCzMbLv69c8a2Q91j_s9-jqaB3E,12817
|
6
|
+
skfolio/datasets/__init__.py,sha256=9Tpf0Uj8wgr-g7xqvqQP4S4TUYDUNmNmK8t6lqBw2Fs,407
|
7
|
+
skfolio/datasets/_base.py,sha256=GYvblFzTyfTs-Tij20FKWgVDCIT1n7y4uwx4TkZzdHc,13915
|
8
|
+
skfolio/datasets/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
skfolio/datasets/data/factors_dataset.csv.gz,sha256=brCJlT25DJo40yg1gnUXAakNtvWZZYR_1ksFeN5JcWE,36146
|
10
|
+
skfolio/datasets/data/sp500_dataset.csv.gz,sha256=7iHKwovvsdCnOanOsiGE-ZU5RyaqDP3pohlB0awErA0,426065
|
11
|
+
skfolio/datasets/data/sp500_index.csv.gz,sha256=iUw0QxwoT4aqZKRn4Xbio8m2l8hX65qzUAbC3VXT_fI,41898
|
12
|
+
skfolio/distance/__init__.py,sha256=vpdmjFlJeI0AvPV3r5tp2zooAG4N9ihCwPlaqqdVj1w,547
|
13
|
+
skfolio/distance/_base.py,sha256=jBgRk6lZrP1woSI9541fTfxBBkp4WCTLlRPmWcmA3j4,1326
|
14
|
+
skfolio/distance/_distance.py,sha256=PHDqEourtqKSSFYiXKaUPQQqNFEqIEBhWcbWwe3fxjg,18539
|
15
|
+
skfolio/measures/__init__.py,sha256=Wm8soTkAapZ-g82INBpljgKfxkwCAIJdqjBOGVZBeQ8,1571
|
16
|
+
skfolio/measures/_enums.py,sha256=oy8wPm3EGsHokgLXe9xfUKet4vAuvch0cJuISH9RNvk,8902
|
17
|
+
skfolio/measures/_measures.py,sha256=nrpfaOVF94_ZpZXe2ciaBNzioGVTkzuYTmkYp9_EMec,16826
|
18
|
+
skfolio/metrics/__init__.py,sha256=MomHJ5_bgjq4qUwGS2bfhNmG_ld0oQ4wK6y0Yy_Eonc,75
|
19
|
+
skfolio/metrics/_scorer.py,sha256=h1VuZk-zzn4rIChHl9FvM7RxqVT3b-jR1CEB-cr9F2s,4306
|
20
|
+
skfolio/model_selection/__init__.py,sha256=QYYm5lYyioZuPnsTu-b3lz-tCcl3Gwrx-y9IIvep13A,453
|
21
|
+
skfolio/model_selection/_combinatorial.py,sha256=z4nhqIq98iGMP9I3GM8ng1WRJDJQn4eQ56bYaw5JWog,14716
|
22
|
+
skfolio/model_selection/_validation.py,sha256=uPk9HhOak1jh3PEjNMyi3jx4PzIW2fxnqdC7u1yWGwY,7644
|
23
|
+
skfolio/model_selection/_walk_forward.py,sha256=pbMD8VM1OoKiEtrlPeCLG29xVijsq1RArSjTvGO1FnU,7539
|
24
|
+
skfolio/moments/__init__.py,sha256=BaP6FjU-CEsV_mcC2AOKXNFy-_wXZsk-jqzJG6mTpsM,746
|
25
|
+
skfolio/moments/covariance/__init__.py,sha256=KuzhGuiu-eOwQMgWmEhFhqCcOmiayrYp5yeL1NsFW98,563
|
26
|
+
skfolio/moments/covariance/_base.py,sha256=mJ61A-zWU6mIXmGKzP3hoGEZyMpPV6qNeSM-VcScaWY,3955
|
27
|
+
skfolio/moments/covariance/_covariance.py,sha256=AyLm15Y5aziAJGg5P58_sXoW4jf4inV8PAs2Ye1zEyA,39003
|
28
|
+
skfolio/moments/expected_returns/__init__.py,sha256=NETEcKKYKsQvzUU4ZIq6mgT14zdrgGS6pb5Dy3qMEAE,367
|
29
|
+
skfolio/moments/expected_returns/_base.py,sha256=xk9mzi48uCOHaMTGQBMr3FU7Ai_shxYhmGeOsVwjv9Q,871
|
30
|
+
skfolio/moments/expected_returns/_expected_returns.py,sha256=T_tt_dsYgXrjIM2REUii7_4_R8IEc3xdtuv45yYM-5o,13388
|
31
|
+
skfolio/optimization/__init__.py,sha256=vXIbwWJL48zJ1jy7ZB2PPBVx7rZo0vVA8QQQuD-L6ts,1021
|
32
|
+
skfolio/optimization/_base.py,sha256=5GEMjlw5jrbygTp-4ZCk7cmwjJ0PBOoNdULqypVlfQM,5606
|
33
|
+
skfolio/optimization/cluster/__init__.py,sha256=M3xVdYhNKp4e9CB7hzb4yjTxkkNCHh7Mt_KGFFrkOgs,388
|
34
|
+
skfolio/optimization/cluster/_nco.py,sha256=MKzNvDIAbqS_D41Vp7tNa7OrXYq_bYVSQEVbVCHOEWA,14834
|
35
|
+
skfolio/optimization/cluster/hierarchical/__init__.py,sha256=YnfcPHvjwB6kcG4hoQqc0NqIJKaG7OjBtmXNbOxCq08,405
|
36
|
+
skfolio/optimization/cluster/hierarchical/_base.py,sha256=0FtVcrMOFsQIJVaShf_qoHBRSuVmR4qzmJdvJc214HI,17255
|
37
|
+
skfolio/optimization/cluster/hierarchical/_herc.py,sha256=JyXYX4PE17alCzIv6piF-G7_nprgzdzfYp35kjAeWMo,17235
|
38
|
+
skfolio/optimization/cluster/hierarchical/_hrp.py,sha256=xdnbYNcY1Vpv-mDw-JAGz5o--Rl2b8CfGzyunLJe75M,16121
|
39
|
+
skfolio/optimization/convex/__init__.py,sha256=F6BPFikTo0B-7JCKazqLGEwM3RkgTNbFm5GAGkaq9Uo,570
|
40
|
+
skfolio/optimization/convex/_base.py,sha256=rw9j-FM6gfY0UvAZG99rdrbZsH9neQ_MxeJr6AGIwlQ,75423
|
41
|
+
skfolio/optimization/convex/_distributionally_robust.py,sha256=nQW_MD0wlVY_tvLvRq_CvezOn4q92YC7wHfzFE9k9tY,17308
|
42
|
+
skfolio/optimization/convex/_maximum_diversification.py,sha256=8wQn5eFEat5wixmu0cfaswAee8D5C-hzV4s5ntUoAFM,19137
|
43
|
+
skfolio/optimization/convex/_mean_risk.py,sha256=ivAjLXis4fUZ9XOvh_iOemfnvgDAzrK3LDvrlaa2TpA,43130
|
44
|
+
skfolio/optimization/convex/_risk_budgeting.py,sha256=wXCgn64w2alAGG-dGJ8IwFrhYVtybM-O2hXiFaXietg,23618
|
45
|
+
skfolio/optimization/ensemble/__init__.py,sha256=8TXxcxH2_gG3C1xtgQj9OHHr0Le8lhdejtlURL6T3ZY,158
|
46
|
+
skfolio/optimization/ensemble/_base.py,sha256=vOi08U1MjoceD_xMFKTdM8egd1sY0GsCh1BSJuKH_fQ,3445
|
47
|
+
skfolio/optimization/ensemble/_stacking.py,sha256=3yqGHE1MpnugkJ0Z6fp7bfYLOuImsfmeiMQ8XDdIdZY,13098
|
48
|
+
skfolio/optimization/naive/__init__.py,sha256=Dkr55R48urC-jfYN007NTbei16N91Na_EDYLVqzhGgQ,147
|
49
|
+
skfolio/optimization/naive/_naive.py,sha256=sadsU8TnNRf28EDLg-KZ4yJm2FvV204vdsb1MhVJyMQ,5561
|
50
|
+
skfolio/population/__init__.py,sha256=rsPPMUv95aTK7vmpPeQwF8NzFuBwk6RDo5g4HNaPzNM,80
|
51
|
+
skfolio/population/_population.py,sha256=cyHdpZr6Ib725CRE_rr0irI4sHEcVEAY-Gmy--1goKo,29242
|
52
|
+
skfolio/portfolio/__init__.py,sha256=YYtcAPmA2zeCxFGTXegg2FXcA7py6CxOX7IMTdYuXl0,586
|
53
|
+
skfolio/portfolio/_base.py,sha256=XHSFrQJRY6nIyUG8sd8ZgbwZt7_ZKlMRNCfOqdls0Rw,38314
|
54
|
+
skfolio/portfolio/_multi_period_portfolio.py,sha256=63RwL0oTn-3L5LON6f2e9J58zw9q8S2gQ5c8JfSnN28,22759
|
55
|
+
skfolio/portfolio/_portfolio.py,sha256=axthHXaavCll_qXrYvJqfk-6AuMNDb-syD__jU_9acU,30714
|
56
|
+
skfolio/pre_selection/__init__.py,sha256=VtUtDn-U-Mn_xR2k7yfld0Yb0rPhLakEAiBwUyi-4Z8,189
|
57
|
+
skfolio/pre_selection/_pre_selection.py,sha256=w84T14nKmzkgzbw5CW_AIlci741lXYxKUwB5pBjhTTI,12163
|
58
|
+
skfolio/preprocessing/__init__.py,sha256=15A1bzfPsbfxxXgGP1gstf4R0E_347Wn18z5W5jH-hk,94
|
59
|
+
skfolio/preprocessing/_returns.py,sha256=_7UtXugQPWitNrrZ3M2dUOAun8aVr0lI45Ms6KFiS94,3826
|
60
|
+
skfolio/prior/__init__.py,sha256=jql8NTiWlykPKJUXTOPdqm531mP8Pul1QAR6hXTXA6c,446
|
61
|
+
skfolio/prior/_base.py,sha256=Dx6rX0X6ymDiieFOI-ik3xMNNFhYEtwLSXOdajf5wZY,1927
|
62
|
+
skfolio/prior/_black_litterman.py,sha256=JuwVXLXY5qHETBZDg0wmBGMSQehJp_1t7c1-kanKaiU,9397
|
63
|
+
skfolio/prior/_empirical.py,sha256=YhCYW8R3vqs3ntF4WSokuwLW6Gd98df7f8LL8zCS-D0,5740
|
64
|
+
skfolio/prior/_factor_model.py,sha256=E42sx_CbT-GbkT-BBb59XrUP4DMYJzuf3I2MEcGEnyE,9608
|
65
|
+
skfolio/uncertainty_set/__init__.py,sha256=LlMHtYv9G9fgtM7m4sCSToS9et57Pm2Q2gGchTVrj6c,617
|
66
|
+
skfolio/uncertainty_set/_base.py,sha256=rZ3g2AhDKFQTPajgh6Fz5S5TTf0qM4Ie6RGxPhp32D8,3301
|
67
|
+
skfolio/uncertainty_set/_bootstrap.py,sha256=Rig8ZGc8rEOnYygPyTaDSu5lp3wGuZrQVRoJTm3UuAA,10301
|
68
|
+
skfolio/uncertainty_set/_empirical.py,sha256=81DoTFxWsx8dALVRbvVEc6mBfgC-QIkUOK60dhkgFUI,8429
|
69
|
+
skfolio/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
70
|
+
skfolio/utils/bootstrap.py,sha256=3zY2kO_GQURKEcQMCasJOSByde9Mt2IAi3KJH0_a4mk,3550
|
71
|
+
skfolio/utils/equations.py,sha256=w0HsYjA7cS0mHYsI9MpixHLkof3HN26nc14ZfqFrHlE,11047
|
72
|
+
skfolio/utils/sorting.py,sha256=lSjMvH2L-sSj-06B3MlwBrH1rtjCeGEe4hG894W7TE0,3504
|
73
|
+
skfolio/utils/stats.py,sha256=IP36nMc5j5Hcqjbg7lvDIsGp1GWRdOh5jU3W6Z8nkYs,13132
|
74
|
+
skfolio/utils/tools.py,sha256=roj4zTwmfunPb8HtxcOPAsCKpk0ZPEPnQztSglE9t4o,15351
|
75
|
+
skfolio/utils/fixes/__init__.py,sha256=knHau8PRZP07XDHR59CW8VWxkpTP0gdr6RAHJrO-zaA,95
|
76
|
+
skfolio/utils/fixes/_dendrogram.py,sha256=QK0OYAmlDe4sdrbFtRvxIlKfPlOGyA2zmsZIz1fIMsM,13505
|
77
|
+
skfolio-0.1.0.dist-info/LICENSE,sha256=F6Gi-ZJX5BlVzYK8R9NcvAkAsKa7KO29xB1OScbrH6Q,1526
|
78
|
+
skfolio-0.1.0.dist-info/METADATA,sha256=zUZtTWjCZIla8MbEauTnhntSsQbJut6GWXk2cjJPMuE,19613
|
79
|
+
skfolio-0.1.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
80
|
+
skfolio-0.1.0.dist-info/top_level.txt,sha256=NXEaoS9Ms7t32gxkb867nV0OKlU0KmssL7IJBVo0fJs,8
|
81
|
+
skfolio-0.1.0.dist-info/RECORD,,
|