<a id="skfolio-optimization-stackingoptimization"></a>

# skfolio.optimization.StackingOptimization

<a id="skfolio.optimization.StackingOptimization"></a>

### *class* skfolio.optimization.StackingOptimization(estimators, final_estimator=None, cv=None, quantile=0.5, quantile_measure=Sharpe Ratio, n_jobs=None, verbose=0, portfolio_params=None, fallback=None, previous_weights=None, raise_on_failure=True)

Stack of optimizations with a final optimization.

Stacking Optimization is an ensemble method that consists of stacking the output of
individual portfolio optimizations with a final portfolio optimization.

The weights are the dot-product of individual optimization weights with the final
optimization weights.

Stacking uses the strength of each individual portfolio optimization by
using their output as input of a final portfolio optimization.

To avoid data leakage, out-of-sample estimates are used to fit the outer
optimization.

Note that `estimators_` are fitted on the full `X` while `final_estimator_`
is trained using cross-validated predictions of the base estimators using
`cross_val_predict`.

* **Parameters:**
  **estimators** *list[tuple[str, BaseOptimization]]*
  : [Optimization estimators](https://skfolio.org/user_guide/optimization.html.md#optimization) which will be stacked together.
    Each element of the list is defined as a tuple of string (i.e. name) and an
    [optimization estimator](https://skfolio.org/user_guide/optimization.html.md#optimization).

  **final_estimator** *BaseOptimization, optional*
  : A final [optimization estimator](https://skfolio.org/user_guide/optimization.html.md#optimization) which will be used to
    combine the base estimators.
    The default (`None`) is to use [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk).

  **cv** *BaseCrossValidator | BaseCombinatorialCV | int | “prefit” | “ignore”, optional*
  : Determines the cross-validation splitting strategy used in `cross_val_predict`
    to train the `final_estimator`.
    The default (`None`) is to use the 5-fold cross validation `KFold()`.
    Possible inputs for `cv` are:
    > * “ignore”: no cross-validation is used (note that it will likely lead to data leakage with a high risk of overfitting)
    > * integer, to specify the number of folds in a `KFold`
    > * An object to be used as a cross-validation generator
    > * An iterable yielding train, test splits
    > * “prefit” to assume the `estimators` are prefit, and skip cross validation
    > * A [`CombinatorialPurgedCV`](https://skfolio.org/generated/skfolio.model_selection.CombinatorialPurgedCV.html.md#skfolio.model_selection.CombinatorialPurgedCV)
    <br/>
    If a `CombinatorialCV` cross-validator is used, each cluster out-of-sample
    outputs becomes a collection of multiple paths instead of one single path. The
    selected out-of-sample path among this collection of paths is chosen according
    to the `quantile` and `quantile_measure` parameters.
    <br/>
    If “prefit” is passed, it is assumed that all `estimators` have been fitted
    already. The `final_estimator_` is trained on the `estimators` predictions on
    the full training set and are **not** cross validated predictions.
    Please note that if the models have been trained on the same data to train the
    stacking model, there is a very high risk of overfitting.

  **n_jobs** *int, optional*
  : The number of jobs to run in parallel for `fit` of all `estimators`.
    The value `-1` means using all processors.
    The default (`None`) means 1 unless in a `joblib.parallel_backend` context.

  **quantile** *float, default=0.5*
  : Quantile for a given measure (`quantile_measure`) of the out-of-sample
    inner-estimator paths when the `cv` parameter is a
    [`CombinatorialPurgedCV`](https://skfolio.org/generated/skfolio.model_selection.CombinatorialPurgedCV.html.md#skfolio.model_selection.CombinatorialPurgedCV) cross-validator.
    The default value is `0.5` corresponding to the path with the median measure.
    (see `cv`)

  **quantile_measure** *PerfMeasure or RatioMeasure or RiskMeasure or ExtraRiskMeasure, default=RatioMeasure.SHARPE_RATIO*
  : Measure used for the quantile path selection (see `quantile` and `cv`).
    The default is `RatioMeasure.SHARPE_RATIO`.

  **verbose** *int, default=0*
  : The verbosity level. The default value is `0`.

  **portfolio_params** *dict, optional*
  : Portfolio parameters forwarded to the resulting `Portfolio` in `predict`.
    If not provided and if available on the estimator, the following
    attributes are propagated to the portfolio by default: `name`,
    `transaction_costs`, `management_fees`, `previous_weights` and `risk_free_rate`.

  **fallback** *BaseOptimization | “previous_weights” | list[BaseOptimization | “previous_weights”], optional*
  : Fallback estimator or a list of estimators to try, in order, when the primary
    optimization raises during `fit`. Alternatively, use `"previous_weights"`
    (alone or in a list) to fall back to the estimator’s `previous_weights`.
    When a fallback succeeds, its fitted `weights_` are copied back to the primary
    estimator so that `fit` still returns the original instance. For traceability,
    `fallback_` stores the successful estimator (or the string `"previous_weights"`)
    and `fallback_chain_` stores each attempt with the associated outcome.

  **previous_weights** *float | dict[str, float] | array-like of shape (n_assets,), optional*
  : When `fallback="previous_weights"`, failures will fall back to these weights
    if provided.

  **raise_on_failure** *bool, default=True*
  : Controls error handling when fitting fails.
    If True, any failure during `fit` is raised immediately, no `weights_` are
    set and subsequent calls to `predict` will raise a `NotFittedError`.
    If False, errors are not raised; instead, a warning is emitted, `weights_`
    is set to `None` and subsequent calls to `predict` will return a
    `FailedPortfolio`. When fallbacks are specified, this behavior applies only
    after all fallbacks have been exhausted.
* **Attributes:**
  **weights_** *ndarray of shape (n_assets,)*
  : Weights of the assets.

  **estimators_** *list[BaseOptimization]*
  : The elements of the `estimators` parameter, having been fitted on the
    training data. When `cv="prefit"`, `estimators_`
    is set to `estimators` and is not fitted again.

  **named_estimators_** *dict[str, BaseOptimization]*
  : Attribute to access any fitted sub-estimators by name.

  **final_estimator_** *BaseOptimization*
  : The fitted `final_estimator`.

  **n_features_in_** *int*
  : Number of assets seen during `fit`.

  **feature_names_in_** *ndarray of shape (`n_features_in_`,)*
  : Names of assets seen during `fit`. Defined only when `X`
    has assets names that are all strings.

  **fallback_** *BaseOptimization | “previous_weights” | None*
  : The fallback estimator instance, or the string `"previous_weights"`, that
    produced the final result. `None` if no fallback was used.

  **fallback_chain_** *list[tuple[str, str]] | None*
  : Sequence describing the optimization fallback attempts. Each element is a
    pair `(estimator_repr, outcome)` where `estimator_repr` is the string
    representation of the primary estimator or a fallback (e.g. `"EqualWeighted()"`,
    `"previous_weights"`), and `outcome` is `"success"` if that step produced
    a valid solution, otherwise the stringified error message. For successful
    fits without any fallback, this is `None`.

  **error_** *str | list[str] | None*
  : Captured error message(s) when `fit` fails. For multi-portfolio outputs
    (`weights_` is 2D), this is a list aligned with portfolios.

### Methods

| [`fit`](#skfolio.optimization.StackingOptimization.fit)(X[, y])            | Fit the Stacking Optimization estimator.                                                                                        |
|-------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| [`fit_predict`](#skfolio.optimization.StackingOptimization.fit_predict)(X)         | Perform `fit` on `X` and returns the predicted `Portfolio` or `Population` of `Portfolio` on `X` based on the fitted `weights`. |
| [`get_metadata_routing`](#skfolio.optimization.StackingOptimization.get_metadata_routing)() | Get metadata routing of this object.                                                                                            |
| [`get_params`](#skfolio.optimization.StackingOptimization.get_params)([deep])     | Get the parameters of an estimator from the ensemble.                                                                           |
| [`predict`](#skfolio.optimization.StackingOptimization.predict)(X)             | Predict the `Portfolio` or a `Population` of portfolios on `X`.                                                                 |
| [`score`](#skfolio.optimization.StackingOptimization.score)(X[, y])          | Prediction score using the Sharpe Ratio.                                                                                        |
| [`set_params`](#skfolio.optimization.StackingOptimization.set_params)(\*\*params) | Set the parameters of an estimator from the ensemble.                                                                           |

### Notes

All estimators should specify all parameters as explicit keyword arguments in
`__init__` (no `*args` or `**kwargs`), following scikit-learn conventions.

<a id="skfolio.optimization.StackingOptimization.fit"></a>

#### fit(X, y=None, \*\*fit_params)

Fit the Stacking Optimization estimator.

* **Parameters:**
  **X** *array-like of shape (n_observations, n_assets)*
  : Price returns of the assets.

  **y** *array-like of shape (n_observations, n_targets), optional*
  : Price returns of factors or a target benchmark.
    The default is `None`.

  **\*\*fit_params** *dict*
  : Parameters to pass to the underlying estimators.
    Only available if `enable_metadata_routing=True`, which can be
    set by using `sklearn.set_config(enable_metadata_routing=True)`.
    See [Metadata Routing User Guide](https://skfolio.org/user_guide/metadata_routing.html.md#metadata-routing) for
    more details.
* **Returns:**
  **self** *StackingOptimization*
  : Fitted estimator.

<a id="skfolio.optimization.StackingOptimization.fit_predict"></a>

#### fit_predict(X)

Perform `fit` on `X` and returns the predicted `Portfolio` or
`Population` of `Portfolio` on `X` based on the fitted `weights`.
For factor models, use `fit(X, factors=...)` then `predict(X)` separately.

If fitting fails and `raise_on_failure=False`, this returns a
`FailedPortfolio`.

* **Parameters:**
  **X** *array-like of shape (n_observations, n_assets)*
  : Price returns of the assets.
* **Returns:**
  Portfolio | Population
  : The predicted `Portfolio` or `Population` based on the fitted `weights`.

<a id="skfolio.optimization.StackingOptimization.get_metadata_routing"></a>

#### get_metadata_routing()

Get metadata routing of this object.

Please check [User Guide](https://skfolio.org/user_guide/metadata_routing.html.md#metadata-routing) on how the routing
mechanism works.

* **Returns:**
  **routing** *MetadataRequest*
  : A `MetadataRequest` encapsulating
    routing information.

<a id="skfolio.optimization.StackingOptimization.get_params"></a>

#### get_params(deep=True)

Get the parameters of an estimator from the ensemble.

Returns the parameters given in the constructor as well as the
estimators contained within the `estimators` parameter.

* **Parameters:**
  **deep** *bool, default=True*
  : Setting it to True gets the various estimators and the parameters
    of the estimators as well.
* **Returns:**
  **params** *dict*
  : Parameter and estimator names mapped to their values or parameter
    names mapped to their values.

<a id="skfolio.optimization.StackingOptimization.named_estimators"></a>

#### *property* named_estimators

Dictionary to access any fitted sub-estimators by name.

* **Returns:**
  `Bunch`

<a id="skfolio.optimization.StackingOptimization.needs_previous_weights"></a>

#### *property* needs_previous_weights

Whether `previous_weights` must be propagated between folds/rebalances.

Used by `cross_val_predict` and `online_predict` to decide whether to run
sequentially and pass the weights from the previous rebalancing to the next.
This is `True` when `portfolio_params` sets `weight_drift=True`, or when
transaction costs, a maximum turnover, or a fallback depending on
`previous_weights` are present.

<a id="skfolio.optimization.StackingOptimization.predict"></a>

#### predict(X)

Predict the `Portfolio` or a `Population` of portfolios on `X`.

Optimization estimators can return a 1D or a 2D array of `weights`.
For a 1D array, the prediction is a single `Portfolio`.
For a 2D array, the prediction is a `Population` of `Portfolio`.

If `name` is not provided in the portfolio parameters, the estimator
class name is used.

* **Parameters:**
  **X** *array-like of shape (n_observations, n_assets) | ReturnDistribution*
  : Asset returns or a `ReturnDistribution` carrying returns and optional
    sample weights.
* **Returns:**
  Portfolio | Population
  : The predicted `Portfolio` or `Population` based on the fitted `weights`.

<a id="skfolio.optimization.StackingOptimization.score"></a>

#### score(X, y=None)

Prediction score using the Sharpe Ratio.
If the prediction is a single `Portfolio`, the score is its Sharpe Ratio.
If the prediction is a `Population`, the score is the mean Sharpe Ratio
across portfolios.

* **Parameters:**
  **X** *array-like of shape (n_observations, n_assets)*
  : Price returns of the assets.

  **y** *Ignored*
  : Not used, present here for API consistency by convention.
* **Returns:**
  **score** *float*
  : The Sharpe Ratio of the portfolio if the prediction is a single `Portfolio`
    or the mean of all the portfolio Sharpe Ratios if the prediction is a
    `Population` of `Portfolio`.

<a id="skfolio.optimization.StackingOptimization.set_params"></a>

#### set_params(\*\*params)

Set the parameters of an estimator from the ensemble.

Valid parameter keys can be listed with `get_params()`. Note that you
can directly set the parameters of the estimators contained in
`estimators`.

* **Parameters:**
  **\*\*params** *keyword arguments*
  : Specific parameters using e.g.
    `set_params(parameter_name=new_value)`. In addition, to setting the
    parameters of the estimator, the individual estimator of the
    estimators can also be set, or can be removed by setting them to
    ‘drop’.
* **Returns:**
  **self** *object*
  : Estimator instance.

