diff --git a/fair_prob.py b/fair_prob.py new file mode 100644 index 0000000..484c7c0 --- /dev/null +++ b/fair_prob.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import math + + +def _norm_cdf(z: float) -> float: + # Standard normal CDF via erf (no scipy dependency) + return 0.5 * (1.0 + math.erf(z / math.sqrt(2.0))) + + +def fair_prob_threshold( + *, + spot: float, + strike: float, + sigma_per_second: float, + time_remaining_seconds: float, + resolves_yes_if_spot_ge_strike: bool, +) -> float: + """ + Conservative approximation: + spot(t) ~ Normal(spot, spot*sigma*sqrt(t)) + and compute P(spot_T >= strike) or P(spot_T <= strike). + """ + if spot <= 0 or strike <= 0: + return 0.5 + t = max(1.0, float(time_remaining_seconds)) + sigma = max(1e-9, float(sigma_per_second)) + stdev = spot * sigma * math.sqrt(t) + if stdev <= 0: + return 0.5 + + z = (spot - strike) / stdev + p_ge = _norm_cdf(z) # P(spot_T >= strike) + + fair = p_ge if resolves_yes_if_spot_ge_strike else (1.0 - p_ge) + + # clip away from certainty (tail risk) + return max(0.03, min(0.97, fair))