Skip to content

betting_combat.services.rounds_cache

The datasets’ incremental partitions (rounds_clock_years, rounds_fight_frames: two of the dataset tables, services.rounds_datasets), so a datasets update only computes what is new. Every entry carries the digest of exactly what it was built from and is rebuilt when that no longer matches; a cached result is the library’s own result for the same inputs, so the frames are the same with or without the caches (tests: the cold and the warm build are equal, and equal the research’s).

Group 5 (the clock). Year Y’s models are fitted on the bouts before 1 January of Y with seed Y (ClockFeatures.fit_year). Each year’s fit is cached with the digest of its inputs (the fit columns of every bout before 1 January of Y, basis_digest); every row is then priced by ClockFeatures.year_frame with its year’s fit, which is ClockFeatures.build operation for operation. The fighter profiles are as of each bout, so adding later cards leaves every older year’s inputs, and so its fit, unchanged (tests: the digest of every year before a card is the same before and after it): in steady state no year is refitted, and the first refit of a new year fits that year once.

Market frames, per Kalshi-listed fight (build_fight_frames): its Set 4 minutes, its Set 3 main and side rows BEFORE the one dataset-wide step (each spread column’s missing values filled with the median over every fight), and its tape fills for every quoted round start, market and side. The digest covers the fight’s clock row, its markets, its dataset keys and every pull record (candles, trades) of its markets. Only fights whose digest changed are rebuilt, a few cards at a time (their candles and trades read for them alone); the frames are then assembled in the whole build’s order and the spread fill applied over all of them, as set3_main / set3_side apply it.

Both caches are keyed on the code too (code_digest: the source of the modules each depends on, this one included): an entry built by other code is rebuilt.

Classes

CachedDataset

Bases: RoundDataset

RoundDataset whose Group 5 comes from the clock cache: every year’s rows priced by ClockFeatures.year_frame with that year’s fit (ClockFeatures.build, each year fitted only when not cached). The cache argument of build is not used.

model_features

model_features(prof: pd.DataFrame, d1: pd.DataFrame, cached: pd.DataFrame | None = None) -> pd.DataFrame

ClockCache

The cached years (year -> (basis digest, ClockYear)), and the years fitted now.

year

year(cf: ClockFeatures, f: pd.DataFrame, year: int) -> ClockYear

Year year’s models: the cached fit when its inputs are unchanged, else fitted.

FightFrames

Functions

assemble

assemble(fights: pd.DataFrame, frames: Mapping[str, FightFrames]) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]

(Set 4, Set 3 main rows, Set 3 side rows, the fill grid) over every fight, in the whole build’s order, the spread fill applied over all of them (set3_main / set3_side’s own last step). Set 3 is before its keys (with_keys).

basis_digest

basis_digest(f: pd.DataFrame, year: int, code: str | None = None) -> str

The digest of everything year year’s fit reads: the fit columns of every bout of f (ClockFeatures.fight_table) before 1 January of that year, and the fitting code (code; default: code_digest(CLOCK_CODE)).

build_fight_frames

build_fight_frames(fights: pd.DataFrame, markets: pd.DataFrame, keys: pd.DataFrame, candles: Mapping[str, list[dict[str, Any]]], tapes: Mapping[str, list[list[Any]]], a_slot: Mapping[str, int], config: BacktestConfig = BacktestConfig()) -> dict[str, FightFrames]

Every fight’s frames (see the module doc) from its own candles and trades.

chunks

chunks(fights: pd.DataFrame, fight_ids: Iterable[str], cards: int = CHUNK_CARDS) -> list[list[str]]

The fights to rebuild, a few cards at a time.

code_digest

code_digest(modules: tuple[str, ...]) -> str

SHA-256 over the source of modules (a package: every .py under it, sorted).

fight_digests

fight_digests(fights: pd.DataFrame, markets: pd.DataFrame, keys: pd.DataFrame, pulls: Mapping[str, Sequence[Mapping[str, Any]]], code: str | None = None) -> dict[str, str]

fight_id -> the digest of everything its frames are built from: the building code (code; default code_digest(FRAMES_CODE)), its clock row, markets, dataset keys and the pull records of its candles and trades (a re-pull changes them).

fill_grid

fill_grid(keys: pd.DataFrame, fights: pd.DataFrame, set4: pd.DataFrame, trades_side: pd.DataFrame, config: BacktestConfig) -> pd.DataFrame

The tape fills (backtest.tape_fills) of every bet the fights could make: each quoted round start x traded market x side, at its decision minute and quote.

fills_for

fills_for(events: pd.DataFrame, grid: pd.DataFrame) -> pd.DataFrame

tape_fills(events, ...) read from the grid (indexed by the events’ index); an event the grid lacks, or whose decision price differs from the grid’s, is an error.

from_parquet

from_parquet(text: str) -> pd.DataFrame

load_clock_cache

load_clock_cache(store: RoundsStore) -> ClockCache

The stored years whose blobs are intact and were fitted under the running libraries (any other is refitted).

load_fight_frames

load_fight_frames(store: RoundsStore, digests: Mapping[str, str]) -> dict[str, FightFrames]

The stored frames whose digest still matches.

pack

pack(obj: Any) -> tuple[str, str]

(base64 of the zlib’d pickle, its SHA-256).

padded

padded(set4: pd.DataFrame) -> pd.DataFrame

Set 4 with a column for every field of every market Set 3 looks up (a missing one is all missing, as in a panel built over every fight, where another fight has it).

raw_main_spread

raw_main_spread(set4: pd.DataFrame, fight: Any) -> dict[int, float]

round_idx -> Set 3 main’s spread BEFORE its dataset-wide fill (set3_main: 100 x the mean of the two winner books’ spreads at the row time, NaN without a minute there).

raw_side_spreads

raw_side_spreads(set4: pd.DataFrame, fight: Any) -> dict[int, dict[str, float]]

round_idx -> each side market’s Set 3 spread before the fill (set3_side).

rebuild_fights

rebuild_fights(store: RoundsStore, fight_ids: Sequence[str], fights: pd.DataFrame, markets: pd.DataFrame, keys: pd.DataFrame, main_candles: Mapping[str, list[dict[str, Any]]], a_slot: Mapping[str, int], load_tapes: Callable[[pd.DataFrame, pd.DataFrame], Any], windows: Mapping[str, Any] | None = None) -> dict[str, FightFrames]

Build the frames of fight_ids chunk by chunk: each chunk’s side candles and trade tapes read for it alone. main_candles: the winner and distance candles (read whole: the fight clock needs them); load_tapes(fights, markets): the chunk’s tapes; windows: the research windows the side candles are served over (rounds_windows; None: as stored).

save_clock_cache

save_clock_cache(store: RoundsStore, cache: ClockCache, at: dt.datetime) -> int

save_fight_frames

save_fight_frames(store: RoundsStore, frames: Mapping[str, FightFrames], digests: Mapping[str, str], dates: Mapping[str, dt.date], at: dt.datetime) -> int

to_parquet

to_parquet(frame: pd.DataFrame) -> str

unpack

unpack(text: str, sha: str) -> Any

The object back; ValueError when the blob does not match its SHA-256.