""" League Confidence Loader ======================== Loads pre-computed per-league CONFIDENCE labels from data/league_confidence.json. Called once at orchestrator startup. Unlike league_reliability (odds-calibration), this reflects the model's *backtested betting performance* per league: a label of high/medium/low/unknown derived from BET ROI **and** sample size together, so a few lucky bets in a thin league don't earn an undeserved "high" badge. Label rule (from scripts that build the artifact): high : bet_roi > +10% AND bet_n >= 20 low : bet_roi < -5% AND bet_n >= 15 unknown : bet_n < 10 (too few bets to judge) medium : everything else Usage: from utils.league_confidence import load_league_confidence lookup = load_league_confidence() info = lookup.get(league_id) # {"label","bet_roi","bet_n","hit","name"} or None """ from __future__ import annotations import json import os from typing import Dict, Any _DATA_FILE = os.path.join( os.path.dirname(os.path.abspath(__file__)), "..", "data", "league_confidence.json", ) def load_league_confidence() -> Dict[str, Dict[str, Any]]: """ Returns dict mapping league_id → {label, bet_roi, bet_n, hit, name}. Falls back to empty dict if the file is missing/corrupt — callers then treat every league as 'unknown' (no badge), never crashing. """ if not os.path.isfile(_DATA_FILE): print( f"⚠️ league_confidence.json not found at {_DATA_FILE}. " "All leagues will show as 'unknown' confidence." ) return {} try: with open(_DATA_FILE, "r", encoding="utf-8") as f: data = json.load(f) lookup: Dict[str, Dict[str, Any]] = data.get("lookup", {}) print(f"✅ Loaded league confidence labels for {len(lookup)} leagues") return lookup except (json.JSONDecodeError, KeyError, TypeError) as exc: print(f"⚠️ Failed to parse league_confidence.json: {exc}") return {}