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))