Skip to content

betting_combat.models.distance

Strategy 2 — the distance model.

The pre-fight price of “the fight goes the distance” is accurate; during the fight the market barely updates it as minutes pass without a finish. The fair price is the pre-fight price updated by Bayes for “no finish yet”:

P(distance | no finish by minute m) = p0 / (p0 + (1 - p0) * S(m | x))

S(m | x) is the share of this fight’s possible finishes that would come after minute m. It comes from a Bayesian piecewise-exponential hazard model fitted on UFC history (never on Kalshi prices): a minute-by-minute baseline hazard with a random-walk prior, covariate effects and partially pooled division effects, truncated to “finish by the final bell”. Inference averages S over the posterior draws (research: ufc/distance_bayes.py::BayesPE).

Classes

DistanceModel

decision_factor

decision_factor(p_decision: float, fight_min: float, rounds: int, cov: FightCovariates) -> float

How much more likely a decision has become by fight_min without a finish: 1 / (pD + (1 - pD) S(m)), where pD is the pre-fight chance of a decision.

Any market that pays only on a decision is worth its pre-fight price times this factor (fair is the distance market’s case: its own price is pD).

fair

fair(p0: float, fight_min: float, rounds: int, cov: FightCovariates) -> float

P(the fight goes the distance | no finish by fight_min), from the pre-fight price p0.

from_params

from_params(params: dict[str, Any], version: int) -> DistanceModel

method_elapsed

method_elapsed(method: str, fight_min: float, rounds: int, cov: FightCovariates) -> float

Share of this method’s finishes that come before fight_min; without method curves, every finish is assumed to keep the overall timing.

FightCovariates

The curve’s inputs for one fight. Unknown values stay None and are replaced by the training mean, exactly as in training.

raw_vector

raw_vector() -> list[float | None]

FinishCurve

Posterior draws of the piecewise-exponential finish-time model.

from_posterior

from_posterior(posterior: dict[str, Any], design_mean: dict[str, float], design_sd: dict[str, float]) -> FinishCurve

standardize

standardize(cov: FightCovariates) -> np.ndarray

survival_after

survival_after(minute: float, rounds: int, cov: FightCovariates) -> float

S(m | x): the share of this fight’s finishes (if it ends in one) after minute.

Functions

division_group

division_group(weight_class: str | None) -> str

The division a weight class belongs to (the curve’s partially pooled groups).