"""
Does PURE Kalshi-vs-Poly deviation make money, with NO Pinnacle anchor?  NO.

Question (2026-06-29): the unique/overlap edge is always selected by CLV-vs-pin_fair.
Can you instead drop Pinnacle entirely and just trade the two books against EACH OTHER
-- when Kalshi and Poly disagree, bet the cheaper one? Tested here. Answer: it needs
pin_fair. The two-book midpoint is a worse fair than Pinnacle and carries no edge.

Strategy A (PURE X-BOOK): fair := mean(kalshi_mid, poly_price) per side. Bet the
CHEAPER book's side when its x-book CLV (vs that two-book avg) is in [lo,hi). Settle
at the cheaper book's ask (Kalshi ask; Poly est-ask via near-term half-spread). One
bet/fixture (max x-book CLV, first qualifying pre-KO snapshot, non-look-ahead).

RESULTS on poly_backfill (975 resolved fixtures, 2026-06-29):
  A) PURE x-book deviation, NO Pinnacle (bet cheaper book):
       [3,12)% n=180 +1.4% z+0.54  |  >=5% n=67 -23.1% z-0.60  |  >=10% n=21 -52.4% z-1.16
       -> flat-to-negative, and gets MONOTONICALLY WORSE as the deviation widens
          (opposite of a real edge).
  B) FALSIFICATION (bet the DEARER book): also loses (-29% to -42%). Deviation is
     non-directional noise -- neither leg is profitable.
  C) Crux: of 67 pure-dev bets, 57 are ones where Pinnacle ALSO says cheap=cheap, and
     even those lose (-9.6%). The two-book avg is contaminated: when both books are
     cheap vs Pinnacle, their midpoint is cheap too, so dev-from-midpoint never catches
     the real mispricing.
  D) Reference -- the live pin_fair signal on the SAME 975 fixtures: +11.0% ROI,
     25.2% WR, n=421, z+1.26. Positive, on 6x the sample.

VERDICT: Pinnacle (a SHARP book) is the truth anchor doing all the discriminating.
Kalshi & Poly are both soft venues; their mutual disagreement says nothing about which
is right. Pure cross-book deviation is NOT a standalone strategy. Don't reopen unless a
genuinely sharp third reference (not two soft books) is available. Consistent with the
unique/overlap mechanism finding (edge needs the 2nd book to CONFIRM Pinnacle).
Caveat: pure-dev n is small (~63-67 in-band) because the two books usually price within
~1-2c; big divergences are rare and noisy -- itself part of the point.

Read-only, trades nothing. Multiplicative de-vig. Mirrors kalshi_poly_unique_*.py.
"""
import csv, glob, os, math
from datetime import datetime
from collections import defaultdict

DIR = r"E:\soccer\poly_backfill"
_FMTS = ['%Y-%m-%d %H:%M:%S', '%m/%d/%Y %H:%M', '%m/%d/%Y %H:%M:%S', '%Y-%m-%d %H:%M']
def _pts(s):
    for f in _FMTS:
        try: return datetime.strptime(s, f)
        except (ValueError, TypeError): pass
    return None
def _f(x):
    try: return float(x)
    except (TypeError, ValueError): return None
def _result(rows):
    for r in reversed(rows):
        v = (r.get('ftr') or '').upper().strip()
        if v in ('H', 'D', 'A'): return v
    return None
def fair_mult(o):
    r = [1.0/x for x in o]; s = sum(r); return [ri/s for ri in r]
def half_spread(mid):
    if   mid < 0.05: return 0.003
    elif mid < 0.25: return 0.005
    elif mid < 0.35: return 0.025
    return 0.020

def load():
    fixtures = defaultdict(list)
    for path in glob.glob(os.path.join(DIR, "*_polybackfill.csv")):
        with open(path, newline='', encoding='utf-8') as fh:
            for r in csv.DictReader(fh):
                fixtures[(r.get('game_date'), r.get('league'),
                          r.get('home'), r.get('away'))].append(r)
    fx = []
    for key, rows in fixtures.items():
        gd = key[0]
        if not gd: continue
        pre = sorted([(_pts(r['timestamp']), r) for r in rows
                      if (r.get('status') or '').upper() == 'PRE' and _pts(r['timestamp'])],
                     key=lambda t: t[0])
        if not pre: continue
        ftr = _result(rows)
        if ftr is None: continue
        fx.append(dict(gd=gd, ftr=ftr, pre=[r for _, r in pre]))
    fx.sort(key=lambda f: f['gd'])
    return fx

SIDX = {'home': 0, 'away': 2}

def pure_dev_bet(fx, lo, hi):
    """First pre-KO snapshot with a qualifying x-book deviation. Bet cheaper book.
    Returns dict or None."""
    for r in fx['pre']:
        ph, pd_, pa = _f(r.get('pin_home')), _f(r.get('pin_draw')), _f(r.get('pin_away'))
        pin_ok = not (None in (ph, pd_, pa)) and ph > 1 and pd_ > 1 and pa > 1
        pf_all = fair_mult((ph, pd_, pa)) if pin_ok else None
        cands = []
        for side, sidx in SIDX.items():
            k_mid = _f(r.get(f'kalshi_{side}_mid')); k_ask = _f(r.get(f'kalshi_{side}_ask'))
            p_px  = _f(r.get(f'poly_{side}_price'))
            if k_mid is None or p_px is None: continue
            if not (0 < k_mid < 1 and 0 < p_px < 1): continue
            xfair = (k_mid + p_px) / 2.0
            # cheaper book on this side
            if k_mid <= p_px:
                book, mid, px = 'kalshi', k_mid, (k_ask if k_ask and 0 < k_ask < 1 else k_mid)
            else:
                book, mid, px = 'poly', p_px, p_px + half_spread(p_px)
            xclv = (xfair - mid) / xfair if xfair else None
            if xclv is None or not (lo <= xclv < hi): continue
            won = (fx['ftr'] == 'H' and side == 'home') or (fx['ftr'] == 'A' and side == 'away')
            pin_clv = ((pf_all[sidx] - mid) / pf_all[sidx]) if pf_all else None
            cands.append(dict(xclv=xclv, side=side, book=book, px=px, won=won, pin_clv=pin_clv))
        if cands:
            return max(cands, key=lambda d: d['xclv'])
    return None

def stat(bets):
    n = len(bets)
    if not n: return None
    wins = sum(b['won'] for b in bets)
    net = sum(((1-b['px'])/b['px']) if b['won'] else -1.0 for b in bets)
    mu = sum(b['px'] for b in bets); var = sum(b['px']*(1-b['px']) for b in bets)
    z = (wins-mu)/math.sqrt(var) if var > 0 else 0.0
    p = 0.5*math.erfc(z/math.sqrt(2))
    return dict(n=n, wr=wins/n*100, roi=net/n*100, z=z, p=p)

def line(tag, s):
    if not s: print(f"  {tag:40s} (no bets)"); return
    print(f"  {tag:40s} n={s['n']:3d}  WR={s['wr']:4.1f}%  ROIturn={s['roi']:+6.1f}%  "
          f"z={s['z']:+.2f}  p={s['p']:.3f}")

def main():
    fx = load()
    print(f"resolved fixtures with PRE snapshots: {len(fx)}\n")

    print("=== A) PURE X-BOOK DEVIATION (fair = mean of the two books, NO Pinnacle) ===")
    print("    band sweep on x-book CLV (bet cheaper book @ its ask):")
    for lo, hi in [(0.03, 0.12), (0.05, 0.12), (0.05, 0.20), (0.05, 1.0), (0.08, 1.0), (0.10, 1.0)]:
        bets = [b for b in (pure_dev_bet(f, lo, hi) for f in fx) if b]
        line(f"x-book CLV in [{lo:.2f},{hi:.2f})", stat(bets))

    print("\n=== B) FALSIFICATION: same fixtures, bet the DEARER book instead ===")
    def dearer_bet(fx, lo, hi):
        for r in fx['pre']:
            cands = []
            for side in SIDX:
                k_mid = _f(r.get(f'kalshi_{side}_mid')); p_px = _f(r.get(f'poly_{side}_price'))
                if k_mid is None or p_px is None or not (0<k_mid<1 and 0<p_px<1): continue
                xfair = (k_mid+p_px)/2
                if k_mid >= p_px:
                    mid, px = k_mid, (_f(r.get(f'kalshi_{side}_ask')) or k_mid)
                else:
                    mid, px = p_px, p_px+half_spread(p_px)
                xclv = (mid - xfair)/xfair  # positive = this book DEARER
                if not (lo <= xclv < hi): continue
                won = (fx['ftr']=='H' and side=='home') or (fx['ftr']=='A' and side=='away')
                cands.append(dict(xclv=xclv, px=px, won=won))
            if cands: return max(cands, key=lambda d: d['xclv'])
        return None
    for lo, hi in [(0.05, 0.12), (0.05, 1.0)]:
        bets = [b for b in (dearer_bet(f, lo, hi) for f in fx) if b]
        line(f"bet DEARER book, dev in [{lo:.2f},{hi:.2f})", stat(bets))

    print("\n=== C) DOES IT NEED PINNACLE? split pure-dev bets by pin_fair agreement ===")
    bets = [b for b in (pure_dev_bet(f, 0.05, 1.0) for f in fx) if b]
    have_pin = [b for b in bets if b['pin_clv'] is not None]
    pin_agree = [b for b in have_pin if b['pin_clv'] > 0]      # Pinnacle ALSO says cheap book is cheap
    pin_disag = [b for b in have_pin if b['pin_clv'] <= 0]     # Pinnacle says cheap book is fair/expensive
    line("ALL pure-dev (x-book CLV>=5%)", stat(bets))
    line("  + Pinnacle AGREES (pin_clv>0)", stat(pin_agree))
    line("  + Pinnacle DISAGREES (pin_clv<=0)", stat(pin_disag))

    print("\n=== D) reference: PIN_FAIR signal on same fixtures (the live strategy) ===")
    def pin_bet(fx, lo=0.05, hi=0.12):
        for r in fx['pre']:
            ph, pd_, pa = _f(r.get('pin_home')), _f(r.get('pin_draw')), _f(r.get('pin_away'))
            if None in (ph,pd_,pa) or not (ph>1 and pd_>1 and pa>1): continue
            pf = fair_mult((ph,pd_,pa))
            cands = []
            for side, sidx in SIDX.items():
                k_mid = _f(r.get(f'kalshi_{side}_mid')); k_ask = _f(r.get(f'kalshi_{side}_ask'))
                if k_mid is None or not (0<k_mid<1): continue
                clv = (pf[sidx]-k_mid)/pf[sidx]
                if not (lo<=clv<hi): continue
                won = (fx['ftr']=='H' and side=='home') or (fx['ftr']=='A' and side=='away')
                cands.append(dict(clv=clv, px=(k_ask if k_ask and 0<k_ask<1 else k_mid), won=won))
            if cands: return max(cands, key=lambda d: d['clv'])
        return None
    line("Kalshi CLV vs pin_fair [5,12) @ask", stat([b for b in (pin_bet(f) for f in fx) if b]))

if __name__ == '__main__':
    main()
