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 replayedquotes 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 orientationoutcomes what each round start's markets paid (``Targets``), per stand-in idsettings 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]) -> UfcTablesThe 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) -> ForwardReportOne 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 | NoneWhy 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 | Nonecard_inputs
card_inputs(artifact: RoundsArtifact, card: UpcomingCard, info: pd.DataFrame, before: UfcTables, sources: Sources, side_candles: Sequence[Mapping[str, list[dict[str, Any]]]]) -> CardInputsThe 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.DataFrameThe 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) -> SettingsThe 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 samemeta the meta probability of every decision, against whether its side wonOne 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.DataFrameWhat 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) -> CardReplayThe card through the research decision path (PRODUCTION rules).
results_missing
results_missing(tables: UfcTables, card_date: dt.date) -> str | NoneWhy 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.