betting_combat.services.rounds_odds
The Kalshi card-start prices (fights_kalshi): one row per settled Kalshi fight with both
winner books before the card’s first fight and before its own close, the de-vigged price and
its quality flag — the pre-fight price p_mkt_a of every fight without a sportsbook line
(rounds.features.sources.RawData.odds) and the fight list of the market chain
(rounds.market.build_fights).
Port of the research ufc/pull.py (pull_kalshi, _quote, _close, pull_events,
classify_event, _attach_events) with identical numbers and the file’s own cell text:
sides every winner market with a YES/NO result: its fighter, whether it won, its close, the card date in its event tickercard_first_close per card date: the earliest close among the markets closing within 8 hours of the date's median close (the card-start proxy)quote the last hourly candle ending at or before a limit: its YES bid and ask closes, and the contracts traded in the 24 hours to the limitfight rows per event with exactly two sides, one YES: 'card' quotes at card_first_close - 60 min, 'close' quotes at the fight's close - 60 min; prob = each mid normalised across the two books (``card_quote``, the live engine's rule), vig, payout net of the taker fee, quote_okevents Wikipedia's past events (event name, date), attached by date (+/- 1 day), unlisted midweek cards = Dana White's Contender SeriesThe hourly candles are the research’s: the 48 hours to each market’s close, 60-minute periods, from /historical when the market settled before Kalshi’s cutoff.
A fight’s row is derived once, the day after its card at the earliest (every fight of a card has settled by then; the research pulled after the cards), and never rewritten.
Classes
OddsReport
RoundsOddsService
Extends fights_kalshi after every card: the hourly candles of every settled winner
market of a derivable fight, then the fight’s row.
derive
derive(s: pd.DataFrame, events_todo: Sequence[str]) -> OddsReportThe rows of events_todo whose two markets’ candles are stored (the others wait
for their candles), inserted; a stored row is never rewritten.
derive_due
derive_due(since: dt.date | None = None) -> OddsReportThe datasets job’s half: the rows of every due fight whose candles are stored.
land
land(kalshi: KalshiRest, since: dt.date | None = None) -> OddsReportPull the candles of every due fight, then derive the rows (both halves at once).
land_candles
land_candles(kalshi: KalshiRest, since: dt.date | None = None) -> OddsReportThe data job’s half: the hourly candles of every due fight’s winner markets (raw).
pending
pending(since: dt.date | None = None) -> tuple[pd.DataFrame, list[str]](sides of every stored winner market, the events whose row is due and missing):
exactly two YES/NO markets, one YES, the card at least a day old (dated on or after
since when given).
pull_candles
pull_candles(kalshi: KalshiRest, tickers: Sequence[str]) -> OddsReportThe hourly candles of tickers not stored yet (the research’s window and
endpoint rule); a market whose pull raises is counted and retried next run.
Functions
attach_events
attach_events(df: pd.DataFrame, events: pd.DataFrame) -> pd.DataFrameevent_name and event_type by date: the first event listed on that date, else
one day either side (research _attach_events); event_type ‘unknown’ when none.
card_date_of
card_date_of(event_ticker: str) -> dt.date | Nonecell
cell(value: Any) -> strOne value as the research’s to_csv wrote it: ” for a missing value, True/False,
a float by its shortest round-trip repr, a date ISO, a timestamp as pandas prints it.
cells_of
cells_of(df: pd.DataFrame) -> list[dict[str, str]]Each row as {column: its CSV cell}.
classify_event
classify_event(name: str) -> strThe card type from its Wikipedia name (research classify_event).
fight_rows
fight_rows(s: pd.DataFrame, candles: Mapping[str, Sequence[Mapping[str, Any]]], events: pd.DataFrame) -> pd.DataFrameThe research’s fights_kalshi rows of every event in s with exactly two sides and one
winner (s: sides rows, possibly of a few events, their card_first_close computed
over every market of their dates; candles: ticker -> hourly candles, one entry per
market of those events).
past_events
past_events(list_json: str) -> pd.DataFrameWikipedia’s past events (research pull_events): event_name (footnotes removed),
date (a datetime.date), location and event_type, in the list’s order
(newest first), rows without a readable date dropped.
quote
quote(candles: Sequence[Mapping[str, Any]], limit: pd.Timestamp) -> dict[str, Any]The book at limit from hourly candles (research _quote): the last candle ending
at or before it, and the contracts traded in the 24 hours to it.
research_close
research_close(candle: Mapping[str, Any], side: str) -> float | NoneA candle’s close for side (research _close: live candles carry
‘close_dollars’, archived ones ‘close’).
sides
sides(markets: Iterable[Mapping[str, Any]]) -> pd.DataFrameEvery winner market with a YES/NO result (research pull_kalshi’s sides): ticker,
event_ticker, fighter, won, close_time, date, card_first_close.