Skip to content

betting_combat.rounds.backtest.capacity

Capacity: the same bets (the same final probability, meta probability and sizing) filled through every instrument that pays on exactly the same event, cheapest first (research ufc/modeling/capacity.py).

VIEWS and their instruments rounds view ‘ends this round’ k_rounds Kalshi rounds market (‘ends before round k’) p_before Polymarket ‘ends before round k’ distance view ‘goes to the judges’ k_distance Kalshi distance k_pair Kalshi decision pair: ‘A wins by decision’ and ‘B wins by decision’ bought together; exactly one pays $1 on a decision with a winner (YES bets only); a decision without one (draw, no contest) pays the pair nothing (pair_won: an event’s no_winner = 1; the datasets exclude draws, so the backtests have none) p_distance Polymarket ‘Fight to Go the Distance?’

Per bet and instrument: the quote at t, the fill from the instrument’s own tape (arrival price after latency_s, limit = quote + cushion), its own volume cap (a share of its $ in the window before t) and its own fee (Polymarket: 0 unless poly_fee_as_kalshi).

run(): per bet in decision order (stop.decision_order) skip a pre-fight event (round_idx 0) unless config.trade_round0 want 0.25 x Kelly x AFML meta size x bankroll, Kelly priced on the Kalshi instrument; or, with cap ‘joint’, 0.25 x the stake maximising expected log wealth over the fight’s three scenarios given the distance position already held, x AFML meta size room min(fight cap - staked on the fight, card cap - staked on the card, max_bet, want) route cheapest all-in price (price + fee) first (equal prices in instrument-name order), each instrument up to its volume cap, only while our probability still beats its all-in price and more than $1 of room is left skip the whole bet once the card’s SETTLED P&L <= -daily_stop x bankroll (stop.SettledStop)

Functions

capacity_fight_cap

capacity_fight_cap(cap: str | float) -> float

The fight cap as a share of bankroll (‘joint’ caps at 20 %).

instruments

instruments(events: pd.DataFrame, kalshi_trades: pd.DataFrame, minutes: pd.DataFrame | None, poly_trades: pd.DataFrame | None = None, config: BacktestConfig = BacktestConfig()) -> pd.DataFrame

One row per (bet, instrument): bet (the event’s index label), inst, price paid if filled (NaN if missed), fee per contract at the arrival price, window $.

events needs fight_id, round_idx, market, t_entry, entry, side. minutes: the Kalshi minute books with fight_id, ts and the pair’s asks mov_a_dec_ask, mov_b_dec_ask (the pair is quoted only when the event’s t_entry is one of its minutes and both asks are finite). poly_trades: the Polymarket tape, or None.

joint_kelly_stake

joint_kelly_stake(p_now: float, p_later: float, p_dec: float, held_dist: float, bet_kind: str, bet_yes: bool, price: float, wealth: float, frac: float = 0.25, max_share: float = 0.2, points: int = 201) -> float

Extra stake ($) on the new bet maximising expected log wealth over three scenarios (finish this round / finish later / decision), given held_dist contracts already held that pay $1 on a decision; searched on points stakes in [0, max_share x wealth]. Returns frac x the optimum.

pair_won

pair_won(won: int, no_winner: Any) -> int

What the decision pair pays per contract: the distance bet’s result (1 on a decision), except 0 when the decision has no winner (draw / no contest; no_winner = 1): neither ‘A by decision’ nor ‘B by decision’ pays then.

run

run(events: pd.DataFrame, inst: pd.DataFrame, use: Sequence[str], cap: str | float, vol: float, config: BacktestConfig = BacktestConfig(), kelly: float = 0.25, sizing: Literal['kelly_x_meta', 'kelly_meta_filter'] = 'kelly_x_meta') -> pd.DataFrame

The fills of every bet through the instruments in use, in time order: event_id, fight_id, event_date, inst, meta, cost, pnl (one row per instrument filled).

events needs t_entry, t_end, fight_id, round_idx, event_id, event_date, market, side, meta, p_side, cost, won (and finish_final, finish_l1, decision_l1 for cap ‘joint’; no_winner optional); inst is instruments on the same events. sizing: the want’s meta factor — the AFML size (the research’s capacity rule, the default) or 1 when meta >= 0.5 else 0 (research execution.Book’s kelly_0.10).