diff --git a/docs/research/RESULTS-0822.md b/docs/research/RESULTS-0822.md index 146a894..d2ec17c 100644 --- a/docs/research/RESULTS-0822.md +++ b/docs/research/RESULTS-0822.md @@ -693,6 +693,7 @@ stessi hanno nominato senza poterli eseguire**. Stesso contratto di consegna, st | # | filone | domanda che decide | verdetto | |---|---|---|---| | 21 | XS01-OOS | il vantaggio del PROP-ALLOC poggia sul drift di XS01 misurato sulla sua finestra di scoperta: regge fuori? | **LEAD** — regge, ed e' PIU' GRANDE fuori | +| 28 | DEPEG | il falsificatore che l'autore di 21 ha nominato contro se stesso: il depeg USDT contamina il ranking? | **SOPRAVVIVE** — il venue sposta 0,01 di Sharpe | | 22 | MAKER | l'esecuzione passiva e' una fonte di ritorno, al netto del costo di non essere eseguiti? | **SCARTATO** — il segno dipende da `<` contro `<=` | | 23 | BOCPD | un rilevatore di cambio di regime vero batte il miglior lookback COSTANTE? | **SCARTATO** — filone chiuso definitivamente | | 24 | CRITICO | cosa NON e' stato misurato, e quale singola misura mancante vale di piu' | **3 correzioni all'ondata**, 1 regola mia ritirata | @@ -1094,3 +1095,65 @@ verificato contro l'osservato su **6.578 coppie: |errore| mediano 0,023%, p95 0, 1,000000** → rende la superficie utilizzabile su tutti i 75 giorni invece che 23. ✅ **Terza convergenza indipendente sul muro del dato** (75 giorni di superficie); e lo **smile** — che i filoni SKEW/TERM non usavano — esiste invece su **113 giorni dal 2026-05-01**. + +--- + +## 28 — DEPEG (il falsificatore di XS01-OOS, eseguito) + +`scripts/research/r0822b_depeg.py` (811 righe, **18 s**, offline dalla cache, **due corse +byte-identiche**). **112 configurazioni**, e **nessuna e' una selezione**: e' un confronto **appaiato** +dello stesso meccanismo congelato su due fonti di prezzo. + +**Perche':** l'autore di §21 aveva dichiarato contro se stesso che la sua validazione di venue gira +**solo sul 2024+**, cioe' proprio il periodo **senza depeg USDT**, mentre il fuori campione contiene +il **maggio 2022**. La soglia — `corr fra i due sleeve >= 0,99` — era **dichiarata da lui, non +dall'esecutore del test**. + +**Il dato, e il primo limite:** su 13 asset **10 hanno un prezzo USD** che copre la finestra (9 +Coinbase + **XRP da Bitstamp**, perche' Coinbase l'aveva sospeso). **BNB non esiste in USD prima del +2025-10** — e' il token nativo del venue sotto esame. AVAX parte 2021-09-30 → il test **non copre il +2021**, ma copre **esattamente cio' che l'obiezione nomina: maggio 2022 e FTX**. + +📌 **Divergenza SCOMPOSTA nelle due componenti che sono domande diverse** (824 giorni, 8.240 +osservazioni appaiate): **(a) comune** med 3,2 bps / max 76,7 — quella che lo z-score annulla; +**(b) idiosincratica** med **2,1 bps** / p95 11,2 / max 116,5 — quella che cambia il ranking. +Nel depeg (07→20 maggio 2022) il comune arriva a **−39 bps** ma l'idiosincratico sale solo a med +**3,6** / max **33,8 bps** contro 2,0 / 10,9 fuori. + +**TEST 1** (meccanismo congelato, 10 asset, 10 fasi, 2021-09→2023-12): **corr mediana 0,9992, minima +0,9921 → PASS**; **dSharpe appaiato −0,000** [−0,056, +0,036]; divario di equity cumulato su 2,25 +anni **+0,07%**. **Il canale del danno, guardato direttamente:** 734 ribilanciamenti, **10 con gambe +diverse (1,36%)**, tutti a sovrapposizione 4/5, **ZERO dentro la finestra del depeg**; Spearman dello +score mediana **1,0000**. +**TEST 2** (finestra intera di §21): il numero di testa **+1,12 → +1,11**, delta appaiato −0,003. + +**VERDETTO: `IL RISULTATO XS01-OOS: SOPRAVVIVE`** — il venue sposta il titolo di §21 di **0,01 di +Sharpe** e **non cambia una sola gamba dentro il depeg**. +**Controllo positivo girato** (obbligatorio, o "corr 0,99" potrebbe essere uno sfasamento): USD +ritardato di 1 giorno → corr mediana **−0,011**. + +**Tre cose trovate che vanno registrate:** +1. 📌 **L'unica corr sotto soglia e' ATTRIBUITA, e non e' il prezzo.** Col **gate di dispersione + spento** su entrambi i venue la minima passa **0,9674 → 0,9977**. Il gate `disp >= percentile` e' + **binario**, quindi pochi bps cadono ai due lati → **4 intervalli da 10 giorni** in cui uno sleeve + e' pieno e l'altro **flat**, piu' una coda di ~30 giorni in cui la `rv30` del vol-target resta + diversa. **Una scansione di ranking non lo vede.** ✅ Converge con §21 (*"il gate p30 fuori campione + vale ZERO"*): **non porta edge e amplifica il rumore** — ⚠️ non e' una proposta di cambiarlo, + cambiarlo guardando questo numero sarebbe selezione. +2. 🚨 **Il caso peggiore dell'intero campione NON e' il depeg: e' il 2025-10-10** (cascata di + liquidazioni sulle coppie /USDT) — **INJ 1.981 bps**, ADA 315, LTC 201, AAVE 136 mentre BTC/ETH + stanno a 21-22. **Il meccanismo temuto dall'obiezione e' REALE**; semplicemente non e' accaduto nel + 2021-2023 ed e' caduto nella finestra di **scoperta**, non nel fuori campione. Nel depeg le + peggiori divergenze sono **AVAX subito dopo la quotazione = book sottile, non stablecoin**. +3. ⚠️ **BNB resta non controllabile** e toglierlo costa **−0,75** di mediana di fase (+1,12 → +0,37) + — ✅ **replica esatta del leave-one-out di §21 con implementazione separata**. Contesto onesto: + nella LOO di §21 **LTC (+0,20), BTC (+0,33) e XRP (+0,33) pesano di piu'**, e quelle tre **sono + coperte** dal controllo USD. + +**Smentitore residuo dichiarato:** la divergenza del 2025-10-10 e' di **chiusura**; un evento +**intra-giornaliero** della stessa natura sposterebbe il ranking **senza lasciare traccia sulle +chiusure**, e i close giornalieri non lo vedrebbero. + +⚠️ *Nota di attribuzione: il file risultava `M` in git perche' **io** (coordinatore) l'avevo incluso +in un commit mentre l'agente ci stava ancora lavorando — non un altro agente. Un `git add -A` durante +un'ondata cattura il lavoro in corso.* diff --git a/scripts/research/r0822b_depeg.py b/scripts/research/r0822b_depeg.py index 0c4a413..d9dd013 100644 --- a/scripts/research/r0822b_depeg.py +++ b/scripts/research/r0822b_depeg.py @@ -191,7 +191,12 @@ def certify_usd(asset: str, d: pd.DataFrame, a: str, b: str) -> dict: flat=float("nan"), zero_vol=float("nan")) v = series_of(d.assign(close=d["volume"])) v = v[(v.index >= pd.Timestamp(a, tz="UTC")) & (v.index < pd.Timestamp(b, tz="UTC"))] - attesi = (pd.Timestamp(b, tz="UTC") - s.index.min()).days + # ⚠️ la copertura si misura sulla finestra RICHIESTA, non sulla prima barra disponibile: + # contando dal proprio inizio, un asset quotato a meta' finestra esce con gap=0 e "OK", e il + # conteggio degli usabili contraddirebbe la riga sotto che lo esclude. E' lo stesso difetto + # che il progetto ha gia' incontrato due volte (serie TRONCATA che passa ogni controllo + # interno): un controllo che guarda solo DENTRO la serie non vede cio' che la serie non copre. + attesi = (pd.Timestamp(b, tz="UTC") - pd.Timestamp(a, tz="UTC")).days c = s.values flat = float(np.mean(c[1:] == c[:-1])) if len(c) > 1 else float("nan") zv = float(np.mean(v.values == 0.0)) if len(v) else float("nan") @@ -294,19 +299,83 @@ def ranking_scan(PB: pd.DataFrame, PU: pd.DataFrame, phases: list[int], if ov < 1.0: diff = sorted(set(PB.columns[list(hiB ^ hiU)]) | set(PB.columns[list(loB ^ loU)])) rows.append(dict(fase=ph, data=PB.index[i], overlap=ov, gambe=",".join(diff))) - D = pd.DataFrame(rows) + D = pd.DataFrame(rows, columns=["fase", "data", "overlap", "gambe"]) print(f" [{label}] {tot} ribilanciamenti su {len(phases)} fasi; specchio verificato " f"contro il motore in {checked}/{checked} con posizione") print(f" [{label}] Spearman dello score fra i venue: mediana {np.median(sp):.4f} " f"min {np.min(sp):.4f}") print(f" [{label}] ribilanciamenti con gambe DIVERSE: {len(D)}/{tot} " f"({len(D)/max(tot,1)*100:.2f}%)") - for _, r in D.iterrows(): - print(f" fase {int(r['fase'])} {r['data'].date()} " - f"sovrapposizione {r['overlap']*100:3.0f}% gambe scambiate: {r['gambe']}") + if len(D): + pre = D[D["data"] < pd.Timestamp(T2_END, tz="UTC")] + print(f" [{label}] di cui NELLA finestra fuori campione ({T2_START}..{T2_END}): " + f"{len(pre)} — elencati qui sotto; quelli dal 2024 in poi non sono la domanda") + for _, r in pre.iterrows(): + print(f" fase {int(r['fase'])} {r['data'].date()} " + f"sovrapposizione {r['overlap']*100:3.0f}% gambe scambiate: {r['gambe']}") return D +def gate_flips(PB: pd.DataFrame, PU: pd.DataFrame, ph: int) -> list[tuple]: + """Il SECONDO canale, che una scansione di ranking non vede: il gate di dispersione e' BINARIO + (`disp_i >= percentile espandente`) e quindi DISCONTINUO — due prezzi che differiscono di + pochi bps possono cadere ai due lati della soglia, e allora uno sleeve resta pienamente + investito per 10 giorni mentre l'altro sta FLAT. Non e' un cambio di ranking: e' un + interruttore. Ritorna gli intervalli in cui i due venue non sono d'accordo su acceso/spento.""" + dB: dict = {} + dU: dict = {} + X.xsec_engine(PB, phase=ph, detail=dB) + X.xsec_engine(PU, phase=ph, detail=dU) + gb = np.abs(dB["W"]).sum(axis=1) > 1e-9 + gu = np.abs(dU["W"]).sum(axis=1) > 1e-9 + idx = PB.index + flip = np.flatnonzero(gb != gu) + runs, i0 = [], None + for j, i in enumerate(flip): + if i0 is None: + i0 = i + if j + 1 == len(flip) or flip[j + 1] != i + 1: + runs.append((idx[i0], idx[i], int(i - i0 + 1), bool(gb[i0]))) + i0 = None + return runs + + +def autopsia(PB: pd.DataFrame, PU: pd.DataFrame, ph: int, D: pd.DataFrame, label: str) -> None: + """La fase con la corr piu' bassa NON si riassume, si guarda: una corr di 0,97 o e' un + ribaltamento di ranking (il guasto che sto cercando) o e' un singolo giorno di rumore su una + gamba sottile (che non e' un guasto). Sono conclusioni opposte a partire dallo stesso numero.""" + a, b = pair(alive(X.xsec_engine(PU, phase=ph)), alive(X.xsec_engine(PB, phase=ph))) + g = (a - b) + top = g.abs().sort_values(ascending=False).head(4) + dph = D[D["fase"] == ph] if len(D) else D + runs = gate_flips(PB, PU, ph) + print(f" autopsia della fase peggiore ({label}, fase {ph}): i 4 giorni di scarto maggiore") + for t, v in top.items(): + prev = dph[dph["data"] <= t]["data"] + near = (t - prev.iloc[-1]).days if len(prev) else None + inflip = [r for r in runs if r[0] <= t <= r[1]] + # ⚠️ la coda: dopo una discordanza del gate uno dei due sleeve ha 10 giorni di ZERI in + # piu' nella finestra rv30 del vol-target -> la LEVA dei due resta diversa per ~30 giorni + # dopo che la discordanza e' finita. Chiamare "rumore di prezzo" un giorno dentro quella + # coda attribuirebbe al venue un effetto che e' della soglia binaria. + tail = [r for r in runs if r[1] < t and (t - r[1]).days <= 30] + if inflip: + r = inflip[0] + tag = (f"GATE DISCORDE {r[0].date()}..{r[1].date()}: " + f"{'USDT investito, USD flat' if r[3] else 'USD investito, USDT flat'}") + elif tail: + tag = (f"coda del vol-target: gate discorde fino al {tail[-1][1].date()}, " + f"{(t - tail[-1][1]).days}g fa -> rv30 diversa, LEVA diversa") + elif near is not None and near <= XS_CFG["H"]: + tag = f"ultimo ribilanciamento con gambe diverse {near} giorni prima" + else: + tag = "stesse gambe, stesso gate: solo rumore di prezzo" + print(f" {t.date()} scarto {g.loc[t]*1e4:+8.0f} bps ({tag})") + print(f" scarto quadratico totale della fase: {float((g**2).sum())**0.5*1e4:.0f} bps; " + f"i 4 giorni sopra ne spiegano " + f"{float((top**2).sum())/float((g**2).sum())*100:.0f}%") + + def score_at(P: pd.DataFrame, i: int, lookbacks) -> tuple[np.ndarray, np.ndarray]: """Specchio della riga di score del motore (z-score medio sui lookback). Serve per confrontare i RANKING fra venue; la sezione [4] verifica che i top-k/bottom-k che ne derivano coincidano @@ -494,6 +563,35 @@ def main() -> None: (D1["data"] < pd.Timestamp(DEPEG[1], tz="UTC"))] print(f" di cui dentro la finestra del depeg: {len(ind)}") + # ---------------------- [4b] il SECONDO canale: il gate binario, e l'attribuzione + print("\n[4b] IL GATE DI DISPERSIONE E' UN INTERRUTTORE — e una scansione di ranking non lo") + print(" vede. `disp_i >= percentile espandente` e' una soglia: pochi bps di differenza di") + print(" prezzo possono cadere ai due lati, e per 10 giorni uno sleeve e' pieno e l'altro") + print(" e' FLAT. E' l'unico modo in cui una differenza di venue microscopica puo'") + print(" produrre una differenza di P&L macroscopica.") + for label_, Pb_, Pu_ in (("TEST 1 / U10", PB, PU),): + tot_fl = 0 + for ph in PHASES: + for a_, b_, nd, bfirst in gate_flips(Pb_, Pu_, ph): + tot_fl += 1 + print(f" [{label_}] fase {ph}: {a_.date()} .. {b_.date()} ({nd}g) — " + f"{'USDT investito / USD FLAT' if bfirst else 'USD investito / USDT FLAT'}") + if tot_fl == 0: + print(f" [{label_}] nessuna discordanza del gate su 10 fasi") + else: + print(f" [{label_}] {tot_fl} intervalli di discordanza su 10 fasi") + + print("\n ATTRIBUZIONE — stesso confronto con il gate SPENTO su ENTRAMBI i venue") + print(" (diagnostica, NON una proposta di cambiare il meccanismo: serve a separare") + print(" 'il prezzo e' diverso' da 'la soglia binaria amplifica una differenza minuscola'):") + cg = [] + for ph in PHASES: + a_, b_ = pair(alive(X.xsec_engine(PU, phase=ph, disp_pct=0)), + alive(X.xsec_engine(PB, phase=ph, disp_pct=0))) + cg.append(float(a_.corr(b_))) + print(f" [TEST 1] corr con gate SPENTO: mediana {np.median(cg):.4f} minima {np.min(cg):.4f}" + f" (col gate acceso: mediana {R['corr'].median():.4f}, minima {R['corr'].min():.4f})") + # ------------------------------- [5] TEST 2 — U13 ibrido, finestra INTERA di §21 print(f"\n[5] TEST 2 — U13 IBRIDO (USD dove esiste, USDT altrove), {T2_START} .. {T2_END}") print(" Domanda operativa: sostituendo TUTTO il prezzo in dollari che esiste, il titolo") @@ -537,6 +635,24 @@ def main() -> None: print("\n E il ranking, sull'ibrido (la fase con la corr piu' bassa va GUARDATA, non") print(" riassunta: una corr di 0,97 su una fase o e' un ribaltamento vero o e' un giunto):") D2 = ranking_scan(PBh, PUh, PHASES, "TEST 2 / U13-IBRIDO") + print("\n Discordanze del GATE binario sull'ibrido (finestra fuori campione):") + nfl = 0 + for ph in PHASES: + for a_, b_, nd, bfirst in gate_flips(PBh, PUh, ph): + if a_ >= pd.Timestamp(T2_END, tz="UTC"): + continue + nfl += 1 + print(f" fase {ph}: {a_.date()} .. {b_.date()} ({nd}g) — " + f"{'USDT investito / USD FLAT' if bfirst else 'USD investito / USDT FLAT'}") + print(f" totale {nfl} intervalli su 10 fasi (su ~204 ribilanciamenti per fase)") + cg2 = [] + for ph in PHASES: + a_, b_ = pair(win(alive(X.xsec_engine(PUh, phase=ph, disp_pct=0)), T2_START, T2_END), + win(alive(X.xsec_engine(PBh, phase=ph, disp_pct=0)), T2_START, T2_END)) + cg2.append(float(a_.corr(b_))) + print(f" ATTRIBUZIONE [TEST 2] corr con gate SPENTO: mediana {np.median(cg2):.4f} " + f"minima {np.min(cg2):.4f} (col gate acceso: mediana {R2['corr'].median():.4f}, " + f"minima {R2['corr'].min():.4f})") # ------------------------------- [5b] le gambe che NESSUN venue USD puo' controllare print("\n[5b] LE TRE GAMBE NON CONTROLLABILI — quanto del risultato di §21 ci passa?") @@ -588,15 +704,44 @@ def main() -> None: f"T2 fase {int(worst2['ph'])} corr {worst2['corr']:.4f}") print(f" peggior FASE per dSharpe: T1 fase {int(wd1['ph'])} {wd1['d']:+.3f} | " f"T2 fase {int(wd2['ph'])} {wd2['d']:+.3f}") + autopsia(PB, PU, int(worst1["ph"]), D1, "TEST 1") + autopsia(PBh, PUh, int(worst2["ph"]), D2, "TEST 2") st = idio.abs().stack().sort_values(ascending=False) - print(" le 8 divergenze IDIOSINCRATICHE piu' grandi della finestra (bps di livello):") + print(" le 8 divergenze IDIOSINCRATICHE piu' grandi della finestra del TEST 1 (bps):") for (t, s), v in st.head(8).items(): indep = "DEPEG" if pd.Timestamp(DEPEG[0], tz="UTC") <= t < pd.Timestamp(DEPEG[1], tz="UTC") else "" print(f" {str(t.date()):<12}{s:<6}{v:8.0f} bps (comune quel giorno " f"{common.loc[t]:+.0f} bps) {indep}") - print(" -> se le peggiori NON cadono nel depeg, il rumore di venue e' book sottile,") - print(" non contaminazione da stablecoin: due cause diverse, due implicazioni diverse.") + print(" -> le peggiori NON cadono nel depeg e sono quasi tutte AVAX nelle settimane subito") + print(" dopo la sua quotazione su Coinbase: book sottile, non contaminazione da") + print(" stablecoin. Due cause diverse e due implicazioni diverse.") + + # --------- il caso peggiore su TUTTO il campione, non solo sulla finestra del test + print("\n ⚠️ E ORA LA DOMANDA GIUSTA, allargata: dove divergono di piu' i due venue in") + print(" TUTTO il campione 2021-2026? (cercare il caso peggiore solo dentro la finestra") + print(" che si sta difendendo e' un modo di non trovarlo)") + have = [s for s in U13 if USD_SRC[s] is not None] + Bf = bin_panel(have) + Uf = usd_panel(have).reindex(Bf.index) + bo = Bf.notna() & Uf.notna() + Df = (1e4 * np.log(Uf / Bf)).where(bo) + idf = Df.sub(Df.median(axis=1), axis=0) + worst_day = idf.abs().max(axis=1).sort_values(ascending=False) + print(f" {'giorno':<12}{'|idio| max':>11}{'asset':>7}{'comune':>9} finestra") + for t in worst_day.head(6).index: + s = idf.loc[t].abs().idxmax() + w = "fuori campione" if t < pd.Timestamp(T2_END, tz="UTC") else "scoperta 2024+" + print(f" {str(t.date()):<12}{idf.loc[t, s]:>11.0f}{s:>7}{Df.loc[t].median():>9.0f} {w}") + tw = worst_day.index[0] + print(f" il giorno peggiore in assoluto e' il {tw.date()}: scarto per asset (bps)") + print(" " + " ".join(f"{s}:{idf.loc[tw, s]:.0f}" for s in have + if np.isfinite(idf.loc[tw, s]))) + print(" 📌 E' un fatto che va detto per intero: la divergenza idiosincratica PUO'") + print(" esplodere — qui di due ordini di grandezza — ma e' successo in una CASCATA DI") + print(" LIQUIDAZIONI sulle coppie /USDT, non in un depeg, e cade nella finestra di") + print(" SCOPERTA (2024+, dove lo sleeve gira su Hyperliquid), non nel fuori campione.") + print(" Il meccanismo temuto dall'obiezione e' REALE; non e' accaduto nel 2021-2023.") # il giorno peggiore: dove il P&L dei due sleeve si stacca di piu' a0 = alive(X.xsec_engine(PU, phase=0)); b0 = alive(X.xsec_engine(PB, phase=0)) @@ -615,7 +760,11 @@ def main() -> None: print(f" TEST 1 U10 congelato : corr mediana {R['corr'].median():.4f}, minima " f"{R['corr'].min():.4f} -> {'PASS' if R['corr'].min() >= CORR_SOGLIA else 'FAIL'}") print(f" TEST 2 U13 ibrido : corr mediana {R2['corr'].median():.4f}, minima " - f"{R2['corr'].min():.4f} -> {'PASS' if R2['corr'].min() >= CORR_SOGLIA else 'FAIL'}") + f"{R2['corr'].min():.4f} -> {'PASS' if R2['corr'].min() >= CORR_SOGLIA else 'FAIL'}" + f" (una fase su 10; col gate spento minima {np.min(cg2):.4f} = PASS)") + print(f" ⚠️ il TEST 2 e' MIO, non quello dichiarato: e' piu' severo per costruzione") + print(f" (le gambe cambiano venue in date diverse) e la sua unica fase sotto soglia") + print(f" e' attribuita al gate binario, non al prezzo.") print(f" riferimento 2024+ di §21 (Binance vs Hyperliquid): 0,9991 / dSharpe -0,025") su = alive(X.xsec_engine(PUh, phase=0)) mg = A.marginal_vs_tp01(win(su, T2_START, T2_END)) @@ -633,6 +782,28 @@ def main() -> None: print(" null de-levering: NON PERTINENTE (nessun claim di 'meno drawdown').") print(" anchor: girato per costruzione — ogni numero sopra e' su tutte e 10 le fasi.") + # ------------------------------------------------------------ [8] verdetto + print("\n[8] VERDETTO") + print(f" Il TEST DICHIARATO (meccanismo congelato, stesso sottoinsieme, stessa finestra,") + print(f" USD contro USDT) PASSA: corr mediana {R['corr'].median():.4f}, minima " + f"{R['corr'].min():.4f} >= {CORR_SOGLIA}, dSharpe appaiato {R['d'].median():+.3f}.") + print(f" Il titolo di §21 ricalcolato in dollari si muove di {R2['sh_usd'].median()-R2['sh_usdt'].median():+.2f} " + f"({R2['sh_usdt'].median():+.2f} -> {R2['sh_usd'].median():+.2f} di mediana di fase).") + print(f" Nella finestra del depeg la componente idiosincratica sale (med {idm.median():.1f} bps " + f"contro {idio[~dm].abs().stack().median():.1f}) ma resta due ordini di grandezza sotto") + print(f" la vol giornaliera di un alt, e ZERO ribilanciamenti cambiano gambe li' dentro.") + print(f" L'unica corr sotto soglia (TEST 2, fase 2: {R2['corr'].min():.4f}) e' attribuita:") + print(f" col gate di dispersione SPENTO la minima diventa {np.min(cg2):.4f} -> non e' il") + print(f" prezzo, e' la soglia BINARIA che amplifica pochi bps in 10 giorni di flat.") + print( " -> IL RISULTATO XS01-OOS SOPRAVVIVE al controllo di venue.") + print( " Cio' che NON e' stato controllato, e va citato insieme al verdetto: BNB non ha un") + print( " prezzo USD nel 2021-23 (e' il token nativo del venue sotto esame), e toglierlo") + print( " costa -0.75 di mediana di fase. Il test copre 10-12 gambe su 13, non 13.") + print(f" E il caso peggiore di divergenza dell'INTERO campione ({tw.date()}, " + f"{idf.loc[tw].abs().max():.0f} bps su una gamba)") + print( " dimostra che il meccanismo temuto e' reale: semplicemente non e' accaduto nella") + print( " finestra fuori campione. Non e' 'non puo' succedere', e' 'non e' successo li''.") + print(f"\n[fine] {time.time()-t0:.1f}s")