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

# skfolio.optimization.BenchmarkTracker

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

### *class* skfolio.optimization.BenchmarkTracker(risk_measure=Standard Deviation, prior_estimator=None, min_weights=0.0, max_weights=1.0, max_short=None, max_long=None, cardinality=None, group_cardinalities=None, threshold_long=None, threshold_short=None, transaction_costs=0.0, management_fees=0.0, previous_weights=None, groups=None, linear_constraints=None, left_inequality=None, right_inequality=None, l1_coef=0.0, l2_coef=0.0, risk_free_rate=0.0, solver='CLARABEL', solver_params=None, scale_objective=None, scale_constraints=None, save_problem=False, add_objective=None, add_constraints=None, portfolio_params=None, fallback=None, raise_on_failure=True)

Benchmark Tracker Optimization estimator.

Optimize a portfolio to track a benchmark by minimizing the risk of
benchmark-relative (excess) returns.

This estimator minimizes the tracking risk between portfolio returns and a
benchmark’s returns by optimizing directly on excess (active) returns, defined as
portfolio returns minus benchmark returns.

Tracking risk can be defined using any of the available risk measures. Typical
choices include standard deviation (tracking-error volatility), semi-deviation and
mean absolute deviation.

#### SEE ALSO
[Tracking Error Optimization](https://skfolio.org/user_guide/optimization.html.md#tracking-error-optimization)

* **Parameters:**
  **risk_measure** *RiskMeasure, default=RiskMeasure.STANDARD_DEVIATION*
  : [`RiskMeasure`](https://skfolio.org/generated/skfolio.measures.RiskMeasure.html.md#skfolio.measures.RiskMeasure) to minimize on excess returns.
    The default is `RiskMeasure.STANDARD_DEVIATION`.

  **prior_estimator** *BasePrior, optional*
  : [Prior estimator](https://skfolio.org/user_guide/prior.html.md#prior).
    The prior estimator is used to estimate the [`ReturnDistribution`](https://skfolio.org/generated/skfolio.prior.ReturnDistribution.html.md#skfolio.prior.ReturnDistribution)
    of excess returns (portfolio returns - benchmark returns).
    The default (`None`) is to use [`EmpiricalPrior`](https://skfolio.org/generated/skfolio.prior.EmpiricalPrior.html.md#skfolio.prior.EmpiricalPrior).

  **min_weights** *float | dict[str, float] | array-like of shape (n_assets, ) | None, default=0.0*
  : Minimum assets weights (weights lower bounds).
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **max_weights** *float | dict[str, float] | array-like of shape (n_assets, ) | None, default=1.0*
  : Maximum assets weights (weights upper bounds).
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **max_short** *float, optional*
  : Maximum short position.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **max_long** *float, optional*
  : Maximum long position.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **cardinality** *int, optional*
  : Cardinality constraint to limit the number of invested assets.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **group_cardinalities** *dict[str, int], optional*
  : Cardinality constraints for specific groups of assets.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **threshold_long** *float | dict[str, float] | array-like of shape (n_assets, ), optional*
  : Minimum weight threshold for long positions.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **threshold_short** *float | dict[str, float] | array-like of shape (n_assets, ), optional*
  : Maximum weight threshold for short positions.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **transaction_costs** *float | dict[str, float] | array-like of shape (n_assets, ), default=0.0*
  : Transaction costs of the assets.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **management_fees** *float | dict[str, float] | array-like of shape (n_assets, ), default=0.0*
  : Management fees of the assets.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **previous_weights** *float | dict[str, float] | array-like of shape (n_assets, ), optional*
  : Previous weights of the assets.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **l1_coef** *float, default=0.0*
  : L1 regularization coefficient.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **l2_coef** *float, default=0.0*
  : L2 regularization coefficient.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **groups** *dict[str, list[str]] or array-like of shape (n_groups, n_assets), optional*
  : The assets groups.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **linear_constraints** *array-like of shape (n_constraints,), optional*
  : Linear constraints.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **left_inequality** *array-like of shape (n_constraints, n_assets), optional*
  : Left inequality matrix.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **right_inequality** *array-like of shape (n_constraints, ), optional*
  : Right inequality vector.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **risk_free_rate** *float, default=0.0*
  : Risk-free rate, expressed in the same frequency as the returns `X`.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **solver** *str, default=”CLARABEL”*
  : The solver to use.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **solver_params** *dict, optional*
  : Solver parameters.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **scale_objective** *float, optional*
  : Scale each objective element by this value.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **scale_constraints** *float, optional*
  : Scale each constraint element by this value.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **save_problem** *bool, default=False*
  : If this is set to True, the CVXPY Problem is saved in `problem_`.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **add_objective** *Callable[[cp.Variable], cp.Expression], optional*
  : Add a custom objective to the existing objective expression.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **add_constraints** *Callable[[cp.Variable], cp.Expression | list[cp.Expression]], optional*
  : Add a custom constraint or a list of constraints to the existing constraints.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **portfolio_params** *dict, optional*
  : Portfolio parameters.
    See [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for details.

  **fallback** *BaseOptimization | “previous_weights” | list[BaseOptimization | “previous_weights”], optional*
  : Fallback estimator, `"previous_weights"`, or a list of either. Fallback
    estimators are fitted on the original asset returns and benchmark returns. Use a
    `BenchmarkTracker` fallback to keep a benchmark-relative objective. With
    `partial_fit`, only None or `"previous_weights"` is supported because fallback
    estimators have not accumulated the primary model’s online history. See
    [Fallbacks](https://skfolio.org/user_guide/optimization.html.md#optimization-fallbacks) and [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) for
    details.

  **raise_on_failure** *bool, default=True*
  : Controls error handling when fitting fails and no fallback succeeds. If True,
    the estimator raises the final error. If False, the estimator emits a warning
    and sets `weights_` to None, so subsequent calls to `predict` return a
    [`FailedPortfolio`](https://skfolio.org/generated/skfolio.portfolio.FailedPortfolio.html.md#skfolio.portfolio.FailedPortfolio). During `fit`, `raise_on_failure`
    applies to any fitting error, including errors raised by the prior estimator.
    During `partial_fit`, `raise_on_failure` applies only to optimization failures
    after learning completes. Input validation failures and errors from the prior or
    other learning estimators are always raised. See
    [Failure Handling](https://skfolio.org/user_guide/optimization.html.md#optimization-failure-handling) for batch recovery and
    [Updates and Failure Handling](https://skfolio.org/user_guide/online_learning.html.md#online-failure-handling) for online continuation and restart rules.
* **Attributes:**
  **weights_** *ndarray of shape (n_assets,)*
  : Weights of the assets.

  **problem_values_** *dict[str, float]*
  : Expression values retrieved from the CVXPY problem.

  **prior_estimator_** *BasePrior*
  : Fitted `prior_estimator` on excess returns.

  **problem_: cvxpy.Problem**
  : CVXPY problem used for the optimization.
    Only when `save_problem` is set to `True`.

  **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`.

  **fallback_** *BaseOptimization | “previous_weights” | None*
  : The fallback estimator instance that produced the final result.

  **fallback_chain_** *list[tuple[str, str]] | None*
  : Sequence describing the optimization fallback attempts.

  **error_** *str | None*
  : The recorded error message. This is None after a successful allocation or
    fallback.

### Methods

| [`fit`](#skfolio.optimization.BenchmarkTracker.fit)(X, y, \*\*fit_params)         | Fit the Benchmark Tracker estimator.                                                                                            |
|------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|
| [`fit_predict`](#skfolio.optimization.BenchmarkTracker.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.BenchmarkTracker.get_metadata_routing)()            | Get metadata routing for this estimator.                                                                                        |
| [`get_params`](#skfolio.optimization.BenchmarkTracker.get_params)([deep])                | Get parameters for this estimator.                                                                                              |
| [`partial_fit`](#skfolio.optimization.BenchmarkTracker.partial_fit)(X, y, \*\*fit_params) | Incrementally fit the Benchmark Tracker estimator.                                                                              |
| [`predict`](#skfolio.optimization.BenchmarkTracker.predict)(X)                        | Predict the `Portfolio` or a `Population` of portfolios on `X`.                                                                 |
| [`score`](#skfolio.optimization.BenchmarkTracker.score)(X[, y])                     | Prediction score using the Sharpe Ratio.                                                                                        |
| [`set_params`](#skfolio.optimization.BenchmarkTracker.set_params)(\*\*params)            | Set the parameters of this estimator.                                                                                           |

### Notes

It is implemented as a special case of [`MeanRisk`](https://skfolio.org/generated/skfolio.optimization.MeanRisk.html.md#skfolio.optimization.MeanRisk) where
the input asset returns `X` and benchmark returns `y` are first transformed to
excess returns `X_excess = X - y` before optimization. A full-investment constraint
(`budget = 1.0`) is always enforced because:

$$
r_t^{excess}(w) = \sum_i w_i(r_{t,i} - r_{b,t}) = r_{p,t} - (\sum_i w_i)r_{b,t}

$$

where $r_{p,t}$ is the portfolio return and $r_{b,t}$ the benchmark
return, coincides with the active (benchmark-relative) return

$$
r_{p,t} - r_{b,t}

$$

when $\sum_i w_i = 1$

### References

* <a id='re9e9e2e23476-1'>**[1]**</a> “Portfolio Optimization: Theory and Application”, Chapter 13, Daniel P. Palomar (2025)

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

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

Fit the Benchmark Tracker estimator.

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

  **y** *array-like of shape (n_observations, 1) or (n_observations,)*
  : Price returns of the benchmark.

  **\*\*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** *BenchmarkTracker*
  : Fitted estimator.

<a id="skfolio.optimization.BenchmarkTracker.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.BenchmarkTracker.get_metadata_routing"></a>

#### get_metadata_routing()

Get metadata routing for this estimator.

Extends the parent routing: metadata passed to `fit` and `partial_fit` is also
routed to the matching method of `mu_uncertainty_set_estimator` and
`covariance_uncertainty_set_estimator`.

* **Returns:**
  **routing** *MetadataRouter*
  : Metadata routing configuration.

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

#### get_params(deep=True)

Get parameters for this estimator.

* **Parameters:**
  **deep** *bool, default=True*
  : If True, will return the parameters for this estimator and
    contained subobjects that are estimators.
* **Returns:**
  **params** *dict*
  : Parameter names mapped to their values.

<a id="skfolio.optimization.BenchmarkTracker.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.BenchmarkTracker.partial_fit"></a>

#### partial_fit(X, y, \*\*fit_params)

Incrementally fit the Benchmark Tracker estimator.

Each call receives new asset returns and the corresponding benchmark
returns. The prior estimator must implement `partial_fit`. It updates
from benchmark excess returns before the optimization is solved again.

See [Updates and Failure Handling](https://skfolio.org/user_guide/online_learning.html.md#online-failure-handling) for
continuation and restart rules.

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

  **y** *array-like of shape (n_observations, 1) or (n_observations,)*
  : Corresponding price returns of the benchmark.

  **\*\*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** *BenchmarkTracker*
  : Fitted estimator.

<a id="skfolio.optimization.BenchmarkTracker.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.BenchmarkTracker.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.BenchmarkTracker.set_params"></a>

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

Set the parameters of this estimator.

The method works on simple estimators as well as on nested objects
(such as `Pipeline`). The latter have
parameters of the form `<component>__<parameter>` so that it’s
possible to update each component of a nested object.

* **Parameters:**
  **\*\*params** *dict*
  : Estimator parameters.
* **Returns:**
  **self** *estimator instance*
  : Estimator instance.

