Online Learning#

skfolio provides dedicated online utilities for estimators that support partial_fit. By updating a single stateful estimator incrementally rather than refitting from scratch at every split, online evaluation is significantly faster than standard cross-validation. These utilities cover stateful walk-forward evaluation, online covariance forecast diagnostics, and online hyper-parameter tuning.

Examples of supported estimators include EWMu, EWCovariance, RegimeAdjustedEWCovariance, EmpiricalPrior and portfolio optimizers such as MeanRisk, HierarchicalRiskParity and SchurComplementary when they embed incremental moment estimators through a prior estimator.

For HRP and Schur distance and seriation settings, see Seriation for HRP and Schur. The online Schur example illustrates late listings, delistings, holidays and asset warm-up.

Online learning is also where native NaN-aware estimators are especially useful: they can update from available observations while preserving estimator state. Pipeline based pre-selection and imputation are not currently available in skfolio online learning workflows. See Missing Data and Changing Universes for details and Fixed Asset Schema in Online Learning for adding assets during an online learning run.

How Online Evaluation Works#

The online utilities all follow the same stateful evaluation pattern:

  1. Clone the estimator once, starting from a clean unfitted state.

  2. Initialize it on the first warmup_size observations with partial_fit.

  3. Evaluate on the next test window out-of-sample, with optional purging between the data seen by the estimator and the test window.

  4. Update the same estimator with the newly observed data.

  5. Repeat until the end of the sample.

This differs from standard cross-validation, where each split fits an independent estimator clone. In the online setting, the estimator state is carried forward through time.

Updates and Failure Handling#

For portfolio optimizers, each partial_fit call first updates the prior and other estimators from new observations, then computes portfolio weights. Each call builds on the estimates from previous calls. Calling fit starts estimation again from the supplied history.

Online updates assume that estimation parameters, such as the half_life of an EW covariance estimator, remain unchanged. Changing these parameters requires a new fit on the desired history, because the existing estimates were computed with the previous settings.

Optimization Failures#

Once the prior and other estimators have been updated, the optimizer computes portfolio weights. This step can fail, for example when a convex solver does not converge or portfolio constraints become infeasible at a particular rebalancing. Such failures raise OptimizationError and are handled according to fallback and raise_on_failure. Other examples include undefined risk splits in HRP and a failed numerical repair of Schur’s augmented covariance blocks.

With fallback=None (the default):

  • If raise_on_failure=True (the default), the optimization error is raised. Further updates or predictions require a fresh estimator or a new successful fit, as illustrated below.

  • If raise_on_failure=False, the estimator emits a warning and sets weights_ to None. A subsequent predict returns a FailedPortfolio. The same model can continue through subsequent partial_fit calls with new observations.

With fallback="previous_weights", the model uses the allocation supplied in previous_weights if optimization fails. This allows the last valid allocation to be reused with either raise_on_failure=True or raise_on_failure=False.

Assets outside the current investable universe receive zero weight. The remaining weights stay unchanged, without rescaling or checking them against the original optimization constraints, so part of the portfolio may remain in cash. In a manual update loop, the caller supplies the holdings to retain through previous_weights before each update.

If the fallback also fails, for example because previous_weights was not supplied, raise_on_failure=True raises the fallback error. With raise_on_failure=False, the estimator emits a warning and sets weights_ to None. Errors detected earlier during input validation are always raised, as described under Other Errors below.

After an optimization failure handled by raise_on_failure=False or a successful fallback, the same model can continue with the next batch. The prior and other estimators have already used the current observations, so the next partial_fit receives only new observations. For example, if optimization fails after updating the prior with Monday’s returns, the next update needs to contains Tuesday’s returns.

With raise_on_failure=True, an optimization failure is raised when fallback=None or the previous-weights fallback also fails. Some fitted attributes may already have changed, while weights_ may still contain an earlier allocation. The model therefore needs to be fitted again before further updates or predictions. One way to restart is to create a fresh estimator and train it on the desired history.

Other Errors#

Errors caused by invalid parameters, malformed inputs, or failed updates of the prior or other estimators are always raised by partial_fit, regardless of raise_on_failure and fallback. These errors can leave some estimates updated and others unchanged, so further updates or predictions require a fresh estimator or a new successful fit.

Optimization requires at least one investable asset. If none are investable, partial_fit raises ValueError without attempting fallback. The prior therefore needs enough warm-up history to estimate returns and risk for at least one asset in the active universe before allocation can begin.

Batch Fitting#

During fit, fallbacks can be attempted after any fitting error, including errors in the parameters or failures while fitting the prior. Each fallback estimator is fitted independently on the supplied history. During partial_fit, only fallback=None and fallback="previous_weights" are supported, because a fallback estimator has not accumulated the primary model’s online history.

A batch fallback can produce valid weights even if the primary estimator did not finish fitting. The same incomplete state is possible when a batch error is suppressed with raise_on_failure=False. In both cases, subsequent online learning requires a fresh estimator or a successful fit of the primary model on the desired history. See Failure Handling for exception types and batch diagnostics.

Non-Predictor Estimators Versus Portfolio Optimizers#

The online API distinguishes between non-predictor estimators and portfolio optimizers.

  • Non-predictor estimators such as covariance, expected-return, and prior estimators do not implement predict. Their scores are computed from the fitted estimator and the current test window using callables such as scorer(estimator, X_test). When using make_scorer, the appropriate form is make_scorer(..., response_method=None).

  • Portfolio optimization estimators such as MeanRisk are evaluated by collecting the out-of-sample predictions into a MultiPeriodPortfolio. Measures are then computed on that aggregate portfolio. In that case, scoring uses BaseMeasure enums directly rather than make_scorer.

Accordingly, online_predict is restricted to portfolio optimizers, while online_score and OnlineGridSearch / OnlineRandomizedSearch accept both categories.

Online Versus Standard Cross-Validation#

The standard cross_val_predict and its online counterpart online_predict are both designed exclusively for portfolio optimization estimators. The key differences are:

  • Fitting strategy: standard cross-validation clones and refits the estimator from scratch at every fold, while online evaluation maintains a single stateful estimator updated incrementally via partial_fit, which is significantly faster.

  • Scoring methodology: standard cross-validation scores each test fold independently and averages the results, which can be unreliable when test folds are short (e.g. the Sharpe ratio is undefined on a single observation). Online evaluation instead collects all out-of-sample predictions into a single MultiPeriodPortfolio and computes the metric on the full out-of-sample path, which is generally preferred for short rebalancing horizons.

online_score extends online evaluation to both portfolio optimizers and non-predictor estimators (covariance, expected-return, and prior estimators). For non-predictor estimators, scores are computed per test window and averaged by default.

Because the scoring methodology differs for portfolio optimizers, the online utilities are complementary to the existing cross-validation tools rather than replacements.

Online Covariance Forecast Evaluation#

online_covariance_forecast_evaluation evaluates the quality of covariance forecasts out-of-sample. It is intended for covariance estimators rather than portfolio optimizers, which should instead be evaluated with online_predict or online_score.

At each step, the covariance forecast produced after partial_fit is compared to the realized returns over the next test window. The resulting CovarianceForecastEvaluation provides diagnostics such as:

  • Mahalanobis calibration ratio for the full covariance structure across all eigenvalue directions.

  • Diagonal calibration ratio for asset-level variance calibration.

  • Portfolio standardized returns and the associated bias statistic for calibration along one portfolio direction by default, or multiple portfolio directions when explicit test portfolios are provided.

  • Portfolio QLIKE for portfolio variance forecast quality along one or more portfolio directions.

When portfolio_weights=None, the portfolio diagnostics use a single dynamic inverse-volatility portfolio direction by default. Passing explicit portfolio weights extends the evaluation to multiple selected traded directions.

See the example Online Covariance Forecast Evaluation for the complete workflow.

Online Hyper-Parameter Tuning#

OnlineGridSearch and OnlineRandomizedSearch extend the online workflow to hyper-parameter selection.

Conceptually, this is the online counterpart of combining GridSearchCV or RandomizedSearchCV with WalkForward using expand_train=True. The key difference is that online search updates each candidate incrementally via partial_fit along one sequential path instead of refitting it from scratch at every split.

Each candidate parameter configuration is evaluated on one full online walk-forward path. When refit=True, best_estimator_ exposes the selected fitted candidate without an additional fit after model selection because it has already been updated through the full sample during evaluation.

For non-predictor estimators, online tuning typically uses callable scorers such as QLIKE or calibration losses, typically wrapped with make_scorer using response_method=None. For multi-metric searches, refit should be set explicitly to the name of the metric used to select the best candidate.

See the example Online Covariance Hyperparameter Tuning for covariance tuning with both OnlineGridSearch and OnlineRandomizedSearch.

Online Evaluation of Portfolio Optimization#

For portfolio optimizers, the main entry points are online_predict and online_score.

This is useful when a portfolio estimator embeds incremental moment estimators such as EWMu and RegimeAdjustedEWCovariance.

During online portfolio evaluation, online_predict records a suppressed optimization failure as a FailedPortfolio and continues with the next window. Raised errors interrupt evaluation. See Updates and Failure Handling for data consumption, fallback, and restart rules.

Pass portfolio_params={"weight_drift": True, "compounded": True} to online_predict to evaluate the path with drifted weights and compounded returns. The portfolio_params of online_predict follow the same rules as those of cross_val_predict: the parameters shared by Portfolio and MultiPeriodPortfolio are applied to the returned MultiPeriodPortfolio and to each Portfolio it contains, take precedence over the optimizer’s portfolio_params and are inherited from it when omitted. weight_drift applies to each Portfolio of the path. See Cross-Validation Prediction for the complete rules.

When the estimator needs previous weights, the ending_weights of the last successful portfolio become the previous_weights of the next rebalancing. They equal its target weights with weight_drift=False and its weights after the final observation with weight_drift=True.

online_score, OnlineGridSearch and OnlineRandomizedSearch accept the same portfolio_params when evaluating a portfolio optimizer. Because they score the resulting MultiPeriodPortfolio, these parameters can change the scores and the ranking of the parameter sets. When refitting is enabled, weight_drift is retained in best_estimator_ because prediction requires it. The other parameters are not.

To use those previous holdings instead of producing a failed rebalance after an optimization failure, configure fallback="previous_weights".

See the example Online Evaluation of Portfolio Optimization for an end-to-end online evaluation of MeanRisk.