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

64 lines
1.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""EV期望值運算模組。
本模組提供最基本、可復用的賠率價值判斷邏輯:給定真實勝率與小數賠率,計算期望值與是否為優勢投注。
"""
from __future__ import annotations
from typing import Any
def calculate_expected_value(
true_win_prob: float,
decimal_odds: float,
stake: float = 100.0,
suggested_kelly_fraction: float | None = None,
) -> dict[str, Any]:
"""計算期望值EV並回傳報價建議。
Parameters
----------
true_win_prob:
模型估計的真實勝率,必須在 0 到 1 之間。
decimal_odds:
小數制賠率,必須大於 1否則不具可投注意義
stake:
本次下注本金;同時也是 EV 百分比的基準。
suggested_kelly_fraction:
由外部凱利公式模組預留的建議資金比例;若未提供則回傳 None。
Returns
-------
dict
{
'ev_value': 實際 EV 金額,
'ev_percentage': EV / stake * 100,
'is_value_bet': 當 EV% 大於 3% 時為 True,
'suggested_kelly_fraction': 傳入值或 None
}
"""
if not 0.0 <= true_win_prob <= 1.0:
raise ValueError('true_win_prob 必須介於 0 到 1 之間')
if decimal_odds <= 1:
raise ValueError('decimal_odds 必須大於 1')
if stake <= 0:
raise ValueError('stake 必須大於 0')
win_prob = float(true_win_prob)
odds = float(decimal_odds)
stake_amount = float(stake)
profit_when_win = odds - 1.0
lose_prob = 1.0 - win_prob
ev = win_prob * profit_when_win * stake_amount - lose_prob * stake_amount
ev_percentage = ev / stake_amount * 100
return {
'ev_value': round(ev, 6),
'ev_percentage': round(ev_percentage, 4),
'is_value_bet': ev_percentage > 3.0,
'suggested_kelly_fraction': suggested_kelly_fraction,
}