trader.backtest.metrics module

Backtest performance metrics (requirements §12).

Pure functions over numbers so they can be checked against hand-computed values without constructing a simulation.

trader.backtest.metrics.buy_and_hold(capital, buy_price, final_price)[source]

Ending value and return of putting capital into one symbol and holding.

The do-nothing baseline every strategy result has to be read against: a strategy that returns 20% while the symbol itself returned 55% destroyed value while looking like a success.

Fractional shares, deliberately — unlike the simulated strategy, which buys whole shares because a real order is for whole shares. Whole shares here would leave the remainder in cash and dampen the baseline by that fraction, which flatters the strategy for a reason that has nothing to do with the strategy: at capital 1000 and a 600 price, one share plus 400 idle cash tracks only 60% of the symbol’s move. Worse, when the capital buys no shares at all the baseline would read exactly 0.00% — a number indistinguishable from a flat market, which is the failure BacktestError-on-a-short-window exists to prevent. Fractional shares make the baseline the symbol’s own return, always, which is what “we could have just held it” means.

Raises:

ValueErrorbuy_price is not positive. Returning zero would be a confident number derived from unusable data.

Parameters:
  • capital (Decimal)

  • buy_price (Decimal)

  • final_price (Decimal)

Return type:

tuple[Decimal, Decimal]

trader.backtest.metrics.max_drawdown_pct(equity_curve)[source]

Largest peak-to-trough decline, as a positive percentage.

Measured against the running peak, not the starting value: a curve that ends higher than it began can still have suffered a severe drawdown.

Parameters:

equity_curve (Sequence[Decimal])

Return type:

Decimal

trader.backtest.metrics.total_return_pct(starting_value, ending_value)[source]

Percentage change from start to end. Zero start yields zero.

Parameters:
  • starting_value (Decimal)

  • ending_value (Decimal)

Return type:

Decimal

trader.backtest.metrics.win_loss(pnls)[source]

Count winning and losing trades. Break-even counts as neither.

Parameters:

pnls (Sequence[Decimal])

Return type:

tuple[int, int]