"""凱利準則(Kelly Criterion)工具。""" from __future__ import annotations from dataclasses import dataclass @dataclass(frozen=True) class KellyResult: """凱利投注建議結果。""" decimal_odds: float win_probability: float raw_kelly_fraction: float fractional_kelly_factor: float risk_tolerance_factor: float final_fraction: float stake_fraction: float def calculate_kelly_fraction( decimal_odds: float, true_prob: float, *, bankroll: float, fractional_kelly_factor: float = 1.0, risk_tolerance_factor: float = 1.0, ) -> KellyResult: """依凱利準則估算下注比例與建議金額。 凱利公式: f* = (b * p - q) / b 其中 b = odds - 1,p 為勝率,q = 1 - p。 """ if decimal_odds <= 1: raise ValueError('decimal_odds 必須大於 1') if bankroll <= 0: raise ValueError('bankroll 必須大於 0') if not 0 <= true_prob <= 1: raise ValueError('true_prob 需介於 0 到 1') if not 0 <= fractional_kelly_factor <= 5: raise ValueError('fractional_kelly_factor 須介於 0 到 5') if not 0 <= risk_tolerance_factor <= 2: raise ValueError('risk_tolerance_factor 須介於 0 到 2') b = decimal_odds - 1 raw_kelly = (b * true_prob - (1 - true_prob)) / b final_fraction = raw_kelly * fractional_kelly_factor * risk_tolerance_factor # 保守處理:避免負值與超過總資金比例(100%)的極端輸出。 final_fraction = max(0.0, min(final_fraction, 1.0)) return KellyResult( decimal_odds=decimal_odds, win_probability=true_prob, raw_kelly_fraction=raw_kelly, fractional_kelly_factor=fractional_kelly_factor, risk_tolerance_factor=risk_tolerance_factor, final_fraction=final_fraction, stake_fraction=final_fraction, ) __all__ = ['KellyResult', 'calculate_kelly_fraction']