Migration Guide#

skfolio follows semantic versioning. The public API remains backward compatible within a major series. Deprecated functionality raises a FutureWarning and is removed in the next major release.

This page documents the changes required to upgrade between major versions.

Preparing for 2.0#

The following deprecated APIs remain available throughout 1.x and will be removed in 2.0. Their replacements are available now.

Hierarchical Optimizer Imports#

Import HRP, HERC, Schur Complementary and NCO from skfolio.optimization or skfolio.optimization.hierarchical:

from skfolio.cluster import HierarchicalClustering
from skfolio.optimization.hierarchical import (
    HierarchicalEqualRiskContribution,
    HierarchicalRiskParity,
    NestedClustersOptimization,
    SchurComplementary,
)

Imports from skfolio.optimization.cluster and skfolio.optimization.cluster.hierarchical raise a FutureWarning and return the same estimator classes. The skfolio.cluster module for clustering estimators is unchanged.

HRP and Schur Ordering#

Configure hierarchical clustering through HierarchicalSeriation on HRP and Schur Complementary.

Before:

model = HierarchicalRiskParity(
    hierarchical_clustering_estimator=HierarchicalClustering()
)

After:

from skfolio.cluster import HierarchicalClustering
from skfolio.seriation import HierarchicalSeriation

model = HierarchicalRiskParity(
    seriation_estimator=HierarchicalSeriation(
        hierarchical_clustering_estimator=HierarchicalClustering()
    )
)

The old parameter warns during fit or the first partial_fit of a learning run. Supplying both estimators raises an error. The default ordering is unchanged.

After fitting, access the clustering estimator through model.seriation_estimator_.hierarchical_clustering_estimator_. The old model.hierarchical_clustering_estimator_ attribute raises a FutureWarning. This alias is only available when the fitted seriator is hierarchical.

HERC’s hierarchical_clustering_estimator and NCO’s clustering_estimator remain supported.

Custom Hierarchical Optimizers#

BaseHierarchicalOptimization is deprecated. Existing custom subclasses remain supported throughout 1.x.

HRP, HERC and Schur Complementary no longer inherit from this base. isinstance and issubclass checks against BaseHierarchicalOptimization now return False for these estimators. Use BaseOptimization to recognize portfolio optimizers generally, or a tuple of concrete optimizer classes to recognize a specific family.

For new custom optimizers, inherit from BaseOptimization and implement fit to set weights_. When migrating an existing subclass, provide any risk calculations and bound conversion previously inherited through _risk, _unitary_risks and _convert_weights_bounds. The private seriation base and risk mixin are implementation details, not supported replacements for the public base.

Migrating to 1.0#

Version 1.0 introduces the stable public API. The parameters and aliases deprecated during the 0.x series are removed in this release.

Exponentially Weighted Moments#

EWMu and EWCovariance no longer accept alpha. Use half_life, the number of observations for a weight to decay to 50%.

Before:

from skfolio.moments import EWCovariance, EWMu

EWMu(alpha=0.2)
EWCovariance(alpha=0.2)

After:

EWMu(half_life=3.11)
EWCovariance(half_life=3.11)

The half-life equivalent of a given alpha is

\[\text{half-life} = \frac{-1}{\log_2(1 - \alpha)}\]

For example, alpha=0.2 corresponds to a half_life of approximately \(3.11\) and alpha=0.02 to \(34.31\). The decay factor is \(\lambda = 2^{-1/\text{half-life}}\), computed by half_life_to_decay_factor.

Passing alpha raises a TypeError.

Walk-Forward Cross-Validation#

WalkForward no longer accepts expend_train. Use expand_train, which has identical behavior.

Before:

from skfolio.model_selection import WalkForward

WalkForward(test_size=60, train_size=252, expend_train=True)

After:

WalkForward(test_size=60, train_size=252, expand_train=True)

Factor Models#

The FactorModel prior estimator is replaced by TimeSeriesFactorModel, and factors is now a keyword-only argument of fit.

Before:

from skfolio.optimization import MeanRisk
from skfolio.prior import FactorModel

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

After:

from skfolio.optimization import MeanRisk
from skfolio.prior import TimeSeriesFactorModel
from skfolio.datasets import load_sp500_dataset, load_factors_dataset
from skfolio.preprocessing import prices_to_returns

X, factors = prices_to_returns(load_sp500_dataset(), load_factors_dataset())
X_train, factors_train = X.iloc[:252], factors.iloc[:252]

model = MeanRisk(prior_estimator=TimeSeriesFactorModel())
model.fit(X_train, factors=factors_train)

Warning

FactorModel now refers to a different object: the fitted factor model container exposed on factor_model, holding the loading matrix, the factor and idiosyncratic moments, and the realized factor returns. The import therefore still resolves, and estimator arguments passed to FactorModel raise a TypeError for unexpected keyword arguments rather than an ImportError.

CharacteristicsFactorModel provides a cross-sectional alternative, fitted from point-in-time asset characteristics rather than factor return time series. See Factor Models.

Uncertainty Sets#

UncertaintySet now describes a general norm-ball rather than an ellipsoid, which allows box and diamond sets to use the same representation. The ellipsoid is the \(p = 2\) case.

The field names changed as follows:

Before

After

Description

k

radius

Size \(\kappa\) of the normalized uncertainty ball.

sigma

geometry

Linear map \(L\) with \(S = L L^{T}\) for an ellipsoid with shape matrix \(S\). May be low-rank.

not applicable

norm

Norm \(p\) selecting the shape, defaulting to \(2\) for an ellipsoid.

This only affects code that constructs an UncertaintySet directly or reads the fitted uncertainty_set_ attribute. Passing an uncertainty set estimator to MeanRisk is unchanged.

Two factor-model estimators are added: OrthogonalMuUncertaintySet and OrthogonalCovarianceUncertaintySet. See Uncertainty Set.

Scheduled for Removal in 2.0#

The following remain available throughout 1.x and raise a FutureWarning: