From 0f2e195674fe50c8233b7a087146587b34c83ded Mon Sep 17 00:00:00 2001 From: Adriano Dal Pastro Date: Sat, 22 Aug 2026 20:51:47 +0000 Subject: [PATCH] =?UTF-8?q?research(wave-0822):=20MAKER=20scartato=20(il?= =?UTF-8?q?=20segno=20dipende=20da=20<=20contro=20<=3D)=20+=20CRITICO=20?= =?UTF-8?q?=E2=80=94=20la=20cucitura=20dell'ondata,=20non=20i=20filoni?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/research/RESULTS-0822.md | 134 ++++++++++++++++++++++- scripts/research/r0822b_bin_freq.py | 9 +- scripts/research/r0822b_surface_rv.py | 58 +++++++++- scripts/research/r0822b_tp01_sinistro.py | 88 ++++++++++++--- 4 files changed, 271 insertions(+), 18 deletions(-) diff --git a/docs/research/RESULTS-0822.md b/docs/research/RESULTS-0822.md index ebe226d..2590956 100644 --- a/docs/research/RESULTS-0822.md +++ b/docs/research/RESULTS-0822.md @@ -693,9 +693,9 @@ 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? | _in corso_ | -| 22 | MAKER | l'esecuzione passiva e' una fonte di ritorno, al netto del costo di non essere eseguiti? | _in corso_ | +| 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' | _in corso_ | +| 24 | CRITICO | cosa NON e' stato misurato, e quale singola misura mancante vale di piu' | **3 correzioni all'ondata**, 1 regola mia ritirata | | 25 | BIN-FREQ | il binario di frequenza su SKH01 e' un candidato o un sottoprodotto? | _in corso_ | | 26 | TP01-SINISTRO | quanto pesa TP01 se l'obiettivo include un crash che nel campione non c'e'? | _in corso_ | | 27 | SURFACE-RV | la superficie e' internamente incoerente, e l'incoerenza vale piu' del costo di attraversarla? | _in corso_ | @@ -759,3 +759,133 @@ mostra che la sua serie e quella del lookback costante coincidono a **max|Δ| = n=2719** — non *somiglia a*, **lo e'**. **VERDETTO: SCARTATO. IL FILONE ORIZZONTE-ADATTIVO E' CHIUSO DEFINITIVAMENTE.** + +--- + +## 22 — MAKER (esecuzione passiva come fonte di ritorno) + +`scripts/research/r0822b_maker.py` (19 s, sola lettura). **42 celle dichiarate**, nessuna riduzione. + +📌 **Osservazione strutturale che riapriva la domanda:** il netting su strumento unico — il motivo per +cui T1 resto' non implementata il 26/07 — **non si applica qui**. Quello uccide i *bracket per-sleeve* +(un limit al livello di SKH chiuderebbe quota TP01); l'ordine **netto** di ribilanciamento e' uno +solo, quindi passivizzarlo non ha conflitti fra sleeve. La domanda era davvero aperta. + +**(1) Il differenziale, limite superiore** (tutto maker, zero non-fill): dSharpe **+0,0333**, +dCAGR +0,466 pp → **$2,96/anno a $635**, $23,28 a $5.000, $1.203 al muro di $258k. +✅ Replica indipendente della curva del 26/07: **+0,0167 Sh/bps e +0,233 pp/bps** contro i pubblicati +0,017 / 0,23. + +📌 **(2) Il costo del non-fill, ed e' qui che muore: il parametro che decide non e' l'orizzonte, e' +cosa si chiama "riempito".** + +| N (min) | TOCCO `low <= P` (limite superiore) | ATTRAVERSAMENTO `low < P` (minimo difendibile) | +|---|---|---| +| 5 | fill 93,2% · resta **+0,31** bps (15,5%) | fill 86,2% · resta **−0,47** bps (**−23,6%**) | +| 60 | 98,6% · +0,34 (17,1%) | 95,9% · **−0,45** (−22,4%) | +| 120 | 98,9% · +0,67 (33,7%) | 96,9% · −0,38 (−19,0%) | + +**Fra le due colonne cambia una sola disuguaglianza stretta**: se la barra che apre esattamente al +nostro prezzo, e da li' se ne va, conta come fill. **Non conta** — a quel prezzo non e' stato +scambiato niente dopo l'arrivo dell'ordine, e un passivo sta *dietro* a tutta la coda. Griglia fine: +il salto e' **tutto al primo passo** (3,16 → 3,95 bps a penetrazione sub-tick) e **non esiste un q +positivo di pareggio**. Lente model-free: il fill *richiesto* per pareggiare e' **88-98%**, quello +ottenuto e' sotto in **25 celle su 25**. + +**Gate:** appaiato **per ORDINE** (ogni ordine compare una volta in entrambe le politiche, riempito o +no — allineare sui riempiti avrebbe tenuto solo i casi in cui non e' successo niente); **IC95 +bootstrap contiene lo zero in 10 celle su 10** al tocco e a q=0, interamente negativo da q≥1; +**placebo a ore casuali girato** → reale ≈ placebo e **incoerente fra i due asset** (BTC 6,8 vs 3,1 +bps; ETH 4,1 vs 4,7) ⇒ la selezione avversa **non** e' "il libro trada nei momenti brutti", e' +**strutturale all'esecuzione passiva** e non si aggira scegliendo momenti migliori. Null del +de-levering **non pertinente e dichiarato** (nessun claim di DD; il maxDD **cambia segno** fra le +lenti = non e' un effetto). + +📌 **La firma della troncatura, vista dall'altra parte.** Il passivo **vince sul 92-98% degli ordini e +perde sulla media**: mediana dell'avversa **−2,0 bps** (favorevole), media **+4,3**, peggiore **+948**, +e i **5 ordini peggiori su 1535 fanno il 42% del danno**. E' la forma speculare del profit-take di +VRP01 (30/07). **Una politica che vince quasi sempre e perde sulla media si giudica sulla media.** + +⚠️ **Rischio operativo quantificato:** a N=60 restano aperti al giro successivo il **4,6-7,8% degli +ordini = 9-15 volte l'anno** in cui l'esecutore deve cancellare-e-rimpiazzare su un conto vero. Oggi +`rebalance_signed` manda market e finisce: **nessun ordine sopravvive al giro** → si comprerebbe un +modo nuovo di rompersi (il libro ha gia' pagato quel prezzo con `fresh_5m`) per un beneficio il cui +IC95 contiene lo zero. + +⚠️ **Numero del brief non riprodotto:** l'agente ricostruisce **191 ordini/anno di libro** a $635 +contro i "35-44/anno per asset" del brief; il nastro vero da' 18 ordini in 45 giorni = **146/anno**. +La conclusione non dipende da questo (il punto 1 usa il turnover modellato, che replica la curva +pubblicata al terzo decimale), **ma il numero del brief va ri-verificato.** + +**VERDETTO: SCARTATO.** +0,033 Sharpe nel caso impossibile, contro ±0,20 di banda d'ancora del libro. +**Smentitore dichiarato:** una misura di **profondita' del book** sui perpetual USDC (che l'OHLC non +contiene e che il progetto non raccoglie — `cb_chain` e' opzioni). Se a taglie di $5-80 la coda al +miglior livello si consumasse senza che il prezzo debba attraversare, il segno si ribalta. **E' +misurabile in avanti**: registrare `book_depth` al momento di ogni ordine e poi il volume scambiato +al livello. + +--- + +## 24 — CRITICO (critico di completezza dell'ondata) + +`scripts/research/r0822b_critic.md` (48 KB, markdown — non uno script). Ha letto brief, registro, +diario e i sorgenti degli agenti. + +📌 **La tesi, e regge:** *il metodo dei singoli filoni non e' il problema dell'ondata, la CUCITURA lo +e'.* I difetti gravi stanno nei punti dove **nessun agente era responsabile**. + +🚨 **(a) `dealer_net_gamma` NON e' "il GEX col segno invertito" — la regola l'ho pubblicata io in +CLAUDE.md ed e' FALSA.** ✅ **Verificata da me aprendo la fonte**, che gira su questa stessa VPS: +`/opt/docker/cerbero-mcp/src/cerbero_mcp/common/options.py:11-14` **dichiara la convenzione** +(*"i dealer sono SHORT calls (le vendono al retail) e LONG puts"*) e `dealer_gamma_profile:138-140` +la implementa (`call_dealer_gamma -= contrib` / `put_dealer_gamma += contrib`). Non e' un segno +invertito per errore: e' un'**assunzione di posizionamento dichiarata**, diversa da quella del GEX +standard. Il default `top_n_strikes=50` spiega anche il coefficiente −0,7 e l'offset che il filone +DEALER-GAMMA attribuiva a "non-portabilita'". **Il verdetto SCARTATO regge; cade la regola**, che le +prossime ondate avrebbero ereditato al contrario. + +🚨 **(b) Il deflated-Sharpe e' stato misurato ai suoi DUE estremi degeneri lo stesso giorno, da due +agenti che non si citano — e tre gate pre-registrati ci poggiano sopra** (XSR01 23/10, DVOLSPREAD +24/10, 22/12). `altlib.deflated_sharpe` calcola `sr0 = sd(Sharpe dei trial) × mult(N)`: dipende dalla +**varianza** della griglia, non solo da N. Da un lato VOL-SIZE dichiara il proprio DSR **VACUO** +(1,000 anche per il baseline); dall'altro ORTHO-SCREEN pubblica *"sr0 = 1,572 ⇒ uno screen largo su +BTC/ETH non puo' passare il proprio gate per aritmetica"* — ma quell'1,572 implica sd≈0,58, e **le +stesse 168 celle dichiarate come 7 famiglie da 24 danno 1,15, sotto il soffitto ~1,3**: il verdetto +"impossibile per aritmetica" **si ribalta senza toccare un dato**, e la cura che suggerisce +(dichiarare famiglie piu' piccole) e' esattamente la manovra che il progetto ha proibito il 30/07. +✅ **Convergenza indipendente:** il filone BOCPD, che non ha parlato col critico, ha misurato lo +stesso difetto dall'altro capo (DSR 0,998 PASS dentro la famiglia omogenea → **0,555 FAIL** con +l'sr0 di screen). **Due agenti, due strade, stessa conclusione: il gate non ha una regione utile in +mezzo.** + +🚨 **(c) Il filone ALT-OPTIONS non e' nel registro** — ✅ verificato: **zero occorrenze**, ne' riga ne' +sezione, benche' due altri filoni lo citino e il mio brief per SURFACE-RV mandasse a leggerlo. Il +diario lo liquida come *"alt-options (alt)"*, ma la sua conclusione riguarda **ETH_USDC, che non e' +un alt**: `f_venue` 0,980 e **max-loss $16,62/lotto**. Se regge, e' la **quarta** soglia pubblicata +falsificata (il diario ne annuncia tre) e sposta VRP01 da *"servirebbe il 61% di un conto da $3.000"* +a *"entra in un conto da ~$140"*. ⚠️ **Cio' che NON cambia: la regola "niente short-vol da modello in +deploy" non era una regola di eseguibilita'** — VRP01 resta fuori dal libro per il `f` modellato e +per il gate IV-rank, non per la taglia del lotto. + +📌 **(d) La misura di maggior valore mai fatta, secondo il critico: il peggior giorno che il libro +puo' avere, MISURATO invece che assunto.** Il gradino di leva 1,00→1,50x vale **14,7a → 11,6a** al +capitale-rendita (~€300/mese di versamenti equivalenti, a costo zero) ed e' bloccato da **un unico +parametro scelto a mano** ("un giorno −10%/anno porta k* a 2x"). Controllo di cinque minuti: sui 10 +peggiori giorni di BTC/ETH in 7,4 anni — **incluso il −41,5%/−45,7% del 12 marzo 2020** — il libro ha +fatto **+0,97 · +0,72 · 0,00 · −1,98 · −2,24 · +0,23%**, e il suo peggior giorno assoluto (**−3,38%**) +**non e' un giorno di crash**. Il −10% e' plausibilmente una **coda da buy&hold importata in un libro +difensivo**. + +📌 **(e) La risposta onesta al mandato, che gli era stato chiesto di dare se vera: nessuna misura di +ricerca batte "versare".** 3,1 anni di ricerca valgono meno dei 5 anni che vale €250/mese in piu'. +E la verifica che costa meno di tutte **non e' ricerca**: leggere il listino di due prop firm. +L'intero risultato di testa dell'ondata (+0,400 di J) poggia sull'assunto — scritto in un **commento +a riga 100** — che una firm crypto listi i 19 alt Hyperliquid con short abilitato. **E' la ripetizione +esatta dell'errore GTAA01/PRIIPs**, per cui il progetto ha gia' scritto la regola: *la negoziabilita' +sul conto REALE va verificata quando lo sleeve entra in RICERCA.* + +**Altre contraddizioni fra agenti segnalate:** lo Sharpe di XSR01 compare con **quattro** lenti (non +tre); il muro di XS01 con **tre** numeri; la leva riceve guida **opposta** da GROWTH-POLICY e +PROP-ALLOC; il peso di SKH01 e' **respinto da un agente e raddoppiato da un altro**. Piu' 6 modalita' +non esplorate e 6 punti di autocritica — incluso che i **20 MB del dataset futures 2018-2026 (l'unico +con la coda 2022) vivono solo in uno scratchpad di sessione**. diff --git a/scripts/research/r0822b_bin_freq.py b/scripts/research/r0822b_bin_freq.py index 345285f..bef27eb 100644 --- a/scripts/research/r0822b_bin_freq.py +++ b/scripts/research/r0822b_bin_freq.py @@ -486,9 +486,16 @@ def main() -> None: print(f" e' la scelta CONSERVATIVA e resta quella dichiarata.") print(f" dispersione dei trial: sd(Sharpe FULL) = {float(np.std(all_sr, ddof=1)):.3f} sulle") print(f" {len(ALLC)} celle, {float(np.std(pos_sr, ddof=1)):.3f} sulle {len(POS)} di segno +1.") - print(f" -> il DSR qui NON e' vacuo (il baseline lo fallisce dove il candidato lo passa):") + print(f" -> il DSR qui NON e' vacuo (il baseline lo FALLISCE dove il candidato lo passa):") print(f" la famiglia contiene celle davvero diverse fra loro, al contrario della famiglia") print(f" VOL-SIZE dove erano tutte perturbazioni della stessa size continua.") + print(f" ❌ QUESTO REFUTA LA MIA IPOTESI (b), registrata nel docstring PRIMA di misurare") + print(f" ('il DSR sara' vacuo come su VOL-SIZE'). La ragione per cui mi sbagliavo e'") + print(f" strutturale e vale come regola: un DSR e' vacuo quando i trial si somigliano") + print(f" (var_tr -> 0 => sr0 -> 0 => DSR ~ 1 per chiunque). Una famiglia BINARIA contiene") + print(f" celle che scartano insiemi di trade MOLTO diversi — compreso il segno inverso —") + print(f" quindi la dispersione dei trial e' reale e il test riacquista potenza. Non e' il") + print(f" binario a essere piu' solido della formula: e' la FAMIGLIA a essere piu' larga.") print("\n (c) MARGINAL vs TP01 — sulla gamba modificata e sulla gamba base") for lab, s in (("BASE (size fissa)", base_leg[can]), (nmc, LEG[nmc][can]), diff --git a/scripts/research/r0822b_surface_rv.py b/scripts/research/r0822b_surface_rv.py index 1c222f9..d8cfe23 100644 --- a/scripts/research/r0822b_surface_rv.py +++ b/scripts/research/r0822b_surface_rv.py @@ -369,7 +369,9 @@ def test_calendario(q: pd.DataFrame, dte_min: float, ogni: int = 4) -> dict: iv_need = np.sqrt(np.maximum(x["w"].to_numpy(), 0) / np.maximum(nxt_T, 1e-9)) * 100.0 amp_pt = np.where(ok, iv_need - nxt_iv, np.nan) - res = {"i_n": int(ok.sum()), "i_viol": int(viol_i.sum()), + room = amp_pt[ok] # <0 = margine, >0 = violazione + res = {"room_med_pt": float(np.nanmedian(room)), "room_p5_pt": float(np.nanpercentile(room, 5)), + "i_n": int(ok.sum()), "i_viol": int(viol_i.sum()), "i_quota": float(viol_i.sum() / max(1, ok.sum())), "i_amp_med_pt": float(np.nanmedian(amp_pt[viol_i])) if viol_i.any() else np.nan, "i_amp_p95_pt": float(np.nanpercentile(amp_pt[viol_i], 95)) if viol_i.any() else np.nan} @@ -471,6 +473,37 @@ def persistenza(bf: pd.DataFrame, viol_col: str) -> dict: return {"n": int(m.sum()), "resta": float(nxt[m].mean()) if m.any() else np.nan} +def controfattuale_usdc(bf: pd.DataFrame, asset: str, rel_usdc: float) -> dict: + """SE la famiglia USDC quotasse la STESSA superficie col SUO spread, sarebbe eseguibile? + + Controfattuale DICHIARATO, non una misura: il collettore non raccoglie le USDC (difetto di + produzione del filone 11), quindi si tiene il mid osservato sulle inverse e si stringe lo + spread al valore relativo misurato dagli altri filoni sulla famiglia USDC, con il lotto + minimo USDC e la stessa formula di fee. Assunzione dichiarata: stessa griglia di tick + (una griglia piu' grossa peggiorerebbe il risultato, quindi questo e' un LIMITE SUPERIORE). + """ + x = bf[(bf["asset"] == asset)].dropna(subset=["mid", "mid_p", "mid_n"]).copy() + x = x[np.isclose(x["lam"], 0.5, atol=0.02)] + lot = MIN_LOT_USDC[asset] + out = {} + for nome, rel in (("inverse osservato", None), (f"{asset}_USDC controfattuale", rel_usdc)): + if rel is None: + b, a_p, a_n = x["bid"], x["ask_p"], x["ask_n"] + l = MIN_LOT[asset] + else: + b = x["mid"] * (1 - rel / 2) + a_p = x["mid_p"] * (1 + rel / 2) + a_n = x["mid_n"] * (1 + rel / 2) + l = lot + cred = (b.to_numpy() * 2 * l - a_p.to_numpy() * l - a_n.to_numpy() * l) + f = (fee_coin(b.to_numpy(), 2 * l) + fee_coin(a_p.to_numpy(), l) + fee_coin(a_n.to_numpy(), l)) + netto = (cred - f) * x["spot_feed"].to_numpy() + out[nome] = {"n": int(len(x)), "pos": int(np.nansum(netto > 0)), + "max": float(np.nanmax(netto)), "p999": float(np.nanpercentile(netto, 99.9)), + "lotto_usd": float(np.nanmedian(x["spot_feed"]) * l)} + return out + + # --------------------------------------------------------------------------- controlli positivi def _finto(rows) -> pd.DataFrame: @@ -657,6 +690,12 @@ def main() -> None: print(f" (ii) log-moneyness FISSO, con interpolazione (1 snapshot ogni {c['ii_ogni']}): " f"{c['ii_viol']:,}/{c['ii_n']:,} = {c['ii_quota']:.3%} · ampiezza mediana {c['ii_amp_med_pt']:.3f} pt-vol") print(f" -> contributo dell'INTERPOLATORE = {c['ii_quota'] - c['i_quota']:+.3%} di quota di violazione") + if "i_val_usd_med" in c: + print(f" valore mediano della violazione (i) al lotto minimo ${c['i_val_usd_med']:.2f} " + f"contro un costo di 2 gambe (spread + fee) di ${c['i_costo_usd_med']:.2f}") + print(f" margine di monotonia sull'intera superficie: la iv lunga sta {-c['room_med_pt']:.2f} pt-vol " + f"SOPRA il minimo che la non-arbitraggio richiede (p5 {-c['room_p5_pt']:.2f}) " + f"-> la superficie non e' nemmeno VICINA al bordo") print("\n" + "=" * 100) print("5. TICK E PERSISTENZA — le due difese contro 'la mia incoerenza e' un artefatto'") @@ -674,6 +713,23 @@ def main() -> None: f"(mediana {np.median(nt):.0f} tick) · resta in violazione allo snapshot dopo " f"{p.get('resta', float('nan')):.1%} (n={p['n']:,})") + print("\n CONTROFATTUALE (dichiarato, non misurato): la stessa superficie con lo spread USDC") + for a, rel in (("BTC", 0.082), ("ETH", 0.026)): + if a not in set(bf["asset"]): + continue + cf = controfattuale_usdc(bf, a, rel) + for nome, r in cf.items(): + print(f" {a} {nome:<28}: lotto ${r['lotto_usd']:,.0f} · farfalle a credito netto>0 " + f"{r['pos']:,}/{r['n']:,} · migliore ${r['max']:.2f} · p99.9 ${r['p999']:.2f}") + + print("\n QUANTO MANCA per essere eseguibile (near-miss, triple equispaziate):") + for a in sorted(bf["asset"].unique()): + x = bf[(bf["asset"] == a) & np.isclose(bf["lam"], 0.5, atol=0.02)] + c = x["cost_exec"].to_numpy() * 2 * MIN_LOT[a] * x["spot_feed"].to_numpy() # >0 = costo + print(f" {a}: costo della farfalla eseguibile — migliore ${np.nanmin(c):.2f} · " + f"p0.1 ${np.nanpercentile(c, 0.1):.2f} · mediana ${np.nanmedian(c):.2f} " + f"(negativo = credito riskless)") + print("\n" + "=" * 100) print("6. IL RESIDUO SI RICOMPONE? (l'ipotesi del filone, misurata invece che assunta)") print("=" * 100) diff --git a/scripts/research/r0822b_tp01_sinistro.py b/scripts/research/r0822b_tp01_sinistro.py index 20e0ece..2c158f4 100644 --- a/scripts/research/r0822b_tp01_sinistro.py +++ b/scripts/research/r0822b_tp01_sinistro.py @@ -444,13 +444,19 @@ def main() -> None: # noqa: C901 wins_sk += d > c print(f" {str(IDX[t].date()):>12} {win[t]:>9.1%} {a:>11.1%} {b:>11.1%} " f"{c:>10.1%} {d:>11.1%} {('si' if b > a else 'no'):>9}") + pre = [t for t in w12 if IDX[t] < pd.Timestamp(RECENT_START, tz="UTC")] + wins_pre = sum(1 for t in pre + if float(np.expm1(lr_opt[t:t + EPI_LEN].sum())) + > float(np.expm1(lr_live[t:t + EPI_LEN].sum()))) print(f"\n OPT batte LIVE in **{wins}/12** finestre -> test dei segni " f"p = {binom_two_sided(wins, 12):.4f}") print(f" SKH01 puro batte TP01 puro in **{wins_sk}/12** -> p = " f"{binom_two_sided(wins_sk, 12):.4f}") - print(" ⚠️ 5 di queste 12 finestre stanno nel 2024+, cioe' DENTRO la finestra su cui") - print(" SKH01 e' stato tarato e su cui PROP-ALLOC ha ottimizzato: la potenza sale ma") - print(" l'indipendenza scende. Il test va letto come **una diagnostica, non una prova**.") + print(f" ⚠️ {12-len(pre)} di queste 12 finestre stanno nel 2024+, cioe' DENTRO la finestra") + print(" su cui SKH01 e' stato tarato e su cui PROP-ALLOC ha ottimizzato: la potenza sale") + print(" ma l'indipendenza scende. **Sul solo sotto-campione pre-2024**, che e' quello") + print(f" indipendente: OPT batte LIVE in **{wins_pre}/{len(pre)}** -> p = " + f"{binom_two_sided(wins_pre, len(pre)):.4f}. E' questo il numero da citare.") tick("§2 conto assicurazione") @@ -583,11 +589,15 @@ def main() -> None: # noqa: C901 bw_c = max(s2, key=lambda w: s2[w][2]) print(f"\n argmax della colonna 'peggiore': leva-da-2024+ -> TP01 {bw_a:.3f} | " f"leva comune 0.50x -> TP01 {bw_c:.3f}") - print(" Lettura: se la sopravvivenza al crash SALISSE col peso di TP01, l'assicurazione") - print(" servirebbe. **A leva comune non sale**: la curva e' piatta-decrescente. Il difensivo") - print(" non compra sopravvivenza su questa barriera, perche' cio' che la barriera punisce e'") - print(" la PERDITA nel crash, e nel crash TP01 perde (prende la prima gamba giu' e poi va") - print(" flat) mentre SKH01 si gira short e GUADAGNA.") + print(" ⚠️ LE DUE COLONNE DICONO COSE DIVERSE, E LA SECONDA E' A CAMPANA: a leva COMUNE la") + print(f" sopravvivenza al crash SALE col peso di TP01 fino a {bw_c:.3f} (" + f"{s2[0.0][2]:.1%} a TP01=0 -> {s2[bw_c][2]:.1%}) e poi ricade.") + print(" **Quindi TP01 protegge davvero: a pari leva, il libro con piu' difensivo sopravvive") + print(" di piu' al crash.** Il punto e' che quella protezione si compra anche abbassando la") + print(" leva — ed e' esattamente cio' che misura §5. Alla leva che ciascun libro sceglierebbe") + print(" (prima colonna) il vantaggio sparisce, perche' il libro senza TP01 la sceglie piu'") + print(" bassa. E' la firma del **null del de-levering**, qui in veste di 'protezione dal") + print(" crash' invece che di 'meno drawdown'.") tick("§4 S2 replay") @@ -637,9 +647,16 @@ def main() -> None: # noqa: C901 ret, _, _, _, _ = replay22(w, lo) _, _, _, why, _ = replay22(w, hi) print(f" {w:>7.3f} {lo:>23.2f}x {ret:>20.1%} {why:>25}") - print("\n ⚠️ La leva di rottura e' MONOTONA DECRESCENTE nel peso di TP01 solo se la") - print(" protezione fosse reale. Si legga la colonna: se il libro con piu' TP01 rompe PRIMA,") - print(" l'assicurazione non sta assicurando la cosa giusta.") + print("\n 📌 La colonna 'leva max viva' CRESCE col peso di TP01 (fino a TP01=0.875; a TP01=1") + print(" ricade perche' li' a mordere non e' piu' il giorno singolo ma la perdita CUMULATA).") + print(" **L'assicurazione e' reale e si vede: piu' TP01 = piu' leva sopportabile nel 2022.**") + print(" E accanto c'e' il prezzo: alla PROPRIA leva massima il libro senza TP01 porta a casa") + print(" il +23.3% e quello a TP01 pieno il -5.9%. TP01 compra capacita' di leva, e la") + print(" capacita' di leva non si converte in rendimento perche' cio' che TP01 toglie e'") + print(" proprio il rendimento. E' il null del de-levering scritto in una riga sola.") + print(" ⚠️ Cambia anche il VINCOLO che morde: sotto TP01 0.50 e' la regola a UN GIORNO,") + print(" sopra e' il max-loss cumulato. Due libri diversi muoiono di due morti diverse, e una") + print(" sola delle due lenti (l'accoppiata) vede la prima.") tick("§4 replay 2022") @@ -725,8 +742,10 @@ def main() -> None: # noqa: C901 print(f" {0.5*wxs30[t_xw]:.1%} al libro. La domanda non e' se XS01 sopravvive a cio' che ha") print(" gia' visto, e' se il suo comportamento nel crash somiglia a cio' che ha gia' visto —") print(" e su questo il campione non ha NIENTE da dire.") - W3 = [(0.75, 0.25, 0.00), (0.375, 0.625, 0.00), (0.25, 0.25, 0.50), (0.125, 0.125, 0.75), - (0.50, 0.25, 0.25)] + # ⚠ le ultime tre righe hanno XS01 FISSO al 50%: senza quel controllo si confonderebbe + # "piu' TP01" con "meno XS01", che e' un'altra domanda. + W3 = [(0.75, 0.25, 0.00), (0.375, 0.625, 0.00), (0.50, 0.25, 0.25), + (0.125, 0.375, 0.50), (0.25, 0.25, 0.50), (0.375, 0.125, 0.50)] com = xs.index.intersection(IDX[i_rec:]) xs_al = xs.reindex(com) print(f"\n {'TP/SKH/XS':>16} {'ipotesi XS':>12} {'leva':>6} {'J normale':>10} " @@ -832,7 +851,9 @@ def main() -> None: # noqa: C901 n_act = int((np.abs(R) > 1e-12).sum()) n_los = int((R[np.abs(R) > 1e-12] < 0).sum()) f = A.implausible_sharpe(d, n_trades=n_act, n_losing_trades=n_los) - print(f" implausible_sharpe {lab:>11}: {f}") + print(f" implausible_sharpe {lab:>11}: implausible={f['implausible']} " + f"(Sharpe {f['sharpe']:.2f}, maxDD {f['maxdd']:.1%}, quota barre in perdita " + f"{f['loss_frac']:.1%}, Calmar {f['calmar']:.2f}) {f['reasons']}") except Exception as exc: # pragma: no cover print(f" implausible_sharpe: NON GIRATO ({exc})") print(" marginal_vs_tp01 / study_family_honest / deflated_sharpe : **NON GIRATI, e non") @@ -864,6 +885,45 @@ def main() -> None: # noqa: C901 am = max(tab, key=lambda w: tab[w][key][1]["J"]) print(f" {lab:>26} {am:>14.3f} {tab[am][key][1]['J']:>10.3f} " f"{tab[0.75][key][1]['J']:>10.3f} {tab[0.375][key][1]['J']:>11.3f}") + print("\n ESISTE UN PESO DI COMPROMESSO? Il criterio dichiarato: (a) dentro il 5% del") + print(" massimo di J sulla finestra 2024+ (la 'regione robusta' del funded) E (b) dentro il") + print(" 5% del massimo di J sulla finestra 2019+, che il sinistro ce l'ha dentro.") + jr_max = max(tab[w]["rec"][1]["J"] for w in W_GRID) + jf_max = max(tab[w]["full"][1]["J"] for w in W_GRID) + js_max = max(tab[w]["sin"][1]["J"] for w in W_GRID) + print(f"\n {'w TP01':>7} {'J 2024+':>9} {'entro 5%':>9} {'J 2019+':>9} {'entro 5%':>9} " + f"{'J solo-sin':>11} {'entro 5%':>9} {'compromesso':>13}") + ok_both = [] + for w in W_GRID: + a, b, c = (tab[w]["rec"][1]["J"], tab[w]["full"][1]["J"], tab[w]["sin"][1]["J"]) + oa, ob, oc = a >= 0.95 * jr_max, b >= 0.95 * jf_max, c >= 0.95 * js_max + if oa and ob: + ok_both.append(w) + print(f" {w:>7.3f} {a:>9.3f} {('si' if oa else 'no'):>9} {b:>9.3f} " + f"{('si' if ob else 'no'):>9} {c:>11.3f} {('si' if oc else 'no'):>9} " + f"{('SI' if (oa and ob) else '-'):>13}") + print(f"\n -> pesi che soddisfano (a) E (b): {ok_both if ok_both else 'NESSUNO'}") + print(f" il libro live 75/25 e' {'dentro' if 0.75 in ok_both else 'FUORI'} da questa regione.") + print("\n LA RISPOSTA, IN QUATTRO RIGHE") + print(" 1) La premessa del caveat e' sbagliata nella FORMA: il 2024+ un crash ce l'ha (b&h") + print(" -60% di drawdown, -39.6% in 20 giorni). Manca la TAGLIA, ~2x sulla coda veloce.") + print(" 2) Il compromesso ESISTE e non e' un compromesso: lo stesso peso (TP01 ~0.375) e'") + print(" l'argmax sulla finestra con il 2022 dentro E su quella senza. Il caveat di") + print(" PROP-ALLOC e' onesto come cautela e **falsificato come previsione**.") + print(" 3) TP01 protegge davvero (a pari leva sopravvive di piu' al crash, e alza la leva") + print(" sopportabile nel 2022 da 0.93x a 2.20x) ma la stessa protezione si compra piu' a") + print(" buon mercato ABBASSANDO LA LEVA: a iso-sopravvivenza il payout e' massimo a") + print(" TP01 0.125-0.250 e cala monotonamente da li'. **7ª occorrenza del null del") + print(" de-levering**, in una veste nuova: 'protezione dal crash' invece di 'meno DD'.") + print(" 4) Il rischio vero dell'ottimo di PROP-ALLOC NON e' TP01 sotto-pesato: e' XS01 al") + print(" 50% con un comportamento nel crash che il campione non contiene. Un solo giorno") + print(" a -8% su XS01 dimezza la sopravvivenza; con TP01 al 50% ne serve uno a -12.3%.") + print(" **Se TP01 vale qualcosa su un conto funded, vale come zavorra contro l'ignoto di") + print(" XS01, non come assicurazione contro il crash di BTC/ETH — che SKH01 fa meglio.**") + print("\n ⚠️ COSA MI SMENTIREBBE: un crash in cui SKH01 NON si gira short in tempo (gap") + print(" notturno oltre lo stop, o venue fermo). Il campione ne ha quattro e in tutti e") + print(" quattro SKH01 ha girato. Basterebbe un episodio in cui SKH01 perde quanto il") + print(" sottostante per rovesciare §2 e §5 — e con n=4 quell'episodio non e' improbabile.") print("\n" + "=" * 106) print(f" fatto in {time.time()-t0:.0f}s | valutazioni: {N_EVAL}") print("=" * 106)