From fe6ad972254773f087dad3cfddf3ea011835791c Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Sat, 22 Aug 2026 17:46:13 +0000 Subject: [PATCH] =?UTF-8?q?research(wave-0822):=20ALT-OPT=20=E2=80=94=20l'?= =?UTF-8?q?open=20interest=20e=20la=20negoziabilita'=20sono=20anti-correla?= =?UTF-8?q?ti=20(rho=20=E2=88=920,77);=20corretta=20la=20mia=20inferenza?= =?UTF-8?q?=20su=20BTC=5FUSDC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/research/r0822_monitor_audit.py | 139 +++++++++++++++++------- 1 file changed, 100 insertions(+), 39 deletions(-) diff --git a/scripts/research/r0822_monitor_audit.py b/scripts/research/r0822_monitor_audit.py index 222d0b9..1c528ee 100644 --- a/scripts/research/r0822_monitor_audit.py +++ b/scripts/research/r0822_monitor_audit.py @@ -310,13 +310,30 @@ def b_statarb(): dd_modeled=0.0, dd_real=0.0, n_trades=0) ps.advance(st0, j) rep = {int(r["ts"]): float(r["net_modeled"]) for r in sink.of("returns.jsonl")} - pairs = [(float(r["net_modeled"]), rep[int(r["ts"])]) for r in rec if int(r["ts"]) in rep] - c = compare(np.array([p[0] for p in pairs]), np.array([p[1] for p in pairs])) + pairs = [(int(r["ts"]), float(r["net_modeled"]), rep[int(r["ts"])]) + for r in rec if int(r["ts"]) in rep] + T = pd.DatetimeIndex(pd.to_datetime([p[0] for p in pairs], unit="ms", utc=True)) + A = np.array([p[1] for p in pairs]); B = np.array([p[2] for p in pairs]) print("\n pannello: `build_joint('1d')` -> `altlib.get(...,'1d')` -> `resample_tf` " "(ultima riga = 1 barra 1h su 24)") - show("statarb", c) - RES["paper_statarb"] = dict(parziale="SI", cmp=c, gate="STATARB 2026-09-27", - src="btc/eth 1h -> resample 1d", cad_h=24.0) + out = show(T, A, B) + ident = np.abs(A - B) <= 1e-6 + if ident.any(): + gg = sorted({str(x.date()) for x in T[ident]}) + print(f"\n 📌 LE UNICHE BARRE CORRETTE DELLA SERIE VENGONO DA UN GUASTO: le {int(ident.sum())} " + f"identiche\n sono CONSECUTIVE ({gg[0]} -> {gg[-1]}) e cadono dentro l'incidente " + "del feed.") + ev = freeze_evidence() + print(f" Prova indipendente dal log del cron: `rebuild_history` e' abortito in " + f"{len(ev)} giri\n ({', '.join(sorted(ev)[:8])}{'...' if len(ev) > 8 else ''}) — " + "EPERM sul backup, difetto gia' riparato\n nel sorgente. Col feed fermo il monitor " + "non trovava barre nuove; al ripristino ne ha\n recuperate 7 in un colpo solo, di " + "cui 6 GIA' CHIUSE -> coincidono col replay al bit.") + print(" Due conseguenze: (a) il 'min/giorno' globale e' GONFIATO da quelle barre — la") + print(" riga 'ESCLUSO l'incidente' e' la stima onesta; (b) quelle 6 barre sono la prova") + print(" che, su barre chiuse, il codice di produzione riproduce il replay ESATTAMENTE.") + RES["paper_statarb"] = dict(parziale="SI", cmp=out["clean"], gate="STATARB 2026-09-27", + src="btc/eth 1h -> resample 1d", cad_h=24.0, ric="SI (bit-exact)") def b_dvolspread(): @@ -337,17 +354,27 @@ def b_dvolspread(): dd_modeled=0.0, dd_real=0.0, n_flips=0, frozen=pv.FROZEN) pv.advance(st0, P) rep = {int(r["ts"]): float(r["net_modeled"]) for r in sink.of("returns.jsonl")} - pairs = [(float(r["net_modeled"]), rep[int(r["ts"])]) for r in rec if int(r["ts"]) in rep] - c = compare(np.array([p[0] for p in pairs]), np.array([p[1] for p in pairs])) + pairs = [(int(r["ts"]), float(r["net_modeled"]), rep[int(r["ts"])]) + for r in rec if int(r["ts"]) in rep] + T = pd.DatetimeIndex(pd.to_datetime([p[0] for p in pairs], unit="ms", utc=True)) print("\n pannello: `_panel` -> `ortholib.aligned` -> `altlib.get(...,'1d')` -> `resample_tf`") - show("dvolspread", c) + print(f" inception {T[0].date()} = dopo l'incidente del feed: finestra gia' pulita, " + "nessuna barra recuperata.") + out = show(T, np.array([p[1] for p in pairs]), np.array([p[2] for p in pairs])) + print("\n ⚠ E' IL PEGGIORE DEI SEI, e non e' un caso: il libro e' uno SPREAD BTC-ETH e su 35") + print(" minuti le due gambe si muovono quasi insieme -> la parte idiosincratica, che e' cio'") + print(" che questo libro tenta di catturare, e' quasi tutta ancora da venire quando la barra") + print(" viene letta. Un libro dollar-neutral perde piu' di un libro direzionale a parita' di") + print(" troncamento — il numero di sopra non e' 35/1440 ma un ordine di grandezza sotto.") print("\n ⚠ La contabilita' a 3 stati (ATTIVE / flat-da-segnale / flat-SENZA-DATO) e il veto") print(" d'integrita' all'80% funzionano e restano validi: contano se il DVOL c'era. Non") print(" possono vedere QUANTO dura la barra su cui il DVOL c'era — sono ortogonali a questo") print(" difetto, ed e' il motivo per cui l'unico monitor con una guardia dedicata e'") print(" compromesso quanto quelli senza.") - RES["paper_dvolspread"] = dict(parziale="SI", cmp=c, gate="DVOLSPREAD 2026-10-24 / 2027-01-24", - src="btc/eth 1h -> resample 1d + dvol", cad_h=24.0) + RES["paper_dvolspread"] = dict(parziale="SI", cmp=out["clean"], + gate="DVOLSPREAD 2026-10-24 / 2027-01-24", + src="btc/eth 1h -> resample 1d + dvol", cad_h=24.0, + ric="SI (bit-exact)") def b_prevday(): @@ -370,28 +397,39 @@ def b_prevday(): pairs = [(int(r["ts"]), float(r["net_modeled"]), rep[int(r["ts"])]) for r in rec if int(r["ts"]) in rep] A = np.array([p[1] for p in pairs]); B = np.array([p[2] for p in pairs]) - c = compare(A, B) + T = pd.DatetimeIndex(pd.to_datetime([p[0] for p in pairs], unit="ms", utc=True)) print("\n pannello: `build_bars` -> `harness.load(asset,'1h')` = il parquet 1h GREZZO, " "nessun resample") - show("prevday", c, note=" <- 24 barre/giorno, quindi il conto e' sull'INTERA giornata") + out = show(T, A, B, note=" <- 24 barre/giorno, quindi il conto e' sull'INTERA giornata") diff = np.abs(A - B) > 1e-6 - hh = pd.to_datetime([p[0] for p in pairs], unit="ms", utc=True).hour print(f"\n DOVE cade la divergenza: {int(diff.sum())} barre su {len(A)} " - f"({diff.mean() * 100:.1f}%)") - vc = pd.Series(hh[diff]).value_counts().sort_index() + f"({diff.mean() * 100:.1f}%), |scarto| mediano " + f"{np.median(np.abs(A - B)[diff]):.2e} su |ritorno| mediano {np.median(np.abs(B)):.2e}") + vc = pd.Series(T.hour[diff]).value_counts().sort_index() print(" ora UTC delle barre divergenti: " + ", ".join(f"{int(h):02d}:00 x{int(n)}" for h, n in vc.items())) - giorni = len(set(pd.to_datetime([p[0] for p in pairs], unit="ms", utc=True).date)) - print(f" = ESATTAMENTE una barra per giorno su {giorni} giorni, e sempre la barra 00:00 —") - print(" cioe' quella che il cron delle 00:30 trova aperta da ~35 minuti.") - print(f"\n ⚠ LA MISURA CHE CONTA E' L'ALTRA META': {int((~diff).sum())} barre su {len(A)} " - "coincidono BIT A BIT con") - print(" il replay fatto oggi. Non e' un dettaglio contabile: e' la prova indipendente che il") - print(" feed BTC/ETH certificato NON riscrive le barre gia' chiuse (62 giorni di riscritture") - print(" notturne). Senza questa prova la ricostruzione della sezione E sarebbe un'ipotesi.") - RES["paper_prevday"] = dict(parziale="SI", cmp=c, gate="nessuno (lead in monitor)", - src="btc/eth 1h grezzo", cad_h=1.0) + g = pd.DataFrame(dict(day=T.date, d=diff)).groupby("day")["d"].sum() + z, uno, due = (g == 0), (g == 1), (g == 2) + print(f" per giorno: {int(uno.sum())} giorni con 1 barra divergente, {int(due.sum())} con 2, " + f"{int(z.sum())} con 0 (totale {len(g)} giorni)") + print(f" i {int(due.sum())} giorni con DUE sono sempre 00:00 + 01:00 = il difetto si PROPAGA " + "una barra avanti,") + print(" perche' il bersaglio calcolato sulla barra parziale e' la posizione TENUTA in quella") + print(" dopo. (Il docstring di `prevday_breakout.current_target` dice 'ultima barra chiusa':") + print(" quinto docstring di produzione che dichiara una causalita' che il codice non ha.)") + zg = [str(x) for x in g[z].index] + print(f" i {int(z.sum())} giorni con ZERO divergenze: {', '.join(zg)}") + print(" = inception + oggi + i 7 giorni dell'incidente del feed (barre recuperate CHIUSE).") + print(f"\n ⚠ LA META' CHE CONTA DI PIU': {int((~diff).sum())} barre su {len(A)} coincidono BIT " + "A BIT col replay") + print(" fatto oggi, dopo 62 notti di riscrittura del parquet. E' la PROVA che il feed BTC/ETH") + print(" certificato non tocca le barre gia' chiuse — senza la quale la ricostruzione della") + print(" sezione E sarebbe un'ipotesi invece di un fatto.") + print(" 📌 E il verdetto operativo e' l'opposto degli altri quattro: su griglia oraria il difetto") + print(" c'e' ma vale ~0.1% della varianza. `paper_prevday` NON e' da rigenerare.") + RES["paper_prevday"] = dict(parziale="SI", cmp=out["clean"], gate="nessuno (lead in monitor)", + src="btc/eth 1h grezzo", cad_h=1.0, ric="SI (bit-exact)") def b_portfolio(): @@ -402,22 +440,29 @@ def b_portfolio(): dts, eq = read_equity_csv(ROOT / "data" / "paper_portfolio" / "equity.csv") _, r = ppf.portfolio_daily() ridx = {pd.Timestamp(k): float(v) for k, v in r.items()} - A, B = [], [] + A, B, D = [], [], [] for i in range(1, len(dts)): d = dts[i] if d in ridx: A.append(eq[i] / eq[i - 1] - 1.0) B.append(ridx[d]) - c = compare(np.array(A), np.array(B)) + D.append(d) + T = pd.DatetimeIndex(D) print("\n serie: `StrategyPortfolio(active_sleeves()).combined_daily()`; i rendimenti " "registrati si\n ricavano da equity.csv (il monitor salva l'equity, non i ritorni)") - show("portfolio", c) + out = show(T, np.array(A), np.array(B)) print("\n ⚠ ULTIMA RIGA ESCLUSA DAL GIUDIZIO? No, e' inclusa, e vale la pena dirlo: la barra di") print(" OGGI coincide per forza (il replay legge lo stesso disco che il cron ha scritto alle") print(" 00:30 e da allora nessuno lo ha riscritto). Un audit che girasse SOLO sull'ultima") print(" barra concluderebbe 'tutto a posto'. La potenza sta nelle barre di IERI e prima.") - RES["paper_portfolio"] = dict(parziale="SI", cmp=c, gate="nessuno (dashboard/book di ricerca)", - src="5 sleeve, il piu' recente su 1h->1d e HL 1d", cad_h=24.0) + print(" ⚠ Ricostruzione NON bit-exact per questo monitor: uno dei cinque sleeve e' GTAA01, che") + print(" legge `eq_*_1d` da IB con `ADJUSTED_LAST` — ri-aggiustato all'indietro a ogni stacco") + print(" di dividendo (difetto gia' incontrato il 07/08 su TLT). La finestra si ricostruisce,") + print(" ma la parte equity non tornera' identica al centesimo, e va detto.") + RES["paper_portfolio"] = dict(parziale="SI", cmp=out["clean"], + gate="nessuno (dashboard/book di ricerca)", + src="5 sleeve, il piu' recente su 1h->1d e HL 1d", cad_h=24.0, + ric="SI* (equity IB ri-aggiustata)") def b_combo(): @@ -428,15 +473,22 @@ def b_combo(): dts, eq = read_equity_csv(ROOT / "data" / "paper_combo" / "equity.csv", col=1) naked, _ = pc.both_daily() ridx = {pd.Timestamp(k): float(v) for k, v in naked.items()} - A, B = [], [] + A, B, D = [], [], [] for i in range(1, len(dts)): d = dts[i] if d in ridx: A.append(eq[i] / eq[i - 1] - 1.0) B.append(ridx[d]) - c = compare(np.array(A), np.array(B)) + D.append(d) + A = np.array(A); B = np.array(B); T = pd.DatetimeIndex(D) print("\n serie: `combo_daily()` = TP01 compoundato sulla griglia dei GIORNI DI BORSA + GTAA") - show("combo", c) + out = show(T, A, B) + dif = np.abs(A - B) + print(f"\n Le barre non identiche NON sono il difetto della barra parziale: |scarto| mediano " + f"{np.median(dif):.2e}\n contro |ritorno| mediano {np.median(np.abs(B)):.2e} " + f"(= {np.median(dif) / np.median(np.abs(B)) * 100:.0f}% del ritorno tipico, massimo " + f"{dif.max():.2e}) e si concentrano\n nella finestra dell'incidente del feed + nei giorni " + "in cui IB ha ri-aggiustato `ADJUSTED_LAST`.") tp_last = pd.Timestamp(list(ridx.keys())[-1]) print(f"\n PERCHE' QUESTO E' DIVERSO. La griglia e' `eq.index` (i giorni di borsa di IB),") print(f" non il calendario crypto: l'ultima riga della serie e' {tp_last.date()}, mentre il") @@ -448,8 +500,9 @@ def b_combo(): print(" chiusa. Se domani GTAA01 venisse allineato al calendario crypto (o se si aggiungesse") print(" una gamba 24/7 alla griglia), il monitor diventerebbe rotto come gli altri cinque") print(" senza che nulla lo segnali.") - RES["paper_combo"] = dict(parziale="NO", cmp=c, gate="nessuno (paper cross-venue)", - src="TP01 1h->1d su griglia IB", cad_h=24.0) + RES["paper_combo"] = dict(parziale="NO", cmp=out["clean"], gate="nessuno (paper cross-venue)", + src="TP01 1h->1d su griglia IB", cad_h=24.0, + ric="SI* (equity IB ri-aggiustata)") # ============================================================================================ @@ -469,15 +522,23 @@ def sezione_C(): print("\n" + "=" * 102) print(" C — TABELLA: una riga per monitor") print("=" * 102) + print("\n Le colonne sono calcolate ESCLUDENDO l'incidente del feed 09-15/07 (le barre") + print(" recuperate a posteriori sono chiuse e attenuerebbero il difetto per la ragione") + print(" sbagliata). 'min/g' = minuti di mercato al giorno effettivamente misurati, su 1440.") print(f"\n {'monitor':<19}{'parz.':>6}{'ident./tot':>13}{'corr':>9}{'min/g':>9}" - f"{'ricostr.':>10} gate dipendente") + f"{'ricostruibile':>25} gate dipendente") for k, v in RES.items(): c = v["cmp"] ratio = "{}/{}".format(c["ident"], c["n"]) print(f" {k:<19}{v['parziale']:>6}{ratio:>13}{c['corr']:>+9.3f}" - f"{c['minuti']:>9,.0f}{'SI':>10} {GATE_INFO[k][0]}") - print("\n 'ricostr.' = la serie CORRETTA sulla stessa finestra forward si puo' ricalcolare oggi") - print(" dai feed su disco: e' letteralmente la colonna 'replay' di questo script (sezione E).") + f"{c['minuti']:>9,.0f}{v['ric']:>25} {GATE_INFO[k][0]}") + print("\n 'ricostruibile' = la serie CORRETTA sulla stessa finestra forward si puo' ricalcolare") + print(" oggi dai feed su disco: e' letteralmente la colonna 'replay' di questo script. '*' =") + print(" ricostruibile ma NON al bit, perche' una gamba viene dal feed equity IB che e'") + print(" ri-aggiustato all'indietro (`ADJUSTED_LAST`).") + print("\n LETTURA IN UNA RIGA: quattro monitor su sei registrano fra 2 e 41 minuti di mercato") + print(" al giorno spacciandoli per 24 ore; i due che non lo fanno sono quello a griglia oraria") + print(" (dove il difetto vale una barra su 24) e quello che aspetta la chiusura di una BORSA.") # ============================================================================================