"""Does the volatility->fills effect survive at the TOUCH?

mm_vol_vs_volume.py priced legs at our_ask -- the paper maker's 0-5c ladder
ABOVE the touch. The live maker rests AT the touch. If volatility only helps
when you are asking above the market (because only a price move can reach you),
then the +13pp says nothing about how we actually trade.
"""
import csv, json, statistics, sys
sys.path.insert(0, r'E:\soccer\main')
sys.path.insert(0, r'E:\soccer\research')
import mm_settle as S
from mm_volatility_clean import load_legs, load_movement, CACHE


def _f(x):
    try:
        return float(x)
    except (TypeError, ValueError):
        return None


def load_col(col, lo=0.0, hi=1.0):
    out = {}
    with open(r'E:\soccer\research\mm_paper_quotes.csv',
              encoding='utf-8', errors='replace') as fh:
        for r in csv.DictReader(fh):
            t = r.get('leg_ticker')
            if not t or t in out or not (r.get('ask_size') or '').strip():
                continue
            v = _f(r.get(col))
            if v is not None and lo < v < hi:
                out[t] = v
    return out


legs = load_legs()
mv = load_movement(legs)
touch = load_col('k_ask')
trades = json.load(open(CACHE, encoding='utf-8'))


def run(price_of, label):
    rows = []
    for t, v in legs.items():
        if t not in mv:
            continue
        px = price_of(t, v)
        if px is None:
            continue
        key = f"{t}|{v['ts'].isoformat()}"
        if key not in trades:
            continue
        cum, filled = 0.0, False
        for ts_s, p, c in trades[key]:
            ts = S._pt(ts_s)
            if not ts:
                break
            ko = v['ko']
            if (ts.tzinfo is None) != (ko.tzinfo is None):
                ts = ts.astimezone() if ts.tzinfo else ts.replace(tzinfo=ko.tzinfo)
            if ts >= ko:
                break
            if p >= px - 1e-9:
                cum += c
                if cum > v['queue']:
                    filled = True
                    break
        rows.append({'sd': mv[t]['sd'], 'filled': int(filled),
                     'above': px - (touch.get(t) or px)})
    if len(rows) < 60:
        print(f'{label}: only {len(rows)} legs')
        return
    base = 100.0 * sum(r['filled'] for r in rows) / len(rows)
    med_above = statistics.median(r['above'] for r in rows) * 100
    print(f'\n=== {label} ===')
    print(f'  {len(rows)} legs, base fill {base:.1f}%, '
          f'median {med_above:+.2f}c vs touch')
    sds = sorted(r['sd'] for r in rows)
    q = sds[len(sds) // 2]
    got = []
    for lo, hi, name in ((-1, q, 'calm half'), (q, 9, 'volatile half')):
        sel = [r for r in rows if lo <= r['sd'] < hi]
        f = sum(r['filled'] for r in sel)
        got.append(100.0 * f / len(sel))
        print(f'    {name:>14} {len(sel):>4} legs  {f:>4} filled  '
              f'{100.0*f/len(sel):>6.1f}%')
    print(f'    -> volatility effect: {got[1]-got[0]:+.1f}pp')


run(lambda t, v: v['our_ask'], 'priced at our_ask (paper ladder, 0-5c ABOVE touch)')
run(lambda t, v: touch.get(t), 'priced AT the touch (what the live maker does)')
