from __future__ import annotations from dataclasses import dataclass from datetime import datetime from typing import Any @dataclass(frozen=True) class FinishedMatch: match_id: str competition: str utc_date: datetime home: str away: str home_goals: int away_goals: int home_id: str = "" away_id: str = "" home_aliases: tuple[str, ...] = () away_aliases: tuple[str, ...] = () @property def home_key(self) -> str: return f"id:{self.home_id}" if self.home_id else self.home @property def away_key(self) -> str: return f"id:{self.away_id}" if self.away_id else self.away @dataclass(frozen=True) class TeamIdentity: key: str name: str aliases: tuple[str, ...] @dataclass(frozen=True) class MarketConsensus: home_odd: float | None draw_odd: float | None away_odd: float | None home_prob: float | None draw_prob: float | None away_prob: float | None bookmakers: int dispersion: float = 1.0 home_dispersion: float = 1.0 draw_dispersion: float = 1.0 away_dispersion: float = 1.0 stale_bookmakers: int = 0 bookmaker_names: tuple[str, ...] = () @dataclass class Pick: event_id: str kickoff: str competition: str competition_code: str home: str away: str resolved_home_key: str resolved_away_key: str selection: str side: str odd: float probability: float raw_model_probability: float conservative_probability: float market_probability: float fair_odd: float model_ev: float edge: float safe_score: float quality: float reliability: float disagreement: float market_dispersion: float market_bookmakers: int name_confidence: float calibration_delta: float market_move: float label: str reasons: list[str] model_detail: dict[str, float] model_version: str def as_dict(self) -> dict[str, Any]: return self.__dict__.copy()