60 lines
2.0 KiB
Python
60 lines
2.0 KiB
Python
"""Unit tests for V35 market-anchored calibration (pure, no DB/model deps)."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
|
|
from models.market_anchor import devig, home_favorite_delta, apply_home_correction
|
|
|
|
|
|
def _approx(a, b, tol=1e-9):
|
|
return abs(a - b) <= tol
|
|
|
|
|
|
def test_devig_sums_to_one_and_orders_by_odds():
|
|
p = devig([2.0, 3.5, 4.0])
|
|
assert p is not None
|
|
assert _approx(sum(p), 1.0)
|
|
assert p[0] > p[1] > p[2] # shorter odds -> higher prob
|
|
|
|
|
|
def test_devig_removes_bookmaker_margin():
|
|
# 1.61 / 3.15 / 3.77 carries ~20% margin; fair home prob must be BELOW the
|
|
# raw implied 1/1.61, and the three must sum to exactly 1.
|
|
p = devig([1.61, 3.15, 3.77])
|
|
assert p is not None
|
|
assert p[0] < 1.0 / 1.61
|
|
assert _approx(sum(p), 1.0)
|
|
|
|
|
|
def test_devig_rejects_missing_or_placeholder_legs():
|
|
assert devig([1.0, 3.0, 4.0]) is None # 1.0 leg = no real price
|
|
assert devig([None, 3.0, 4.0]) is None # missing leg
|
|
assert devig([1.005, 3.0]) is None # <= 1.01 placeholder
|
|
assert devig([]) is None
|
|
assert devig([1.90, 1.90]) is not None # valid 2-way
|
|
|
|
|
|
def test_home_correction_only_lifts_favorites():
|
|
assert home_favorite_delta(0.30) == 0.0 # underdog/level: no bias
|
|
assert home_favorite_delta(0.50) > 0.0
|
|
assert home_favorite_delta(0.80) >= home_favorite_delta(0.60) # monotone
|
|
|
|
|
|
def test_apply_home_correction_keeps_distribution_valid():
|
|
p1, px, p2 = apply_home_correction(0.70, 0.18, 0.12)
|
|
assert p1 > 0.70 # favourite lifted
|
|
assert _approx(p1 + px + p2, 1.0) # still a valid distribution
|
|
# underdog vector untouched
|
|
q = apply_home_correction(0.30, 0.30, 0.40)
|
|
assert _approx(q[0], 0.30)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
fns = [v for k, v in sorted(globals().items()) if k.startswith("test_")]
|
|
for fn in fns:
|
|
fn()
|
|
print(f"PASS {fn.__name__}")
|
|
print(f"\nAll {len(fns)} tests passed.")
|