def tearsheet_custom_metrics

tearsheet_custom_metrics is a strategy lifecycle hook that runs during backtest analysis, immediately before LumiBot writes:

  • *_tearsheet.html

  • *_tearsheet_metrics.json

Use this hook when you want strategy-defined metrics in both artifacts.

When it runs

  1. Backtest trading completes.

  2. LumiBot computes strategy/benchmark return series and drawdown context.

  3. LumiBot calls tearsheet_custom_metrics(...).

  4. Returned metrics are appended to the tearsheet metrics table and JSON scalar metrics.

Method signature

def tearsheet_custom_metrics(
    self,
    stats_df: pd.DataFrame | None,
    strategy_returns: pd.Series,
    benchmark_returns: pd.Series | None,
    drawdown: pd.Series,
    drawdown_details: pd.DataFrame,
    risk_free_rate: float,
) -> dict:
    ...

Parameter structure

stats_df (pd.DataFrame | None)

Backtest stats dataframe (same data used for *_stats.csv/parquet).

strategy_returns (pd.Series)

Strategy return series used for tearsheet metric calculations.

benchmark_returns (pd.Series | None)

Benchmark return series when a benchmark is available; otherwise None.

drawdown (pd.Series)

Strategy drawdown series derived from cumulative returns.

drawdown_details (pd.DataFrame)

Drawdown periods table (columns such as start/end/valley/days/max drawdown when available).

risk_free_rate (float)

Effective risk-free rate used by tearsheet metrics.

Return format

Return a dict mapping metric names to values.

Supported formats:

{"Custom Metric A": 1.23}
{"Custom Metric B": {"strategy": 1.23, "benchmark": 0.91}}

Behavior rules:

  1. Return {} if no custom metrics apply.

  2. Returning None is treated as no custom metrics.

  3. Returning a non-dict is ignored (with a warning).

  4. Exceptions inside the hook are caught; tearsheet generation continues.

Example

class MyStrategy(Strategy):
    def tearsheet_custom_metrics(
        self,
        stats_df,
        strategy_returns,
        benchmark_returns,
        drawdown,
        drawdown_details,
        risk_free_rate,
    ):
        if strategy_returns.empty:
            return {}

        p95 = float(strategy_returns.quantile(0.95))
        avg_dd_days = (
            float(drawdown_details["days"].mean())
            if not drawdown_details.empty and "days" in drawdown_details.columns
            else 0.0
        )

        return {
            "95th Percentile Daily Return": p95,
            "Average Drawdown Days": avg_dd_days,
        }

API reference (source of truth)

The method docstring below is auto-loaded from the Strategy class and should be treated as the canonical API reference.

Strategy.tearsheet_custom_metrics(stats_df: DataFrame | None, strategy_returns: Series, benchmark_returns: Series | None, drawdown: Series, drawdown_details: DataFrame, risk_free_rate: float)

Lifecycle hook to append strategy-defined metrics to the tearsheet.

This hook runs during backtest analysis immediately before the tearsheet HTML and *_tearsheet_metrics.json artifacts are generated.

Parameters:
  • stats_df (pd.DataFrame or None) – Full backtest stats DataFrame (same data used for *_stats.csv/parquet).

  • strategy_returns (pd.Series) – Strategy return series used for QuantStats metrics.

  • benchmark_returns (pd.Series or None) – Benchmark return series if a benchmark is available.

  • drawdown (pd.Series) – Drawdown series computed from strategy_returns.

  • drawdown_details (pd.DataFrame) – Drawdown period table (start/end/valley/days/max drawdown when available).

  • risk_free_rate (float) – Effective risk-free rate used for tearsheet calculations.

Returns:

Mapping of metric name to value. Supported values: - {"My Metric": 1.23} - {"My Metric": {"strategy": 1.23, "benchmark": 0.87}}

Return type:

dict

Example

>>> def tearsheet_custom_metrics(
>>>     self,
>>>     stats_df,
>>>     strategy_returns,
>>>     benchmark_returns,
>>>     drawdown,
>>>     drawdown_details,
>>>     risk_free_rate,
>>> ):
>>>     avg_abs_return = float(strategy_returns.abs().mean()) if not strategy_returns.empty else 0.0
>>>     return {"Avg Absolute Daily Return %": avg_abs_return * 100.0}