Files
2026FIFAWorldCup/platform/backend/app/analytics/referee_analyzer.py

54 lines
1.8 KiB
Python

"""裁判尺度分析器。"""
from __future__ import annotations
from typing import Dict
from .ev_calculator import calculate_expected_value
def calculate_cards_ev(
referee_stats: dict,
match_tension_index: float,
bookmaker_card_line: float,
bookmaker_odds: float,
) -> dict[str, float | bool | str]:
"""判斷裁判/對手張力對紅黃牌盤口的偏差與價值。
依據裁判最近場次平均黃牌數與比賽張力(衝突度)估算
本場真實牌數,並與莊家 O/U 盤口比較。
"""
if bookmaker_odds <= 1:
raise ValueError('bookmaker_odds 必須大於 1')
if bookmaker_card_line <= 0:
raise ValueError('bookmaker_card_line 必須大於 0')
if not 0 <= match_tension_index <= 1:
raise ValueError('match_tension_index 必須在 0~1')
avg_cards = float(referee_stats.get('avg_yellow_cards', 0.0) or 0.0)
penalties_per_game = float(referee_stats.get('penalties_per_game', 0.0) or 0.0)
strictness_index = 20.0 + avg_cards * 1.9 + penalties_per_game * 2.5
# 綜合壓力補正,將裁判嚴厲度與球隊/賽事張力轉為預測牌數。
expected_cards = max(
0.5,
strictness_index * (0.45 + 0.55 * max(0.0, min(match_tension_index, 1.0))),
)
true_prob = min(1.0, max(0.0, expected_cards / (bookmaker_card_line * 1.4)))
implied_prob = 1.0 / bookmaker_odds
edge = true_prob - implied_prob
ev = calculate_expected_value(true_prob, bookmaker_odds, stake=100.0)
return {
'strictness_index': round(strictness_index, 3),
'expected_total_cards': round(expected_cards, 3),
'true_prob': round(true_prob, 4),
'implied_prob': round(implied_prob, 4),
'edge_percent': round(edge * 100, 3),
'is_value_bet': ev['is_value_bet'],
'ev_percentage': ev['ev_percentage'],
}