skfolio 0.3.0__py3-none-any.whl → 0.4.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/datasets/_base.py +1 -1
- skfolio/measures/_measures.py +1 -1
- skfolio/model_selection/_walk_forward.py +265 -51
- skfolio/moments/covariance/_implied_covariance.py +19 -11
- skfolio/population/_population.py +215 -152
- skfolio/portfolio/_base.py +48 -9
- skfolio/portfolio/_multi_period_portfolio.py +45 -0
- skfolio/portfolio/_portfolio.py +82 -46
- skfolio/utils/tools.py +18 -1
- {skfolio-0.3.0.dist-info → skfolio-0.4.0.dist-info}/METADATA +1 -1
- {skfolio-0.3.0.dist-info → skfolio-0.4.0.dist-info}/RECORD +14 -14
- {skfolio-0.3.0.dist-info → skfolio-0.4.0.dist-info}/WHEEL +1 -1
- {skfolio-0.3.0.dist-info → skfolio-0.4.0.dist-info}/LICENSE +0 -0
- {skfolio-0.3.0.dist-info → skfolio-0.4.0.dist-info}/top_level.txt +0 -0
skfolio/portfolio/_base.py
CHANGED
@@ -59,6 +59,7 @@ from skfolio.utils.tools import (
|
|
59
59
|
args_names,
|
60
60
|
cached_property_slots,
|
61
61
|
format_measure,
|
62
|
+
optimal_rounding_decimals,
|
62
63
|
)
|
63
64
|
|
64
65
|
_ZERO_THRESHOLD = 1e-5
|
@@ -614,6 +615,13 @@ class BasePortfolio:
|
|
614
615
|
"""DataFrame of the Portfolio composition"""
|
615
616
|
pass
|
616
617
|
|
618
|
+
@abstractmethod
|
619
|
+
def contribution(
|
620
|
+
self, measure: skt.Measure, spacing: float | None = None, to_df: bool = True
|
621
|
+
) -> np.ndarray | pd.DataFrame:
|
622
|
+
"""Compute the contribution of each asset to a given measure"""
|
623
|
+
pass
|
624
|
+
|
617
625
|
# Custom attribute setter and getter
|
618
626
|
@property
|
619
627
|
def fitness_measures(self) -> list[skt.Measure]:
|
@@ -811,7 +819,7 @@ class BasePortfolio:
|
|
811
819
|
The measure. The default measure is the Sharpe Ratio.
|
812
820
|
|
813
821
|
window : int, default=30
|
814
|
-
The window size. The default value is `30
|
822
|
+
The window size. The default value is `30` observations.
|
815
823
|
|
816
824
|
Returns
|
817
825
|
-------
|
@@ -925,11 +933,9 @@ class BasePortfolio:
|
|
925
933
|
key = f"{e!s} at {beta:.0%}"
|
926
934
|
except AttributeError:
|
927
935
|
key = str(e)
|
928
|
-
if
|
936
|
+
if e.is_ratio or e in [
|
929
937
|
ExtraRiskMeasure.ENTROPIC_RISK_MEASURE,
|
930
938
|
RiskMeasure.ULCER_INDEX,
|
931
|
-
ExtraRiskMeasure.SKEW,
|
932
|
-
ExtraRiskMeasure.KURTOSIS,
|
933
939
|
]:
|
934
940
|
percent = False
|
935
941
|
else:
|
@@ -1053,19 +1059,18 @@ class BasePortfolio:
|
|
1053
1059
|
line_dash="dash",
|
1054
1060
|
line_color="blue",
|
1055
1061
|
)
|
1056
|
-
max_val =
|
1057
|
-
min_val =
|
1058
|
-
if max_val > 0:
|
1062
|
+
max_val = np.max(rolling)
|
1063
|
+
min_val = np.min(rolling)
|
1064
|
+
if max_val > 0 > min_val:
|
1059
1065
|
fig.add_hrect(
|
1060
1066
|
y0=0, y1=max_val * 1.3, line_width=0, fillcolor="green", opacity=0.1
|
1061
1067
|
)
|
1062
|
-
if min_val < 0:
|
1063
1068
|
fig.add_hrect(
|
1064
1069
|
y0=min_val * 1.3, y1=0, line_width=0, fillcolor="red", opacity=0.1
|
1065
1070
|
)
|
1066
1071
|
|
1067
1072
|
fig.update_layout(
|
1068
|
-
title=f"
|
1073
|
+
title=f"Rolling {measure} - {window} observations window",
|
1069
1074
|
xaxis_title="Observations",
|
1070
1075
|
yaxis_title=str(measure),
|
1071
1076
|
showlegend=False,
|
@@ -1089,3 +1094,37 @@ class BasePortfolio:
|
|
1089
1094
|
legend_title_text="Assets",
|
1090
1095
|
)
|
1091
1096
|
return fig
|
1097
|
+
|
1098
|
+
def plot_contribution(self, measure: skt.Measure, spacing: float | None = None):
|
1099
|
+
r"""Plot the contribution of each asset to a given measure.
|
1100
|
+
|
1101
|
+
Parameters
|
1102
|
+
----------
|
1103
|
+
measure : Measure
|
1104
|
+
The measure used for the contribution computation.
|
1105
|
+
|
1106
|
+
spacing : float, optional
|
1107
|
+
Spacing "h" of the finite difference:
|
1108
|
+
:math:`contribution(wi)= \frac{measure(wi-h) - measure(wi+h)}{2h}`
|
1109
|
+
|
1110
|
+
Returns
|
1111
|
+
-------
|
1112
|
+
plot : Figure
|
1113
|
+
The plotly Figure of assets contribution to the measure.
|
1114
|
+
"""
|
1115
|
+
df = self.contribution(measure=measure, spacing=spacing, to_df=True).T
|
1116
|
+
fig = px.bar(df, x=df.index, y=df.columns)
|
1117
|
+
yaxis = {
|
1118
|
+
"title": "Contribution",
|
1119
|
+
}
|
1120
|
+
if not measure.is_ratio:
|
1121
|
+
n = optimal_rounding_decimals(df.sum(axis=1).max())
|
1122
|
+
yaxis["tickformat"] = f",.{n}%"
|
1123
|
+
|
1124
|
+
fig.update_layout(
|
1125
|
+
title=f"{measure} Contribution",
|
1126
|
+
xaxis_title="Portfolio",
|
1127
|
+
yaxis=yaxis,
|
1128
|
+
legend_title_text="Assets",
|
1129
|
+
)
|
1130
|
+
return fig
|
@@ -556,6 +556,51 @@ class MultiPeriodPortfolio(BasePortfolio):
|
|
556
556
|
df.columns = deduplicate_names(df.columns)
|
557
557
|
return df
|
558
558
|
|
559
|
+
@property
|
560
|
+
def weights_per_observation(self) -> pd.DataFrame:
|
561
|
+
"""DataFrame of the Portfolio weights per observation."""
|
562
|
+
return (
|
563
|
+
pd.concat([p.weights_per_observation for p in self], axis=0)
|
564
|
+
.fillna(0)
|
565
|
+
.sort_index()
|
566
|
+
)
|
567
|
+
|
568
|
+
def contribution(
|
569
|
+
self, measure: skt.Measure, spacing: float | None = None, to_df: bool = True
|
570
|
+
) -> np.ndarray | pd.DataFrame:
|
571
|
+
r"""Compute the contribution of each asset to a given measure for each
|
572
|
+
portfolio.
|
573
|
+
|
574
|
+
Parameters
|
575
|
+
----------
|
576
|
+
measure : Measure
|
577
|
+
The measure used for the contribution computation.
|
578
|
+
|
579
|
+
spacing : float, optional
|
580
|
+
Spacing "h" of the finite difference:
|
581
|
+
:math:`contribution(wi)= \frac{measure(wi-h) - measure(wi+h)}{2h}`
|
582
|
+
|
583
|
+
to_df : bool, default=False
|
584
|
+
If this is set to True, a DataFrame with asset names in index and portfolio
|
585
|
+
names in columns is returned, otherwise a list of numpy array is returned.
|
586
|
+
When a DataFrame is returned, the assets with zero weights are removed.
|
587
|
+
|
588
|
+
Returns
|
589
|
+
-------
|
590
|
+
values : list of numpy array of shape (n_assets,) for each portfolio or a DataFrame
|
591
|
+
The measure contribution of each asset for each portfolio.
|
592
|
+
"""
|
593
|
+
contributions = [
|
594
|
+
ptf.contribution(measure=measure, spacing=spacing, to_df=to_df)
|
595
|
+
for ptf in self
|
596
|
+
]
|
597
|
+
if not to_df:
|
598
|
+
return contributions
|
599
|
+
df = pd.concat(contributions, axis=1)
|
600
|
+
df.fillna(0, inplace=True)
|
601
|
+
df.columns = deduplicate_names(df.columns)
|
602
|
+
return df
|
603
|
+
|
559
604
|
def summary(self, formatted: bool = True) -> pd.Series:
|
560
605
|
"""Portfolio summary of all its measures.
|
561
606
|
|
skfolio/portfolio/_portfolio.py
CHANGED
@@ -14,7 +14,6 @@ from typing import ClassVar
|
|
14
14
|
import numpy as np
|
15
15
|
import numpy.typing as npt
|
16
16
|
import pandas as pd
|
17
|
-
import plotly.express as px
|
18
17
|
|
19
18
|
import skfolio.typing as skt
|
20
19
|
from skfolio.measures import RiskMeasure, effective_number_assets
|
@@ -668,7 +667,20 @@ class Portfolio(BasePortfolio):
|
|
668
667
|
return df
|
669
668
|
|
670
669
|
@property
|
671
|
-
def
|
670
|
+
def weights_per_observation(self) -> pd.DataFrame:
|
671
|
+
"""DataFrame of the Portfolio weights per observation."""
|
672
|
+
idx = self.nonzero_assets_index
|
673
|
+
weights = self.weights[idx]
|
674
|
+
assets = self.assets[idx]
|
675
|
+
df = pd.DataFrame(
|
676
|
+
np.ones((len(self.observations), len(assets))) * weights,
|
677
|
+
index=self.observations,
|
678
|
+
columns=assets,
|
679
|
+
)
|
680
|
+
return df
|
681
|
+
|
682
|
+
@property
|
683
|
+
def diversification(self) -> float:
|
672
684
|
"""Weighted average of volatility divided by the portfolio volatility."""
|
673
685
|
return (
|
674
686
|
self.weights @ np.std(np.asarray(self.X), axis=0) / self.standard_deviation
|
@@ -750,8 +762,8 @@ class Portfolio(BasePortfolio):
|
|
750
762
|
return float(self.weights @ assets_covariance @ self.weights.T)
|
751
763
|
|
752
764
|
def contribution(
|
753
|
-
self, measure: skt.Measure, spacing: float | None = None
|
754
|
-
) -> np.ndarray:
|
765
|
+
self, measure: skt.Measure, spacing: float | None = None, to_df: bool = False
|
766
|
+
) -> np.ndarray | pd.DataFrame:
|
755
767
|
r"""Compute the contribution of each asset to a given measure.
|
756
768
|
|
757
769
|
Parameters
|
@@ -763,9 +775,15 @@ class Portfolio(BasePortfolio):
|
|
763
775
|
Spacing "h" of the finite difference:
|
764
776
|
:math:`contribution(wi)= \frac{measure(wi-h) - measure(wi+h)}{2h}`
|
765
777
|
|
778
|
+
to_df : bool, default=False
|
779
|
+
If set to True, a DataFrame with asset names in index is returned,
|
780
|
+
otherwise a numpy array is returned. When a DataFrame is returned, the
|
781
|
+
values are sorted in descending order and assets with zero weights are
|
782
|
+
removed.
|
783
|
+
|
766
784
|
Returns
|
767
785
|
-------
|
768
|
-
values :
|
786
|
+
values : numpy array of shape (n_assets,) or DataFrame
|
769
787
|
The measure contribution of each asset.
|
770
788
|
"""
|
771
789
|
if spacing is None:
|
@@ -778,49 +796,26 @@ class Portfolio(BasePortfolio):
|
|
778
796
|
spacing = 1e-1
|
779
797
|
else:
|
780
798
|
spacing = 1e-5
|
781
|
-
args = {
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
w[i] += h
|
787
|
-
a["weights"] = w
|
788
|
-
return getattr(Portfolio(**a), measure.value)
|
789
|
-
|
790
|
-
cont = [
|
791
|
-
(get_risk(i, h=spacing) - get_risk(i, h=-spacing))
|
792
|
-
/ (2 * spacing)
|
793
|
-
* self.weights[i]
|
794
|
-
for i in range(len(self.weights))
|
795
|
-
]
|
796
|
-
return np.array(cont)
|
797
|
-
|
798
|
-
def plot_contribution(self, measure: skt.Measure, spacing: float | None = None):
|
799
|
-
r"""Plot the contribution of each asset to a given measure.
|
800
|
-
|
801
|
-
Parameters
|
802
|
-
----------
|
803
|
-
measure : Measure
|
804
|
-
The measure used for the contribution computation.
|
805
|
-
|
806
|
-
spacing : float, optional
|
807
|
-
Spacing "h" of the finite difference:
|
808
|
-
:math:`contribution(wi)= \frac{measure(wi-h) - measure(wi+h)}{2h}`
|
799
|
+
args = {
|
800
|
+
arg: getattr(self, arg)
|
801
|
+
for arg in args_names(self.__init__)
|
802
|
+
if arg != "weights"
|
803
|
+
}
|
809
804
|
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
fig = px.bar(df, x=df.index, y=df.columns)
|
818
|
-
fig.update_layout(
|
819
|
-
title=f"{measure} contribution",
|
820
|
-
xaxis_title="Asset",
|
821
|
-
yaxis_title=f"{measure} contribution",
|
805
|
+
contribution, assets = _compute_contribution(
|
806
|
+
args=args,
|
807
|
+
weights=self.weights,
|
808
|
+
assets=self.assets,
|
809
|
+
measure=measure,
|
810
|
+
h=spacing,
|
811
|
+
drop_zero_weights=to_df,
|
822
812
|
)
|
823
|
-
|
813
|
+
|
814
|
+
if not to_df:
|
815
|
+
return np.array(contribution)
|
816
|
+
df = pd.DataFrame(contribution, index=assets, columns=[self.name])
|
817
|
+
df.sort_values(by=self.name, ascending=False, inplace=True)
|
818
|
+
return df
|
824
819
|
|
825
820
|
def summary(self, formatted: bool = True) -> pd.Series:
|
826
821
|
"""Portfolio summary of all its measures.
|
@@ -863,3 +858,44 @@ class Portfolio(BasePortfolio):
|
|
863
858
|
return self.weights[np.where(self.assets == asset)[0][0]]
|
864
859
|
except IndexError:
|
865
860
|
raise IndexError("{asset} is not a valid asset name.") from None
|
861
|
+
|
862
|
+
|
863
|
+
def _get_risk(
|
864
|
+
args: dict, weights: np.ndarray, measure: skt.Measure, i: int, h: float
|
865
|
+
) -> float:
|
866
|
+
"""Get the Portfolio risk measure when the weight of asset `i` is increased by `h`."""
|
867
|
+
assert "weights" not in args
|
868
|
+
weights = weights.copy()
|
869
|
+
weights[i] += h
|
870
|
+
return getattr(Portfolio(weights=weights, **args), measure.value)
|
871
|
+
|
872
|
+
|
873
|
+
def _compute_contribution(
|
874
|
+
args: dict,
|
875
|
+
weights: np.ndarray,
|
876
|
+
assets: np.ndarray,
|
877
|
+
measure: skt.Measure,
|
878
|
+
h: float,
|
879
|
+
drop_zero_weights: bool,
|
880
|
+
) -> tuple[list[float], list[str]]:
|
881
|
+
"""Compute the contribution of each asset to a given measure using finite
|
882
|
+
difference.
|
883
|
+
"""
|
884
|
+
contributions = []
|
885
|
+
_assets = []
|
886
|
+
for i, (weight, asset) in enumerate(zip(weights, assets, strict=True)):
|
887
|
+
if weight == 0:
|
888
|
+
if not drop_zero_weights:
|
889
|
+
_assets.append(asset)
|
890
|
+
contributions.append(0)
|
891
|
+
else:
|
892
|
+
_assets.append(asset)
|
893
|
+
contributions.append(
|
894
|
+
(
|
895
|
+
_get_risk(args, weights, measure, i, h)
|
896
|
+
- _get_risk(args, weights, measure, i, -h)
|
897
|
+
)
|
898
|
+
/ (2 * h)
|
899
|
+
* weight
|
900
|
+
)
|
901
|
+
return contributions, _assets
|
skfolio/utils/tools.py
CHANGED
@@ -26,6 +26,7 @@ __all__ = [
|
|
26
26
|
"input_to_array",
|
27
27
|
"args_names",
|
28
28
|
"format_measure",
|
29
|
+
"optimal_rounding_decimals",
|
29
30
|
"bisection",
|
30
31
|
"safe_split",
|
31
32
|
"fit_single_estimator",
|
@@ -465,10 +466,26 @@ def format_measure(x: float, percent: bool = False) -> str:
|
|
465
466
|
if xn == 0:
|
466
467
|
n = 0
|
467
468
|
else:
|
468
|
-
n =
|
469
|
+
n = optimal_rounding_decimals(xn)
|
469
470
|
return "{value:{fmt}}".format(value=x, fmt=f".{n}{f}")
|
470
471
|
|
471
472
|
|
473
|
+
def optimal_rounding_decimals(x: float) -> int:
|
474
|
+
"""Return the optimal rounding decimal number for a user-friendly formatting.
|
475
|
+
|
476
|
+
Parameters
|
477
|
+
----------
|
478
|
+
x : float
|
479
|
+
Number to round.
|
480
|
+
|
481
|
+
Returns
|
482
|
+
-------
|
483
|
+
n : int
|
484
|
+
Rounding decimal number.
|
485
|
+
"""
|
486
|
+
return min(6, max(int(-np.log10(abs(x))) + 2, 2))
|
487
|
+
|
488
|
+
|
472
489
|
def bisection(x: list[np.ndarray]) -> Iterator[list[np.ndarray, np.ndarray]]:
|
473
490
|
"""Generator to bisect a list of array.
|
474
491
|
|
@@ -4,7 +4,7 @@ skfolio/typing.py,sha256=yEZiCZ6UIyfYUqtfj9Kf2KA9mrjUbmxyzpH9uqVboJs,1378
|
|
4
4
|
skfolio/cluster/__init__.py,sha256=4g-PFB_ld9BhiQ1ZPvvAorpFbRwd_p_DkeRlulDv2Hk,251
|
5
5
|
skfolio/cluster/_hierarchical.py,sha256=16INBe5HB7ALODO3RNI8ZjOYALtMZa3U_7EP1aEIxp8,12819
|
6
6
|
skfolio/datasets/__init__.py,sha256=TKzb3wucwuaBI7V8GSiEIun-oaV0W0Mhl_XJgMjlajU,481
|
7
|
-
skfolio/datasets/_base.py,sha256
|
7
|
+
skfolio/datasets/_base.py,sha256=Al8YzVsiuas3NMMKSjMhE0C0XFkYE-qjONumgoXwFbo,15902
|
8
8
|
skfolio/datasets/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
skfolio/datasets/data/factors_dataset.csv.gz,sha256=brCJlT25DJo40yg1gnUXAakNtvWZZYR_1ksFeN5JcWE,36146
|
10
10
|
skfolio/datasets/data/sp500_dataset.csv.gz,sha256=7iHKwovvsdCnOanOsiGE-ZU5RyaqDP3pohlB0awErA0,426065
|
@@ -14,13 +14,13 @@ skfolio/distance/_base.py,sha256=jBgRk6lZrP1woSI9541fTfxBBkp4WCTLlRPmWcmA3j4,132
|
|
14
14
|
skfolio/distance/_distance.py,sha256=yRyyxMXqKYOiuXdq35aQ2MfS8fp6Xh9BR_ABbUVkaGg,19034
|
15
15
|
skfolio/measures/__init__.py,sha256=9ThQikIAQcfKRLSCoMr-Z5vE2-ThtYe9B-L40b6Ewg0,1631
|
16
16
|
skfolio/measures/_enums.py,sha256=NJcngwg9b2JMMiekwkWU9POfnDvgfUgtYtyV2VSFDVM,8934
|
17
|
-
skfolio/measures/_measures.py,sha256=
|
17
|
+
skfolio/measures/_measures.py,sha256=Z7XHSyM9xfecDgOqm-lJQJhvZxasF018-oFS4QjC4g0,16829
|
18
18
|
skfolio/metrics/__init__.py,sha256=MomHJ5_bgjq4qUwGS2bfhNmG_ld0oQ4wK6y0Yy_Eonc,75
|
19
19
|
skfolio/metrics/_scorer.py,sha256=h1VuZk-zzn4rIChHl9FvM7RxqVT3b-jR1CEB-cr9F2s,4306
|
20
20
|
skfolio/model_selection/__init__.py,sha256=8j9Z5tpbgBScjFbn8ZsCm_6rZO7RkPQ1QIF8BqYMVA8,507
|
21
21
|
skfolio/model_selection/_combinatorial.py,sha256=cS_W_4uA2aUC0eRbqbRnfezRRxUpm2_HGs1S5ea0q6E,19045
|
22
22
|
skfolio/model_selection/_validation.py,sha256=3eFYzPejjDZljc33vRehDuBQTEKCkrj-mZihMVuGA4s,10034
|
23
|
-
skfolio/model_selection/_walk_forward.py,sha256=
|
23
|
+
skfolio/model_selection/_walk_forward.py,sha256=T57HhdFGjG31mAufujHQuRK1uKfAdkiBx9eucQZ-WG0,15043
|
24
24
|
skfolio/moments/__init__.py,sha256=zwxaRO4TLoPj8qrcYSofNyd3tYhbLLcZWQaErzfDdNg,794
|
25
25
|
skfolio/moments/covariance/__init__.py,sha256=maWkl5Uh0RMgfaxQ0yO-c5zhJg51vm1zrtxZrk_p0pg,1068
|
26
26
|
skfolio/moments/covariance/_base.py,sha256=98o4YDFcOZ4X4hRFlrJAwWifULGzisEyRZaxFYW1qeA,3970
|
@@ -30,7 +30,7 @@ skfolio/moments/covariance/_empirical_covariance.py,sha256=_7T1x4p-vdATQvQzQjQBM
|
|
30
30
|
skfolio/moments/covariance/_ew_covariance.py,sha256=jzLE4zSEfLCToNBTIG5CMy1n9EYWo1IHJPifcyLVe1g,3673
|
31
31
|
skfolio/moments/covariance/_gerber_covariance.py,sha256=3wSwZtji2cEr2rzZ6pi2knmuOSzTFpyb_4XJl_S3Yj0,5856
|
32
32
|
skfolio/moments/covariance/_graphical_lasso_cv.py,sha256=_6WQ1sjYJRG8XDq8zb5YIPtDhpb8CmLhLBlfewBvqjM,6539
|
33
|
-
skfolio/moments/covariance/_implied_covariance.py,sha256=
|
33
|
+
skfolio/moments/covariance/_implied_covariance.py,sha256=6DiPWo7WVRA8EFvjYxBLBIrYaeRJWpr8yH5I64Sbbd0,17732
|
34
34
|
skfolio/moments/covariance/_ledoit_wolf.py,sha256=iV92TpAopOAgQwa4zk7NF1rYdXkgm3uXn5ZZpbcMss0,4875
|
35
35
|
skfolio/moments/covariance/_oas.py,sha256=ru8BNz7vQU75ARCuUbtJstmR2fy2fiD9OXLDlztUm5g,3684
|
36
36
|
skfolio/moments/covariance/_shrunk_covariance.py,sha256=OOUahkiSdU3vFOb8i0iHtn8WU0AHl7o9pf8pFkG6Lv4,3095
|
@@ -60,11 +60,11 @@ skfolio/optimization/ensemble/_stacking.py,sha256=ZoICUnc_MwoXDQAR2kewCg-KIezSOI
|
|
60
60
|
skfolio/optimization/naive/__init__.py,sha256=Dkr55R48urC-jfYN007NTbei16N91Na_EDYLVqzhGgQ,147
|
61
61
|
skfolio/optimization/naive/_naive.py,sha256=AhEyYKEUAm-Fjn4p8SHwhp7yE9iF0tRyDZIjKYV4EeU,6390
|
62
62
|
skfolio/population/__init__.py,sha256=rsPPMUv95aTK7vmpPeQwF8NzFuBwk6RDo5g4HNaPzNM,80
|
63
|
-
skfolio/population/_population.py,sha256=
|
63
|
+
skfolio/population/_population.py,sha256=9NKnz_rQYLnauP1Me6tnDwD7lq3MeGnSyCq-sb0fTV0,30424
|
64
64
|
skfolio/portfolio/__init__.py,sha256=YYtcAPmA2zeCxFGTXegg2FXcA7py6CxOX7IMTdYuXl0,586
|
65
|
-
skfolio/portfolio/_base.py,sha256=
|
66
|
-
skfolio/portfolio/_multi_period_portfolio.py,sha256=
|
67
|
-
skfolio/portfolio/_portfolio.py,sha256=
|
65
|
+
skfolio/portfolio/_base.py,sha256=EFLsvHoxZmDvGPOKePr6hQGXU7y7TWsALvzYP9qt0fQ,39588
|
66
|
+
skfolio/portfolio/_multi_period_portfolio.py,sha256=K2JfEwlPD9iGO58lOdk7WUbWuXZDWw2prPT5T7pOdto,24387
|
67
|
+
skfolio/portfolio/_portfolio.py,sha256=gqvCKM6ZVfwZrgixiYdahgbQ1DRNW2LkGHkXOpjleb4,32753
|
68
68
|
skfolio/pre_selection/__init__.py,sha256=VtUtDn-U-Mn_xR2k7yfld0Yb0rPhLakEAiBwUyi-4Z8,189
|
69
69
|
skfolio/pre_selection/_pre_selection.py,sha256=w84T14nKmzkgzbw5CW_AIlci741lXYxKUwB5pBjhTTI,12163
|
70
70
|
skfolio/preprocessing/__init__.py,sha256=15A1bzfPsbfxxXgGP1gstf4R0E_347Wn18z5W5jH-hk,94
|
@@ -83,9 +83,9 @@ skfolio/utils/bootstrap.py,sha256=3zY2kO_GQURKEcQMCasJOSByde9Mt2IAi3KJH0_a4mk,35
|
|
83
83
|
skfolio/utils/equations.py,sha256=w0HsYjA7cS0mHYsI9MpixHLkof3HN26nc14ZfqFrHlE,11047
|
84
84
|
skfolio/utils/sorting.py,sha256=lSjMvH2L-sSj-06B3MlwBrH1rtjCeGEe4hG894W7TE0,3504
|
85
85
|
skfolio/utils/stats.py,sha256=wuOmSt5panMMTw_pFYizLbmrclsE_4PHQfamkzJ5J2s,13937
|
86
|
-
skfolio/utils/tools.py,sha256=
|
87
|
-
skfolio-0.
|
88
|
-
skfolio-0.
|
89
|
-
skfolio-0.
|
90
|
-
skfolio-0.
|
91
|
-
skfolio-0.
|
86
|
+
skfolio/utils/tools.py,sha256=4KrmBR9jOLiI6j0hb27gsPC--OHXo4Sp1xl-6i-k9Tg,20925
|
87
|
+
skfolio-0.4.0.dist-info/LICENSE,sha256=F6Gi-ZJX5BlVzYK8R9NcvAkAsKa7KO29xB1OScbrH6Q,1526
|
88
|
+
skfolio-0.4.0.dist-info/METADATA,sha256=Vh_PqWOdbuuaxurc6k3BL0dZeG7BpKLlis___v8YMv4,19617
|
89
|
+
skfolio-0.4.0.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
|
90
|
+
skfolio-0.4.0.dist-info/top_level.txt,sha256=NXEaoS9Ms7t32gxkb867nV0OKlU0KmssL7IJBVo0fJs,8
|
91
|
+
skfolio-0.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|