betting_combat.rounds.market.windows
Set 3: round-start market features from the Kalshi trades, one row per (fight_id, round_idx) like the round dataset, built only from what happened before the row’s time.
Ported from the research (ufc/dataset/set3.py: window_stats, Set3.row_times,
Set3.windows, Set3.main, Set3.side, Set3.implied, Set3.write).
Row time t: the end of the break before round r+1 (round_idx r); for round_idx 0 the minute before the fight. A row for every round that started (no cut at the winner market’s snap, which is only known afterwards; the dataset keeps the rounds that started). Windows, with edges E = [start-60, start-30, start, start+6, start+12, …]:
last_ [E[r+1], t) the round just fought (round 1: the 30 minutes before the fight)prev_ [E[r], E[r+1]) the window before thatsofar_ [start, t) the fight so farpre_ [start-30, min(start, t)) (round 0 stops at its own time t)lastmin_ [t-1, t)Trades are read in (ts, trade_id) order (:func:~.trades.time_order): the last price of a
window never depends on how a sort breaks ties.
Main market (A-framed: a trade in B’s market is its mirror in A’s): mid_a, spread (cents), oi,
mins_since_trade, chg_since_pre, per window trades, contracts, dollars, avg_trade, big_trades
(>= $500), blocks, flow, vwap_a, chg_a, range_a, vol_a, jumps; surprise. Side markets
(:data:SIDE): implied) with their change over
the last window. A window with no trades: counts 0, moves 0, prices carried from the last
trade before it (else the book at t).
Functions
drop_unpriceable
drop_unpriceable(side: pd.DataFrame) -> tuple[pd.DataFrame, dict[str, list[str]]]The side set’s complete-core rule: a listed side market that never had a book or a trade before a row cannot be priced, and its fight leaves the side set. Returns the kept rows and fight_id -> the columns that were empty.
implied
implied(mids: Mapping[str, Any], main_mid_a: float) -> dict[str, Any]Probabilities implied by the side markets: p_dec_dist (distance), p_dec_mov and p_a_mov (shares of all MOV), p_finish_mov, ko_share (of the finishes), gap_dec, gap_a.
row_times
row_times(f: Any) -> list[tuple[int, pd.Timestamp, list[pd.Timestamp]]](round_idx, row time, window edges E) for every scheduled round of a fight (the
dataset keys keep the rounds that started). f needs start, rounds.
set3_main
set3_main(trades_main: pd.DataFrame, minutes: pd.DataFrame, fights: pd.DataFrame, causal: bool = False) -> pd.DataFrameThe winner-market rows (research Set3.main), before the dataset keys are attached.
Args:
trades_main: :func:~.trades.trade_tables main table.
minutes: :func:~.minutes.set4_minutes.
fights: :func:~.listing.live_fights rows.
causal: no window of a row reaches past the row’s time (the round-0 sofar
window, see :func:window_bounds); False = the research.
set3_side
set3_side(trades_side: pd.DataFrame, minutes: pd.DataFrame, fights: pd.DataFrame, markets: pd.DataFrame, main: pd.DataFrame) -> pd.DataFrameThe side-market rows (research Set3.side) for the fights listing all of
:data:SIDE, before the dataset keys are attached.
Args:
trades_side: :func:~.trades.trade_tables side table.
minutes: :func:~.minutes.set4_minutes.
fights: :func:~.listing.live_fights rows.
markets: :func:~.listing.market_list rows (fight_id, name).
main: :func:set3_main (its mid_a).
window_bounds
window_bounds(r: int, t: pd.Timestamp, edges: list[pd.Timestamp], causal: bool = False) -> dict[str, Window]The row’s windows as (lo, hi), lo <= ts < hi. pre ends at min(start, t): the
round-0 row (t = the minute before the start) does not read [t, start) (research fixed
2026-09-30).
causal: the research’s round-0 sofar is the empty window at the start, so its
carried price (sofar_vwap_a) is the last trade before the START, not before t. True
makes it [min(start, t), t), the live rule: nothing at or after t. False reproduces the
research. Rows at or after the start are the same either way.
window_stats
window_stats(tr: pd.DataFrame, lo: Any, hi: Any, carry: float) -> dict[str, Any]Trade statistics for trades with lo <= ts < hi. tr columns: ts, price (A-framed or
the market’s own YES price), count, dollars, sign (+1 buying the priced side), block;
carry is the price before the window.
with_keys
with_keys(keys: pd.DataFrame, rows: pd.DataFrame) -> pd.DataFrameThe dataset’s keys (fight_id, round_idx, event_id, event_date) inner-joined to Set 3 rows, in the dataset’s order.