"""CROSS-CHECK MULTI-FONTE — "chi ci dice che Binance e' corretto?"

Risponde col numero, non con la fede: scarica BTC/ETH 1h da 4 venue INDIPENDENTI
(Binance USDT, Coinbase USD, Kraken USD, Deribit perp mainnet REALE via ccxt),
li allinea per timestamp e misura di quanto divergono dal CONSENSO (mediana cross-venue).

Due finestre:
  A) regime CALMO recente  -> baseline di concordanza
  B) STRESS depeg USDT (mag 2022) -> dove l'assunzione "Binance=verita'" si crepa
     (BTC/USDT != BTC/USD quando USDT perde il peg; noi eseguiamo USDC)

NON modifica nulla. Solo lettura + report. Deribit via ccxt = API pubblica MAINNET (reale).

    uv run python scripts/analysis/multi_source_check.py
"""
from __future__ import annotations
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
import numpy as np
import pandas as pd
import ccxt

TF = "1h"
TF_MS = 60 * 60 * 1000

# (label, ccxt_id, {asset: symbol}, per_request_limit)
SOURCES = [
    ("binance(USDT)", "binance",  {"BTC": "BTC/USDT", "ETH": "ETH/USDT"}, 1000),
    ("okx(USDT)",     "okx",      {"BTC": "BTC/USDT", "ETH": "ETH/USDT"}, 100),
    ("coinbase(USD)", "coinbase", {"BTC": "BTC/USD",  "ETH": "ETH/USD"},  300),
    ("kraken(USD)",   "kraken",   {"BTC": "BTC/USD",  "ETH": "ETH/USD"},  720),
    ("deribit(perp)", "deribit",  {"BTC": "BTC/USD:BTC", "ETH": "ETH/USD:ETH"}, 1000),
]

WINDOWS = [
    ("CALMO recente",   "2026-04-15", "2026-05-27"),
    ("STRESS depeg USDT","2022-05-08", "2022-05-16"),
]


def _ex(eid):
    return getattr(ccxt, eid)({"enableRateLimit": True})


def fetch(eid, symbol, start_ms, end_ms, limit):
    """OHLCV 1h paginato -> dict ts_ms -> close. Tollerante agli errori per-venue."""
    try:
        ex = _ex(eid)
        ex.load_markets()
    except Exception as e:
        return None, f"load_markets {type(e).__name__}: {str(e)[:60]}"
    if symbol not in ex.markets:
        # prova l'id grezzo (es. BTC-PERPETUAL) come fallback
        alt = symbol.split("/")[0] + "-PERPETUAL"
        symbol = alt if alt in ex.markets else symbol
    out, since, last_err = {}, start_ms, None
    while since <= end_ms:
        try:
            rows = ex.fetch_ohlcv(symbol, TF, since=since, limit=limit)
        except Exception as e:
            last_err = f"{type(e).__name__}: {str(e)[:60]}"
            break
        if not rows:
            break
        for r in rows:
            t = int(r[0])
            if start_ms <= t <= end_ms and r[4]:
                out[t] = float(r[4])
        nxt = int(rows[-1][0]) + TF_MS
        if nxt <= since:
            break
        since = nxt
        if len(rows) < limit and since > end_ms:
            break
    if not out:
        return None, last_err or "no-data (storia non servita dalla venue)"
    return out, None


def analyze(asset, wname, start, end):
    start_ms = int(pd.Timestamp(start, tz="UTC").timestamp() * 1000)
    end_ms = int(pd.Timestamp(end, tz="UTC").timestamp() * 1000)
    series, notes = {}, {}
    for label, eid, syms, lim in SOURCES:
        d, err = fetch(eid, syms[asset], start_ms, end_ms, lim)
        if d:
            series[label] = pd.Series(d, name=label)
        else:
            notes[label] = err
    if len(series) < 2:
        print(f"  {asset} [{wname}] insufficienti venue ({list(series)}) — {notes}")
        return
    df = pd.concat(series.values(), axis=1, join="inner").sort_index()
    if len(df) == 0:
        print(f"  {asset} [{wname}] nessun timestamp comune fra {list(series)}")
        return
    cons = df.median(axis=1)                       # consenso = mediana cross-venue
    print(f"\n  {asset}  [{wname}]   barre comuni={len(df)}  venue={len(df.columns)}")
    if notes:
        for k, v in notes.items():
            print(f"      (assente: {k} — {v})")
    print(f"      {'venue':<15s}{'med.bps':>9s}{'p95.bps':>9s}{'max.bps':>9s}"
          f"{'>10bps':>8s}{'>50bps':>8s}")
    for col in df.columns:
        dev = (df[col] - cons).abs() / cons * 1e4   # bps di scostamento dal consenso
        print(f"      {col:<15s}{dev.median():>9.1f}{dev.quantile(.95):>9.1f}"
              f"{dev.max():>9.1f}{(dev>10).mean()*100:>7.1f}%{(dev>50).mean()*100:>7.1f}%")
    # spread max-min fra venue, barra per barra (quanto e' "largo" il disaccordo)
    spread = (df.max(axis=1) - df.min(axis=1)) / cons * 1e4
    print(f"      -> spread cross-venue (max-min): med {spread.median():.1f} bps, "
          f"p95 {spread.quantile(.95):.1f} bps, max {spread.max():.1f} bps")


def main():
    print("=" * 78)
    print("  CROSS-CHECK MULTI-FONTE — scostamento dal CONSENSO (mediana cross-venue), in bps")
    print("  1 bps = 0.01%.  'Binance corretto' == vicino al consenso di venue indipendenti?")
    print("=" * 78)
    for wname, start, end in WINDOWS:
        print(f"\n--- FINESTRA: {wname}  ({start} -> {end}) ---")
        for asset in ("BTC", "ETH"):
            analyze(asset, wname, start, end)


if __name__ == "__main__":
    main()
