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.DataFrameClockCache
The cached years (year -> (basis digest, ClockYear)), and the years fitted now.
year
year(cf: ClockFeatures, f: pd.DataFrame, year: int) -> ClockYearYear 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) -> strThe 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, ...]) -> strSHA-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.DataFrameThe 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.DataFrametape_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.DataFrameload_clock_cache
load_clock_cache(store: RoundsStore) -> ClockCacheThe 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.DataFrameSet 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) -> intsave_fight_frames
save_fight_frames(store: RoundsStore, frames: Mapping[str, FightFrames], digests: Mapping[str, str], dates: Mapping[str, dt.date], at: dt.datetime) -> intto_parquet
to_parquet(frame: pd.DataFrame) -> strunpack
unpack(text: str, sha: str) -> AnyThe object back; ValueError when the blob does not match its SHA-256.