trader.replay.outcomes module

Forward returns and max adverse excursion, from one fetch per symbol.

Structurally isolated from the prompt path. This module must import nothing that builds a model prompt and nothing that loads point-in-time news or bars for one — enforced by a source-text check in this package’s test suite — because the scoring rule requires that nothing computed here can leak into a prompt. Stored bars are dividend-adjusted and adjusted history is retroactively mutable (CLAUDE.md), so both endpoints of every horizon come from a single fetch: mixing a close written months ago with one written today would put an invisible step at the join.

trader.replay.outcomes.HORIZONS: tuple[int, ...] = (1, 5, 10, 21)

The pre-registered horizons. N=5 is the headline; the rest are reported alongside on every run so N cannot be swapped after seeing results.

class trader.replay.outcomes.ForwardPrices(symbol, fetched_at, closes, lows, grid)[source]

Bases: object

One symbol’s closes and lows, from one fetch, for scoring at any horizon.

Parameters:
  • symbol (str)

  • fetched_at (datetime)

  • closes (dict[date, Decimal])

  • lows (dict[date, Decimal])

  • grid (list[date])

symbol
fetched_at
closes
lows
grid
trader.replay.outcomes.fetch_forward_prices(provider, symbol, start, end)[source]

Fetch symbol’s bars once and index them for every horizon.

One call, one adjustment basis. fetched_at is recorded so a run’s provenance shows exactly when this basis was pinned.

Parameters:
  • provider (_Provider)

  • symbol (str)

  • start (date)

  • end (date)

Return type:

ForwardPrices

trader.replay.outcomes.forward_return(prices, entry_day, n)[source]

close(exit) / close(entry) - 1, off the fetched session grid.

Returns None when the horizon runs past the fetched data — never a truncated return, which would silently understate a long horizon.

Raises:

ValueErrorentry_day is not a session on the fetched grid.

Parameters:
Return type:

Decimal | None

trader.replay.outcomes.max_adverse_excursion(prices, entry_day, n)[source]

The worst intraday dip after entry, entry day excluded, exit day included.

min(low) / close(entry) - 1 over the sessions strictly after entry_day up to and including the exit day. The entry day’s own low must not count: it happened before the decision, not after it.

Parameters:
Return type:

Decimal | None