Business Glossary — EdgeBet NRL

Generated from nrl-bet-advisor/data/glossary.py by
scripts/generate_business_glossary.py. Do not edit this file by hand —
edit the module and regenerate. tests/test_glossary.py enforces sync.

Backtesting

Bootstrap confidence interval (season-resampled)

ROI error bars from resampling whole seasons with replacement.

Seasons, not bets, are the resampling unit — bets within a season share fixtures and pricing regime. A ROI claim is 'significant' only when the entire interval clears zero AND covers ≥5 seasons. One good season on ~150 bets is a ±8-14% standard-error coin flip.

Price basis (open vs close)

Which market state a backtest prices and settles bets at.

Actionable models are priced at OPENING odds (what you could actually see at decision time); *_market diagnostics settle at close. Mixing the two flatters strategies — every results row carries its price_basis.

Staking policies (flat / edge-capped / shrunk ¼-Kelly)

flat: $1 every game. edge_capped: $1–2 when raw EV ≥ 5%. shrunk_kelly: quarter-Kelly on the market-blended probability, EV clamped to [2%, 10%].

Kelly fraction = EV/(odds−1); quarter-Kelly against a 100-unit notional, capped at 2 units. The shrunk policy bets far less often — after blending toward the market almost nothing clears 2% EV, which is what an efficient market should look like.

Edge & Value

CLV (Closing Line Value)

How much better the price you took was than the same book's final pre-kickoff price.

The single most reliable edge indicator: consistently beating the close means you had information before the market finished pricing it. Price CLV = taken_price/closing_price − 1; line CLV is in chosen-side points. Measured per bookmaker against raw prices — CLV against an averaged synthetic price is not evidence. Positive average AND median CLV is a promotion gate.

Closing-line agreement (CLA)

When a model disagrees with the OPENING price by ≥3pp, how often the market moves toward the model by close.

The fastest edge detector in the shop: beating the close requires holding information before the market prices it, and the first symptom is the open→close move agreeing with the model's open-time edge above the ~50% coin-flip rate. ≥53% with |z| ≥ 2 on hundreds of signals = real pulse. Uses closing data as a diagnostic label only — never a feature. Note: for close-featured diagnostics the metric is tautological (they contain the answer) and should be ignored.

EV (Expected Value)

model_prob × decimal_odds − 1: expected profit per $1 staked if the model probability is exactly right.

The 'if' is load-bearing. EV inherits every calibration error in the model, and selecting the max-EV side each game preferentially harvests the model's own mistakes (favourite–longshot trap). Recognised EV is capped at 10% in the shrunk policy for exactly this reason.

Edge signal

model_prob − market_prob: how much more likely the model thinks an outcome is than the market implies.

A positive residual is a candidate value bet, not evidence. In a market with ~2% margin, most large residuals are model error, not market error — which is why signals are shrunk toward the market and paper-traded before any promotion.

Explainability

Feature contribution / SHAP

How much each feature pushed one specific prediction, in log-odds; contributions sum exactly to the model's raw score.

LightGBM uses native TreeSHAP (pred_contrib); logistic models use coefficient × standardized value, which is exact for linear models. Surfaced via predict.py --explain and the UI so every recommendation can answer 'why?' — an unexplainable edge cannot be audited and should not be trusted.

Markets

Closing line

A bookmaker's last quoted price/line before kickoff — the market's most-informed state.

Defined as the last pre-kickoff snapshot per book. A snapshot taken after kickoff is not a closing line (the API drops events at commence time). Closing data is a diagnostic ONLY: using it as a model feature is leakage and is blocked by the leakage guard.

Market types (H2H / line / total)

Win-loss (H2H), points handicap (line/spread), and over-under total points — three separate markets.

Treated as separate problems everywhere: separate models, separate CLV benchmarks, separate promotion tracks. Pooling them hides which market a signal actually works in.

Opening-price softness

The empirical finding that NRL opening prices are less efficient than closing prices — the current edge thesis.

Three instruments agree: line_ridge_core's positive ROI exists only at opening lines; open-priced models' edge signals are confirmed by the close ~54–55% of the time (z ≥ 2.7); close-featured diagnostics settle negative. Every live strategy is therefore a race to the soft early price — which is why open snapshots on Monday and close snapshots pre-kickoff both matter.

Steam / line movement

A rapid, market-wide shift in a line or price, usually triggered by sharp money or news.

The movement strategies paper-trade following steam (≥2 pts on totals/spreads, ≥3% no-vig probability on H2H, ≥2 bookmakers). Whether NRL steam carries information is an open hypothesis — that's what the paper trades exist to answer.

Vig / margin / de-vigged probability

The bookmaker's built-in profit: quoted implied probabilities sum to >100%; de-vigging rescales them to a fair probability.

NRL H2H margin is ~2%. Every model comparison uses de-vigged (no-vig) probabilities; beating the vig is the minimum bar any strategy must clear before it earns anything.

Model Quality

Ablation control

The same model minus exactly the feature being tested — the only fair incumbent for a new-feature gate.

logit_open_mkt exists solely so RAPM's gate compares like-for-like: beating a weaker model with a different feature set proves nothing about the new feature. The original phase-3 'pass' compared against bare logit_core and was an artifact of the market feature, not the lineup delta.

Brier score

Mean squared error of probabilities (0 = perfect, 0.25 = coin-flip).

Same role as log-loss with gentler tail penalties; reported alongside it.

Calibration / ECE

Whether events forecast at 60% actually happen 60% of the time. ECE = count-weighted mean |observed − predicted| across probability buckets.

Calibration matters more than accuracy for betting: EV is computed FROM the probability, so a miscalibrated bucket produces systematically fake edge in that bucket. The reliability table shows exactly where the model can't be trusted.

Leakage

Any feature not knowable at placement time — closing prices, line movement, results.

Actionable models may use only placement-time information. Closing-market fields are diagnostics. Enforced by the token guard in model_bench.py and tests/test_leakage_guard.py; *_market model variants are deliberately leaky diagnostics and are never seeded into paper trading.

Log-loss

Penalises confident wrong probabilities; the primary accuracy metric for probabilistic models.

A coin-flip scores 0.693; the closing market scores ~0.62 on NRL H2H. A model is only interesting BELOW the market's log-loss on out-of-sample data. Raw accuracy is misleading for imbalanced or odds-dependent outcomes.

Shrinkage (market-anchored blend)

p_bet = λ·p_model + (1−λ)·p_market, with λ fit on prior seasons only.

The market is the best prior; the model earns weight only by improving out-of-sample log-loss. Fitted λ near 0 is the market telling you the model adds nothing — currently λ ≈ 0.02–0.06 for the H2H bench, which is the honest state of play.

Time decay (training weights)

Down-weighting old seasons in a fit: weight = 0.5^(age/half-life).

Rosters and player primes churn; 2018 evidence should not weigh like 2025. Applied as ridge sample weights in RAPM (RAPMConfig.decay_half_life_seasons). Choose the half-life by out-of-sample log-loss, never by how big it makes the deltas look.

Walk-forward validation

Train on seasons strictly before the test season, roll forward season by season.

The only backtest structure that mimics real deployment. Random train/test splits leak future information through team-strength drift and are banned here.

Models

Elo rating

A team strength score updated after each match by K × margin-scaled surprise; drives the baseline win probability.

Config: base 1500, home advantage +55, K=24 with margin multiplier capped at 1.5×, 25% regression to mean between seasons. Simple, stable, and the backbone of most other features — which is also its weakness: models built on it are correlated, not independent.

Lineup mirroring (positional marking)

In team-list matchups, positions mark their mirror: the home LEFT centre defends the away RIGHT centre, and so on across the field.

Any player-vs-player matchup feature must reverse one side's left/right labels before pairing, or every edge/centre/wing matchup is computed against the wrong opponent. Applies to team-list-derived positional deltas; spine positions (1/6/7/9) are unaffected.

RAPM (Regularized Adjusted Plus-Minus)

Player value from ridge regression on ±1 lineup indicators against match margins — points per game each player adds, adjusted for who they play with and against.

Fit walk-forward (seasons before S only) on team-list lineups with player identity resolved via gold_nrl_player_name_map. rapm_lineup_delta = Σ home ratings − Σ away ratings. With ~2k matches pure RAPM is noisy — the stats-prior variant shrinks toward box-score value instead of zero.

Season regression (to the mean)

Between seasons every Elo rating is pulled 25% toward 1500.

Rosters churn over the off-season; last year's strength decays. The transfer disruption features try to price the same effect at player level.

Stats prior / offset ridge

Shrinking each player's RAPM rating toward a box-score-derived value (per-80 metres, breaks, tackles…) instead of toward zero.

The regression fits the margin residual after the prior explanation, so sparse players (debutants, rarely-rested stars) keep a sensible rating instead of being crushed by the L2 penalty. Priors for season S must be built from data through S−1 only — the walk-forward guarantee is the constructor's responsibility. Known as xRAPM/RPM in basketball.

Operations

Data freshness

Age of each feed's latest record vs its expected cadence (odds snapshots ≤6h in-round, draw/results weekly, team lists by Tue 4pm).

Stale feeds silently degrade models: rolling form goes quiet, lineup deltas zero out, CLV becomes uncollectable. The Ops tab turns each feed's staleness into an OK/STALE/MISSING status against explicit thresholds.

Process

Model agreement filter

Only act when independent models (e.g. Elo and LightGBM) agree on direction.

Agreement adds confidence only if the models are actually independent — most of the current bench is Elo restated, so treat agreement as weak evidence until the feature families diverge (e.g. player-level lineup pricing).

Paper trading

Recording hypothetical bets with real prices and settling them against real results — no money.

Every strategy is paper-first. paper_trades_v2 records the named bookmaker, taken price/line, model vs market probability, and later CLV and settlement. Language rule: candidate / hypothesis / paper trade — never 'proven edge'.

Promotion gates

The bar a candidate must clear before advancing: ≥100 settled paper bets, ROI > +5%, positive mean AND median CLV, no round >30% of profit, holds home & away.

Canonical values live in data/promotion_gates.py; docs and skills must match it (test-enforced). Negative-CLV models get zero vote weight regardless of ROI.