Skip to content

betting_combat.services.rounds_forward

Strategy 4’s forward check (ROUND_SYSTEM_FLOW §4 rounds_forward, §9 rounds_forward_check): after a card has settled, the card replayed through the research decision path (rounds.live.replay, PRODUCTION rules) with the model version the live run traded, beside every decision the live run recorded, bet by bet, for each mode it ran in.

What the replay is given, so that the only differences left are the engine’s own:

models the version the live decisions name (else the newest locked before the card)
rows the card as the live engine received it (``rounds_upcoming_cards``, stored by
the loader at the run; else assembled again), rebuilt through the same feature
path (``with_upcoming`` -> ``build_upcoming``, the version's clock) on the
inputs as they stood before the card: the same fighters, the same stand-in
fight ids, so the same A/B orientation. Only the round starts that happened
(UFCStats' result, as Dataset 1 keeps them) are replayed
quotes the card-start Kalshi prices (p_mkt_a) from the card's fights_kalshi rows (the
live run read its own from the books before the first fight)
markets the settled card from the store: the Kalshi fight clock (``live_fights`` on the
card's fights_kalshi rows and winner candles), Set 4 and the trade tables,
keyed to the stand-in ids with the live orientation
outcomes what each round start's markets paid (``Targets``), per stand-in id
settings the strategy row and the portfolio now, with the money settings the card ran
under (``rounds_card_limits``, per mode)

Compared per (Kalshi fight, round start, market): side, p_side, edge, meta, entry (the decision) and the $1-payoff units intended; fills are shown, not compared (the replay’s are simulated on the tape). avg_price on both sides is the all-in cost (fees included) per unit held. A mismatch, a live-only or a replay-only bet is a finding.

Then the forward calibration (rounds_calibration, source ‘forward’): for each model version the card’s decisions name, every live or paper decision naming it on a checked card, its probabilities against what its market paid (forward_calibration), rewritten whole.

Classes

CardInputs

Everything the replay of one card reads but the trade tapes.

CardReplay

The replay of one card and how its fights map to Kalshi’s.

ForwardReport

NotReady

Bases: RuntimeError

What the forward check needs is not (or no longer) available.

RoundsForwardService

The forward check of a card (see the module doc).

artifact

artifact(card_date: dt.date, named: set[int]) -> tuple[RoundsArtifact, int]

The version the live decisions name (exactly one), else the newest locked before the card; ArtifactError when none can be loaded.

as_of

as_of(after: UfcTables, card_date: dt.date, stored: Mapping[str, Any]) -> UfcTables

The tables as the live run read them: before the card, with the Wikipedia list snapshot and the fighter table’s rows of the card’s fighters it was assembled against (NotReady when the assembly lacks them or the snapshot has aged out).

calibrate

calibrate(versions: Sequence[int], sources: Sources) -> dict[int, int]

Each version’s forward reliability bins (forward_calibration) over every checked card whose decisions name it, rewritten whole (‘oos’ rows untouched). Returns version -> rows written.

check

check(card_date: dt.date) -> ForwardReport

One card: per mode, the card assembly that mode’s run used, replayed with every model version its decisions name (a key under the version of its decision; a bet only the replay made, under the version of its fight’s first decision, else the mode’s first); written per mode (the mode’s previous rows replaced). A card whose results or Kalshi rows are not all landed stays pending (nothing written: checked again).

kalshi_pending

kalshi_pending(card_date: dt.date) -> str | None

Why the card’s Kalshi side is not complete yet: a winner market of the card not settled, or a settled fight without its fights_kalshi row (derived the day after).

Functions

card_date_of_ticker

card_date_of_ticker(ticker: str) -> dt.date | None

card_inputs

card_inputs(artifact: RoundsArtifact, card: UpcomingCard, info: pd.DataFrame, before: UfcTables, sources: Sources, side_candles: Sequence[Mapping[str, list[dict[str, Any]]]]) -> CardInputs

The card’s replay inputs (see the module doc): before = the tables as they stood before the card, sources = the store’s inputs after it.

card_outcomes

card_outcomes(raw: RawData, ufc_ids: list[str]) -> pd.DataFrame

The round starts that happened and what each paid (y_finish_round, y_decision), for the card’s eligible bouts (as Dataset 1 keeps them), UFCStats ids.

card_settings

card_settings(base: Settings, limits: Mapping[str, Any] | None) -> Settings

The replay’s settings: base (the strategy row and portfolio now) with the money settings the card ran under, when recorded (rounds_card_limits): the sizing bankroll, the card cap, the settled-loss stop, the fight and order caps (dollars -> shares of the bankroll).

forward_calibration

forward_calibration(version: int, decisions: pd.DataFrame, outcomes: pd.DataFrame) -> list[dict[str, Any]]

The forward reliability bins of one model version (calibration_rows, source ‘forward’): its live and paper decisions (rounds_decisions) against what their market paid (outcomes: kalshi_outcomes), as the refit’s ‘oos’ bins are built:

layer2 the rounds market's p (P(ends this round)) where layer 2 priced it (source
'layer 2'), against 'ends this round'
market the rounds market's mid, against the same
meta the meta probability of every decision, against whether its side won

One decision per (card, Kalshi fight, round start, market): the live run’s, else the paper run’s (each prices the same model; a bet is never counted twice). Decisions of another version or mode, and round starts without an outcome, are left out; a model with no decision has no rows. Layer 1 is not recorded on a decision, so it has none.

kalshi_outcomes

kalshi_outcomes(sources: Sources, card_dates: Sequence[dt.date]) -> pd.DataFrame

What each round start of the cards’ Kalshi fights paid, keyed as the decisions are (fight_id = the Kalshi fight, round_idx): y_finish_round, y_decision (card_outcomes on the UFCStats bout each Kalshi fight is, fight_ids). Both targets are symmetric, so no orientation is needed.

live_bets

live_bets(decisions: pd.DataFrame, orders: pd.DataFrame, bets: pd.DataFrame) -> dict[str, dict[tuple[str, int, str], dict[str, Any]]]

mode -> (Kalshi fight, round start, market) -> the live decision’s fields.

decisions: the card’s rounds_decisions rows; orders: its rounds_orders rows; bets: its rounds_bets rows (units and staked of what was held).

rekeyed_fights

rekeyed_fights(sources: Sources, raw_after: RawData, card_date: dt.date, info: pd.DataFrame) -> tuple[pd.DataFrame, dict[str, str]]

The card’s Kalshi fights with their result (build_fights -> fight_ids), each keyed to its stand-in id and oriented as the live run was (ka_is_1: Kalshi’s fighter A is the card’s name_1); and stand-in id -> UFCStats id.

replay_bets

replay_bets(r: CardReplay) -> dict[tuple[str, int, str], dict[str, Any]]

(Kalshi fight, round start, market) -> the replay’s decision, the units it bought (a pair counts once) and their all-in cost per unit.

replay_card

replay_card(artifact: RoundsArtifact, version: int, ci: CardInputs, tapes: Mapping[str, list[list[Any]]], settings: Settings) -> CardReplay

The card through the research decision path (PRODUCTION rules).

results_missing

results_missing(tables: UfcTables, card_date: dt.date) -> str | None

Why the card cannot be checked yet: UFCStats’ results or its Kalshi card-start rows (fights_kalshi, derived the day after) not landed; None when both are.