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) -> floatHow 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) -> floatP(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) -> DistanceModelmethod_elapsed
method_elapsed(method: str, fight_min: float, rounds: int, cov: FightCovariates) -> floatShare 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]) -> FinishCurvestandardize
standardize(cov: FightCovariates) -> np.ndarraysurvival_after
survival_after(minute: float, rounds: int, cov: FightCovariates) -> floatS(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) -> strThe division a weight class belongs to (the curve’s partially pooled groups).