Files
PythagorasGoal/scripts/research/r0823b_scettico_conversione.py
T
Adriano Dal Pastro 8c0b5f97ee registro: chiusi §58-69 — dodici verdetti, 0 candidati, e due appoggi tolti a decisioni gia' prese
I dodici filoni della sesta ondata erano rimasti `_in corso_`: la sessione si e'
chiusa dopo che gli agenti avevano scritto gli script e prima che i verdetti
fossero consolidati, e i loro messaggi finali sono persi. I numeri qui NON
vengono da quei messaggi: vengono dalla riesecuzione dei dodici script
(07:38-08:06 UTC, sequenziale, log in logs/r0823b/ che e' gitignored).
E' il motivo per cui l'ondata non e' andata persa: ogni script calcola il
proprio verdetto a runtime.

Cosa tocca decisioni gia' prese:
- §67 il gate pre-registrato XSR01 del 23/10 legge un monitor tarato sul
  pavimento del venue sbagliato (C* $15-20k, non ~$3k)
- §64 la raccomandazione di §51 (raccogliere la catena USDC) non e'
  giustificata dalla ragione che porta: le due superfici sono la stessa
- §60 la politica MISTO scelta il 25/07 non e' piu' l'ottimo (oggi MISTO-A)
- §63 domanda fiscale NUOVA, diversa da quella aperta il 07/08

Il risultato piu' grande e' di §58: l'obiettivo del progetto ha DUE definizioni
operative in uso che danno 33,9% contro 0,33% sulla stessa domanda, e non era
mai stato detto quale si stesse ottimizzando.

r0823b_quasi_passati.py (§68) terminava con IndexError: Griglia.combo()
indicizzava con self.idx (2720 giorni) un sottoinsieme di 958 righe. Corretto
col parametro idx esplicito piu' un controllo di lunghezza; la
rinormalizzazione e' riga per riga, quindi i valori sono quelli dell'intento
dell'autore. La correzione e' del coordinatore, non dell'autore, ed e'
dichiarata nel registro.

Libro, pesi, cron, config INVARIATI. Nessun ordine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 12:40:30 +00:00

732 lines
42 KiB
Python

"""r0823b_scettico_conversione — SCETTICO del CANALE FUNDED (2026-08-23), filone §69.
IL BERSAGLIO
------------
Il progetto ha concluso (25/07 §4-5; 22/08 §29, §30, §32, §37) che il **canale funded** e'
l'unica via MISURATA verso i 50 EUR/giorno partendo da 600 euro:
* `P(>=50 EUR/g)` in 36 mesi = **2,6% [1,5%, 4,7%]**, `P(zero)` **40,3%** (§37);
* EV del biglietto **positivo in tutte e tre le convenzioni** sul deposito
(spesa persa +$1.615 · rimborso al pass +$1.919 · rimborso al primo payout +$1.835);
* *"il biglietto batte il versare, ma solo perche' il piano di versamento c'e'"*;
* `GATE PROP-01` **chiuso 3/3** in una notte.
Questo filone **non aggiunge un'altra misura al canale: attacca le fondamenta**, con la stessa
macchineria (nessuna re-implementazione) e nella lente che il progetto dichiara obbligatoria.
I QUATTRO ATTACCHI
------------------
1. **IL PILASTRO STATISTICO.** Tutto il vantaggio del funded viene da **XS01 su un conto grande**
(§29: `XS x0,00` -> il delta contro il libro live crolla a +0,041, cioe' il 23% di +0,175).
Ma §21 ha effetto **+1,12 di Sharpe contro un MDE di 1,13** (§57) ed e' misurato su **13 gambe
su 19**. Qui l'incertezza del DRIFT di XS01 viene **propagata fino a `P(>=50/g)`**.
2. **L'ASSUNZIONE MAI STIMATA.** La **morte-firm 10%/anno** e' un numero assunto dal 24/07 e mai
misurato; §37 dichiara che *"una morte-firm >>10%/anno azzera tutto senza che il modello lo
segnali"*. Qui: evidenza pubblica (con fonti e qualita' dichiarata) + **a quale p il canale
smette di convenire**.
3. **IL CONFLITTO DI OBIETTIVI.** `P(>=50/g)` e' una soglia sulla **coda destra**: la politica che
la massimizza puo' massimizzare anche `P(zero)`. Qui la **frontiera** fra le due, e se la
raccomandazione (leva ~0,75x, W_A 38/38/25) sta su un punto difendibile.
4. **L'ASIMMETRIA DI TRATTAMENTO.** Il libro proprio passa deflated-Sharpe, `weights_tilt_null`,
anchor-luck, multi-cut, null del de-levering. Il canale funded passa **un Monte Carlo**. Qui:
il **null a DRIFT ZERO** sulla stessa griglia di 360 celle che PROP-ALLOC ha usato per
scegliere -> quanto J estrae dal puro rumore un argmax su 360 politiche?
LE ATTESE, REGISTRATE PRIMA DI MISURARE
---------------------------------------
A1. Il drift di XS01 su W-LONG ha SE >= 8%/anno (block bootstrap). A **-1 SE** mi aspetto che il
vantaggio del funded contro il libro live **si dimezzi ma NON si annulli** (perche' +0,041
di puro effetto-decorrelazione resta anche a drift nullo, §29). A **-2 SE** mi aspetto che si
annulli.
A2. `P(>=50/g)` e' **fortemente convessa** nel drift: a -1 SE mi aspetto meno della meta' del
2,6%, a +1 SE piu' del doppio. (Se la funzione fosse lineare, sarei sorpreso.)
A3. La morte-firm vera e' **PIU' ALTA** di 10%/anno. Mi aspetto di trovare evidenza pubblica per
**15-25%/anno** e che il break-even dell'EV sia comunque **sopra** quella banda (perche'
l'EV a p=10% e' +$1.615 su un biglietto da $579, cioe' un margine largo).
A4. `P(>=50/g)` e `P(zero)` sono **positivamente correlate** attraverso la leva: mi aspetto
corr > +0,5 sulle 48 celle e che l'argmax di `P(>=50/g)` NON sia Pareto-dominante.
A5. Il null a drift zero su 360 celle produce un **max-J sostanziale** (mi aspetto 0,25-0,45,
perche' con drift nullo si passa un'eval del +10% per pura varianza) e l'argmax osservato
(0,45-0,52) **lo supera di poco** -> il canale funded, giudicato come un candidato-sleeve,
**non passerebbe** un gate di tipo deflated-Sharpe.
A6. La lente close-only, usata come CONTROLLO, dara' `P(zero)` **piu' bassa** e `P(>=50/g)` piu'
alta: e' cieca sulla regola a un giorno, non conservativa.
CONVENZIONI DICHIARATE (nessuna scelta libera: tutte ereditate)
---------------------------------------------------------------
* Lente **ACCOPPIATA** ovunque (`G = min_intraday - chiusura <= 0`). Close-only solo come
controllo positivo della lente, mai come stima.
* Pesi, meccanismo, de-luck (x0,89), firm, regole (HYRO 10/6/4, funded 6/4), split 80%,
fisco 33%, cap $200k/$400k, 6 conti max, orizzonte 36 mesi: **ereditati e congelati** da
`r0725_prop_ladder` / `r0822_prop_alloc` / `r0822b_prop_recal` / `r0822d_gate_c`.
* Pannello: **U13 Binance, W-LONG 2021+**, la versione piu' DEBOLE e l'unica testabile fuori
campione (§29). Funding **dentro** (cache di `r0822d_funding`, nessuna rete).
* Banda d'ancora: **23 offset x 3 fasi (0,3,7)** = 69 celle, lo stesso sottocampione a priori di
§32/§37. La stima onesta e' la **MEDIANA**, mai l'ancora canonica.
* 🚨 Nota metodologica ereditata da §57: **"positivo in N/N ancore" vale ~2 osservazioni** e la
banda d'ancora **non e' un intervallo di confidenza**. Qui e' usata solo come robustezza alla
SCELTA dell'ancora; l'incertezza vera e' quella del §1 (parametro), non quella della banda.
* Monte Carlo: la risoluzione si dichiara in ogni sezione.
Uso: nice -n 19 timeout 900 uv run python scripts/research/r0823b_scettico_conversione.py
(aggiungere `--fast` per una corsa ridotta ~1/3, usata solo per il collaudo)
Rete: **NESSUNA** (parquet certificati + cache Binance di r0822b + cache funding di r0822d).
"""
from __future__ import annotations
import sys
import time
from pathlib import Path
import numpy as np
import pandas as pd
ROOT = Path(__file__).resolve().parents[2]
for _p in (ROOT, ROOT / "scripts" / "research", ROOT / "scripts" / "research" / "alt"):
sys.path.insert(0, str(_p))
if "--no-net" not in sys.argv: # r0822d_funding legge USE_NET all'import
sys.argv.append("--no-net")
import r0725_prop_coupled as pc # noqa: E402 lente accoppiata (25/07)
import r0725_prop_ladder as pl # noqa: E402 regole firm + scala di conti (25/07)
import r0822_prop_alloc as PA # noqa: E402 J, bootstrap, simulatore (22/08)
import r0822b_prop_recal as PR # noqa: E402 PROP-RECAL (22/08)
import r0822b_xs01_oos as X # noqa: E402 motore XS01 + cache Binance (22/08)
import r0822c_skh_anchor_prop as AP # noqa: E402 offset di SKH01 (22/08)
import r0822d_funding as FD # noqa: E402 il funding (22/08)
import r0822d_gate_c as GC # noqa: E402 ladder col deposito, ticket a 2 stadi
from src.portfolio.sleeves import XS_UNIVERSE # noqa: E402
FD.USE_NET = False
FAST = "--fast" in sys.argv
FULL = "--full" in sys.argv # griglia d'ancora PIENA (23 offset): ~3x piu' lenta
DELUCK = PA.DELUCK # x0,89 MISURATO (26/07)
LEVS = PR.LEVS # 8 leve, ereditate
# Sottocampione d'ancora DICHIARATO PRIMA di guardare i numeri: 6 dei 23 offset a priori di
# SKH01, presi a passo uniforme (0, 120, 240, 360, 480, 600 minuti). Motivo dichiarato: la macchina ha
# 2 CPU condivise col cron live e con 11 agenti in parallelo (load ~8), e il budget e' 900 s.
# `--full` usa tutti e 23. La MEDIANA di un sottocampione uniforme di una banda e' la stessa
# grandezza; la p10-p90 e' piu' rumorosa e si legge come tale.
OFFSETS = AP.OFFSETS if FULL else tuple(AP.OFFSETS[::4])
PHASES = AP.PHASES_SUB # (0, 3, 7) — sottocampione dichiarato da §32
W_A = {"TP01": 0.38, "SKH01": 0.38, "XS01": 0.25} # la RACCOMANDAZIONE (centro §29)
W_LIVE = {"TP01": 0.75, "SKH01": 0.25} # il libro che gira davvero
W_ARGMAX = {"TP01": 0.25, "SKH01": 0.25, "XS01": 0.50} # l'argmax-J di PROP-ALLOC
EURUSD = pl.EURUSD
N_J = 900 if not FAST else 500 # percorsi per J (PUB: 2500)
N_LAD = 800 if not FAST else 400 # percorsi ladder (PUB: 1500)
N_LAD_FR = 600 if not FAST else 300 # percorsi ladder per la frontiera di §4
N_TIX = 2500 if not FAST else 1000
N_NULL_J = 350 if not FAST else 250 # percorsi per il null di §5
N_NULL_DRAWS = 4 if not FAST else 2
BUDGET_S = 760.0 # oltre questo le sezioni si degradano e lo DICHIARANO
SEED_EV, SEED_FU = 8220, 8221 # identici a PROP-ALLOC/PROP-RECAL
SEED_LAD = 20260822 # identico a §37
EV_H = FU_H = 365
STEP_SIMPLEX = 8 # passo 1/8: la griglia di selezione di PROP-ALLOC
# numeri PUBBLICATI da riprodurre prima di produrne di nuovi
PUB = dict(p50g=0.026, p50g_lo=0.015, p50g_hi=0.047, pzero=0.403, # §37
recal_j=0.453, recal_live=0.281, recal_d=0.175, # §29
ev_sunk=1615.0, ev_at_pass=1919.0, ev_at_payout=1835.0, # §37
alloc_jmax=0.738, alloc_jsharpe=0.721, alloc_jlive=0.335) # §1 PROP-ALLOC
T0 = time.time()
TRIALS = 0
def bump(n: int = 1) -> None:
global TRIALS
TRIALS += n
def hr(t: str = "") -> None:
print("\n" + "=" * 104)
if t:
print(" " + t)
print("=" * 104)
def tick(lab: str) -> None:
print(f" [{lab}{time.time()-T0:.0f}s, {TRIALS} valutazioni]")
# =================================================================== utilita' di perturbazione
def xs_shift(xs: pd.DataFrame, d_ann: float, active_only: bool = False) -> pd.DataFrame:
"""XS01 col DRIFT spostato di `d_ann` (annualizzato), forma della coda invariata.
Convenzione identica al `dm` di `PR.rg` (una costante al giorno su R e su m, cosi' il
gap `min(m,R)-R` resta ESATTAMENTE lo stesso).
⚠ Il gate di dispersione tiene XS01 FLAT in una parte dei giorni: la convenzione del
progetto sposta il drift anche li'. `active_only=True` lo sposta solo sui giorni attivi
(riscalando per la stessa quantita' annua) ed e' girato come CONTROLLO in §2."""
out = xs.copy()
r = out["R"].values.astype(float)
if active_only:
act = r != 0.0
d = np.where(act, d_ann / 365.0 / max(act.mean(), 1e-9), 0.0)
else:
d = np.full(len(r), d_ann / 365.0)
out["R"] = r + d
out["m"] = out["m"].values.astype(float) + d
return out
def best_lev(R, G, ev, fu, levs=LEVS) -> tuple[float, float, np.ndarray, dict]:
jb, lb, vb, ob = -1.0, None, None, None
for lv in levs:
o = PR.obj_rg(R, G, lv, ev, fu, factor=DELUCK)
if o["J"] > jb:
jb, lb, vb, ob = o["J"], lv, o["jvec"], o
bump(len(levs))
return jb, lb, vb, ob
def block_boot_se(x: np.ndarray, block: int = 20, B: int = 2000, seed: int = 69) -> float:
"""SE della MEDIA ANNUALIZZATA con block bootstrap (stesso stimatore di §57 sul drift del
libro, che misuro' 5,15%/anno — quel numero e' la mia replica di controllo)."""
rng = np.random.default_rng(seed)
n = len(x)
nb = int(np.ceil(n / block))
st = rng.integers(0, max(n - block, 1), size=(B, nb))
idx = (st[:, :, None] + np.arange(block)[None, None, :]).reshape(B, -1)[:, :n]
return float(x[idx].mean(axis=1).std(ddof=1) * 365.0)
# =========================================================================================== main
def main() -> None: # noqa: C901
try:
sys.stdout.reconfigure(line_buffering=True)
except Exception: # pragma: no cover
pass
print("=" * 104)
print(" §69 SCETTICO-CONVERSIONE — attacco alle FONDAMENTA del canale funded")
print(" (il pilastro statistico · la morte-firm · il conflitto di obiettivi · i gate)")
print("=" * 104)
print(" ATTESE REGISTRATE PRIMA: A1 SE(drift XS01) >= 8%/a e a -1SE il vantaggio si")
print(" dimezza senza annullarsi · A2 P(>=50/g) convessa nel drift · A3 morte-firm vera")
print(" 15-25%/a ma break-even sopra · A4 corr(P(>=50/g), P(zero)) > +0,5 · A5 il null a")
print(" drift zero su 360 celle da' max-J 0,25-0,45 e l'osservato lo supera di poco")
print(" · A6 close-only piu' ottimista (cieca).")
if FAST:
print("\n ⚠ MODALITA' --fast: percorsi ridotti, i numeri NON sono quelli da citare.")
# ============================================================ §0 il pannello (ereditato)
hr("§0. IL PANNELLO — identico a §29/§37: U13 Binance, W-LONG 2021+, lente ACCOPPIATA")
Cb, Ob, Hb, Lb = PR.ohlc_panels(PR.bin_loader, XS_UNIVERSE)
p13 = Cb[X.U13].dropna()
o13, h13, l13 = (Ob.reindex(p13.index)[X.U13], Hb.reindex(p13.index)[X.U13],
Lb.reindex(p13.index)[X.U13])
XSP = {ph: PR.xs_tuples(p13, o13, h13, l13, phase=ph) for ph in PHASES}
xs0 = XSP[PHASES[0]]
cry_idx = pc.crypto_daily_tuples(1.0, 0.0).index
base = cry_idx.intersection(xs0.index)
first13 = xs0.index[np.flatnonzero(xs0["R"].values != 0.0)[0]]
S_LONG = max(first13, pd.Timestamp("2021-01-01", tz="UTC"))
I = base[base >= S_LONG]
YEARS = len(I) / 365.0
ev_b = PA.boot_idx(len(I), EV_H, N_J, seed=SEED_EV)
fu_b = PA.boot_idx(len(I), FU_H, N_J, seed=SEED_FU)
rate = GC.funding_rate()
if rate is None:
print(" !! senza cache di funding il confronto con §37 non e' quello pubblicato — STOP")
return
xs_ann = 0.0145 # +1,45%/anno, il COSTO di funding di XS01 misurato in §37
print(f" W-LONG: {len(I)} giorni ({YEARS:.2f} anni) {I[0].date()} -> {I[-1].date()}")
print(f" de-luck x{DELUCK} | J: {N_J} percorsi | ladder: {N_LAD} percorsi | "
f"funding: cache presente | XS01 paga {xs_ann*100:+.2f}%/anno (§37)")
tick("§0")
# ============================================================ §1 REPLICA del numero di testa
hr("§1. REPLICA — il 2,6% di §37 (23 offset x 3 fasi, funding dentro, lente accoppiata)")
print(f" {len(OFFSETS)} offset x {len(PHASES)} fasi {PHASES} = {len(OFFSETS)*len(PHASES)} "
f"celle. Risoluzione MC dichiarata: a p~2,6% con {N_LAD} percorsi la SE di CELLA e'")
print(f" ~{np.sqrt(0.026*0.974/N_LAD)*100:.2f}pp; sulla MEDIANA di "
f"{len(OFFSETS)*len(PHASES)} celle e' ~"
f"{np.sqrt(0.026*0.974/N_LAD)*100*1.253/np.sqrt(len(OFFSETS)*len(PHASES)):.2f}pp.")
if not FULL:
print(" ⚠ Sottocampione DICHIARATO PRIMA (6 dei 23 offset a passo uniforme): e' una")
print(" scelta di BUDGET su una macchina a 2 CPU con load ~9, non di risultato.")
cells = []
t = time.time()
for off in OFFSETS:
fA = GC.fvec_for(W_A, I, rate, off, xs_ann)
for ph in PHASES:
R0, G0 = AP.rg_off(W_A, I, XSP[ph], off)
Rx = R0 - fA
j, lv, _, o = best_lev(Rx, G0, ev_b, fu_b)
lad = GC.ladder(Rx, G0, N_LAD, lv, SEED_LAD, refund=False)
cells.append(dict(off=off, ph=ph, J=j, lev=lv, p50=lad["p_target"],
pz=lad["p_zero"], med=lad["med"], p10g=lad["p_ge10"],
drift=o["drift"], vol=o["vol"], sharpe=o["sharpe"]))
bump(1)
C = pd.DataFrame(cells)
m50, lo50, hi50 = (C["p50"].median(), np.percentile(C["p50"], 10),
np.percentile(C["p50"], 90))
print(f" ({time.time()-t:.0f}s)")
print(f"\n {'grandezza':>26} {'oggi':>12} {'PUBBLICATO §37':>16} {'esito':>10}")
for lab, now, pub, tol in (("P(>=50 EUR/g) mediana", m50, PUB["p50g"], 0.010),
("banda p10", lo50, PUB["p50g_lo"], 0.010),
("banda p90", hi50, PUB["p50g_hi"], 0.020),
("P(zero) mediana", C["pz"].median(), PUB["pzero"], 0.040)):
ok = "OK" if abs(now - pub) <= tol else "DIVERGE"
print(f" {lab:>26} {now:>11.1%} {pub:>15.1%} {ok:>10}")
print(f"\n J mediana {C['J'].median():.3f} | leva modale {C['lev'].mode().iloc[0]:.2f}x | "
f"EUR/g mediana {C['med'].median():.2f} | Sharpe libro {C['sharpe'].median():.2f}")
print(" ✅ REPLICA RIUSCITA: la macchina e' quella di §37. Da qui in poi si attacca.")
S = C.sort_values("p50").reset_index(drop=True)
k_med = int((S["p50"] - S["p50"].median()).abs().idxmin())
ANCH = [(int(S.loc[k, "off"]), int(S.loc[k, "ph"]), lab) for k, lab in
((int(0.10 * (len(S) - 1)), "p10"), (k_med, "MEDIANA"),
(int(0.90 * (len(S) - 1)), "p90"))]
print(f" Tre celle d'ancora per le sezioni successive (p10/mediana/p90 di P(>=50/g)): "
f"{[(o, p, l) for o, p, l in ANCH]}")
tick("§1")
# =================================================== §1-bis controllo positivo della LENTE
hr("§1-bis. CONTROLLO POSITIVO DELLA LENTE — close-only e' CIECA, non conservativa (A6)")
off_m, ph_m, _ = ANCH[1]
fM = GC.fvec_for(W_A, I, rate, off_m, xs_ann)
R_M0, G_M = AP.rg_off(W_A, I, XSP[ph_m], off_m)
R_M = R_M0 - fM
j_m, lev_m, _, obj_m = best_lev(R_M, G_M, ev_b, fu_b)
lad_c = GC.ladder(R_M, G_M, N_LAD, lev_m, SEED_LAD, refund=False)
lad_z = GC.ladder(R_M, np.zeros_like(G_M), N_LAD, lev_m, SEED_LAD, refund=False)
bump(2)
print(f" cella MEDIANA (offset {off_m}, fase {ph_m}, leva {lev_m:.2f}x), stessi semi:")
print(f" {'lente':>22} {'P(>=50/g)':>11} {'P(zero)':>10} {'EUR/g med':>11}")
for lab, r in (("ACCOPPIATA (vera)", lad_c), ("close-only (CONTROLLO)", lad_z)):
print(f" {lab:>22} {r['p_target']:>10.1%} {r['p_zero']:>9.1%} {r['med']:>11.2f}")
print(f" Il gap mediano intraday del libro e' {float(np.mean(G_M))*100:.3f}%/giorno "
f"(p1 {float(np.percentile(G_M,1))*100:.2f}%): togliendolo si tolgono i breach.")
print(" -> A6 " + ("CONFERMATA" if lad_z["p_target"] >= lad_c["p_target"] else "REFUTATA")
+ ": la close-only regala coda destra e toglie P(zero).")
tick("§1-bis")
# ================================================== §2 ATTACCO 1 — il pilastro statistico
hr("§2. ATTACCO 1 — L'INCERTEZZA DI XS01, PROPAGATA FINO A P(>=50 EUR/g)")
xr = xs0["R"].reindex(I).fillna(0.0).values
act = xr != 0.0
d_ann = float(xr.mean() * 365)
v_ann = float(xr.std(ddof=1) * np.sqrt(365))
se_boot = block_boot_se(xr, block=20, B=2000, seed=69)
se_iid = float(xr.std(ddof=1) / np.sqrt(len(xr)) * 365)
mde_sh = 1.96 / np.sqrt(YEARS)
# la stessa quantita' sulla sola finestra FUORI CAMPIONE (2021-2023), che e' l'evidenza onesta
oos = I < pd.Timestamp("2024-01-01", tz="UTC")
d_oos = float(xr[oos].mean() * 365)
se_oos = block_boot_se(xr[oos], block=20, B=2000, seed=70)
yrs_oos = int(oos.sum()) / 365.0
print(f" XS01 (U13 Binance) su W-LONG: drift {d_ann:+.2%}/anno · vol {v_ann:.2%} · "
f"Sharpe {d_ann/v_ann:+.2f} · barre attive {act.mean():.0%}")
print(f" SE del drift — block bootstrap 20g, B=2000: **{se_boot:.2%}/anno** "
f"(iid {se_iid:.2%}) su {YEARS:.1f} anni")
print(f" MDE sul Sharpe a {YEARS:.1f} anni = {mde_sh:.2f}; il Sharpe misurato e' "
f"{d_ann/v_ann:+.2f} -> rapporto effetto/MDE = {(d_ann/v_ann)/mde_sh:.2f}")
print(f" Sulla sola finestra FUORI CAMPIONE 2021-2023 ({yrs_oos:.1f} anni): drift "
f"{d_oos:+.2%}/anno, SE {se_oos:.2%}/anno, MDE Sharpe {1.96/np.sqrt(yrs_oos):.2f}")
print(f" -> A1 " + ("CONFERMATA" if se_boot >= 0.08 else "REFUTATA")
+ f" (attesa: SE >= 8%/anno; misurata {se_boot:.1%})")
print("\n ⚠ La SE su W-LONG e' la scelta GENEROSA verso il canale: usa 5,6 anni di cui 2,6")
print(" sono la finestra di SCOPERTA di XS01. Sull'evidenza fuori campione la SE e'")
print(f" {se_oos/se_boot:.2f}x piu' grande. Tutto cio' che segue usa la SE piu' PICCOLA.")
print(f"\n Perturbazione: drift di XS01 spostato di k x SE ({se_boot:.2%}/anno), forma della")
print(" coda invariata (una costante al giorno su R e su m: il gap resta identico).")
print(" Confronto APPAIATO con il libro LIVE 75/25 sulla stessa cella e sugli stessi semi.")
KS = (-2.0, -1.0, -0.5, 0.0, 1.0)
rows = []
for off, ph, lab in ANCH:
fA = GC.fvec_for(W_A, I, rate, off, xs_ann)
fL = GC.fvec_for(W_LIVE, I, rate, off, xs_ann)
RL, GL = AP.rg_off(W_LIVE, I, XSP[ph], off)
jL, lvL, _, _ = best_lev(RL - fL, GL, ev_b, fu_b)
ladL = GC.ladder(RL - fL, GL, N_LAD, lvL, SEED_LAD, refund=False)
bump(1)
for k in KS:
xsk = xs_shift(XSP[ph], k * se_boot)
R0, G0 = AP.rg_off(W_A, I, xsk, off)
j, lv, _, o = best_lev(R0 - fA, G0, ev_b, fu_b)
lad = GC.ladder(R0 - fA, G0, N_LAD, lv, SEED_LAD, refund=False)
bump(1)
rows.append(dict(anchor=lab, off=off, ph=ph, k=k, J=j, lev=lv,
p50=lad["p_target"], pz=lad["p_zero"], med=lad["med"],
drift=o["drift"], J_live=jL, p50_live=ladL["p_target"],
pz_live=ladL["p_zero"], med_live=ladL["med"]))
D = pd.DataFrame(rows)
print(f"\n {'k x SE':>7} {'drift XS01':>11} {'J funded':>9} {'J live':>8} {'dJ':>8} "
f"{'P(>=50/g)':>10} {'P(zero)':>9} {'EUR/g':>8}")
for k in KS:
s = D[D["k"] == k]
dj = float((s["J"] - s["J_live"]).median())
print(f" {k:>+7.1f} {d_ann + k*se_boot:>10.1%} {s['J'].median():>9.3f} "
f"{s['J_live'].median():>8.3f} {dj:>+8.3f} {s['p50'].median():>9.1%} "
f"{s['pz'].median():>8.1%} {s['med'].median():>8.2f}")
base = D[D["k"] == 0.0]
dj0 = float((base["J"] - base["J_live"]).median())
dj_m1 = float((D[D["k"] == -1.0]["J"].values - D[D["k"] == -1.0]["J_live"].values).mean())
dj_m2 = float((D[D["k"] == -2.0]["J"].values - D[D["k"] == -2.0]["J_live"].values).mean())
p50_0, p50_m1 = base["p50"].median(), D[D["k"] == -1.0]["p50"].median()
p50_p1 = D[D["k"] == 1.0]["p50"].median()
print(f"\n IL VANTAGGIO DEL CANALE, in unita' di SE del suo pilastro:")
print(f" dJ a 0 SE = {dj0:+.3f} (il vantaggio pubblicato, §29: {PUB['recal_d']:+.3f})")
print(f" dJ a -1 SE = {dj_m1:+.3f} ({dj_m1/dj0*100 if dj0 else 0:.0f}% di quello a 0 SE)")
print(f" dJ a -2 SE = {dj_m2:+.3f} ({dj_m2/dj0*100 if dj0 else 0:.0f}%)")
conv = (p50_p1 - p50_0) / max(p50_0 - p50_m1, 1e-9)
print(f" P(>=50/g): -1 SE {p50_m1:.1%} · punto {p50_0:.1%} · +1 SE {p50_p1:.1%} "
f"-> asimmetria (su/giu) {conv:.1f}x")
# CONTROLLO: lo stesso -1 SE messo SOLO sui giorni attivi di XS01
off_c, ph_c, _ = ANCH[1]
fC = GC.fvec_for(W_A, I, rate, off_c, xs_ann)
Rc, Gc = AP.rg_off(W_A, I, xs_shift(XSP[ph_c], -se_boot, active_only=True), off_c)
jc, lvc, _, _ = best_lev(Rc - fC, Gc, ev_b, fu_b)
ladc = GC.ladder(Rc - fC, Gc, N_LAD, lvc, SEED_LAD, refund=False)
bump(1)
rowm = D[(D["k"] == -1.0) & (D["anchor"] == "MEDIANA")].iloc[0]
print(f"\n CONTROLLO di convenzione (cella MEDIANA, -1 SE): spostare il drift su TUTTI i")
print(f" giorni da' J {rowm['J']:.3f} / P(>=50/g) {rowm['p50']:.1%}; spostarlo solo sui")
print(f" giorni ATTIVI ({act.mean():.0%} del campione) da' J {jc:.3f} / "
f"P(>=50/g) {ladc['p_target']:.1%} -> la conclusione NON dipende dalla convenzione.")
a1 = "CONFERMATA" if (0.2 * dj0 < dj_m1 < 0.8 * dj0) else "REFUTATA"
a2 = "CONFERMATA" if conv > 1.5 else "REFUTATA"
print(f" -> A1 (vantaggio a -1 SE fra il 20% e l'80%) {a1}; A2 (convessita') {a2}")
print("\n ⚠ Cio' che NON e' propagato qui, e va nel MIO verso (piu' incertezza, non meno):")
print(" (a) le 6 gambe non testabili — §29 misura che valgono il 42% di J e non sono")
print(" nel pannello U13 usato qui; (b) la SE del drift CRYPTO (5,15%/anno, §57),")
print(" che agisce su ENTRAMBE le strade e in parte si cancella nell'appaiato;")
print(" (c) l'incertezza sul maxDD di XS01 (10,8% -> 20,9-22,0% fuori campione),")
print(" che e' cio' che la barriera guarda.")
tick("§2")
# ============================================== §3 ATTACCO 2 — la morte-firm, misurata
hr("§3. ATTACCO 2 — LA MORTE-FIRM: cosa dice l'evidenza pubblica, e dove sta il break-even")
print(" Il progetto usa 10%/anno dal 24/07 ('il settore ha perso il 13% delle firm nel")
print(" 2024'), mai ri-misurato. Ricerca pubblica del 2026-08-23 (fonti SECONDARIE, in")
print(" larga parte siti di settore/affiliazione: qualita' dichiarata, non primaria):")
EVID = [
("Finance Magnates (stampa di settore)",
"80-100 firm chiuse fra 02/2024 e fine 2025", 0.18,
"~90 chiusure in ~22 mesi su una base attiva ~230 -> ~21%/anno lordo, ~18% netto entrate"),
("proptradingvibes (tracker, 07/2026)",
"302 tracciate, 230 attive, 72 chiuse", 0.12,
"23,8% cumulato sulla vita del tracker (orizzonte non dichiarato -> limite INFERIORE)"),
("thepropfirmguide / tradernotion (aggregatori)",
"55-65% della coorte 2020-2023 chiusa/sospesa/ristrutturata entro il 2026", 0.19,
"survival 0,40 su ~4 anni -> 20,5%/anno; a 55%: 18,1%/anno"),
("track360 / tradersyard (report di mercato)",
"120-150 firm retail attive nel 2026 contro 220+ nel 2023", 0.15,
"135/220 su 3 anni = 14,9%/anno, ma e' NETTO delle nuove entranti -> limite INFERIORE"),
]
print(f"\n {'fonte':>44} {'implica p/anno':>15}")
for src, claim, p, why in EVID:
print(f" {src:>44} {p:>14.0%} {claim}")
print(f" {'':>44} {why}")
p_lo = min(e[2] for e in EVID)
p_hi = max(e[2] for e in EVID)
p_mid = float(np.median([e[2] for e in EVID]))
print(f"\n BANDA IMPLICATA: **{p_lo:.0%} - {p_hi:.0%}/anno, mediana {p_mid:.0%}** contro il "
f"**{pl.FIRM_DEATH_PER_YEAR:.0%}** assunto.")
print(" ⚠ Tre riserve, tutte a favore del canale e tutte dichiarate: (i) 'chiusa/sospesa/")
print(" ristrutturata' e' piu' largo di 'sparita col saldo dentro'; (ii) i denominatori")
print(" delle fonti non coincidono (2.000 / 302 / 135 firm) e nessuna e' primaria;")
print(" (iii) FTMO (2015) e HyroTrader (2022) sono SOPRAVVISSUTE — condizionarsi su una")
print(" firm gia' vecchia abbassa il suo hazard, ma e' esattamente il survivorship bias")
print(" che non si puo' rivendicare a priori su un orizzonte di 36 mesi.")
PS = (0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.40, 0.55)
print(f"\n SWEEP su p (cella d'ancora MEDIANA, leva {lev_m:.2f}x, {N_LAD} percorsi ladder,")
print(f" {N_TIX} percorsi biglietto; tutto il resto CONGELATO):")
print(f" {'p/anno':>7} {'P(>=50/g)':>10} {'P(zero)':>9} {'EUR/g med':>10} "
f"{'EV spesa persa':>15} {'EV rimb.payout':>15} {'P(pass)':>8} {'P(payout)':>10}")
p_saved = pl.FIRM_DEATH_PER_YEAR
sw = []
for p in PS:
pl.FIRM_DEATH_PER_YEAR = p
lad = GC.ladder(R_M, G_M, N_LAD, lev_m, SEED_LAD, refund=True)
tix = GC.ticket_mc(R_M, G_M, lev_m, lev_m, 100_000.0, n_paths=N_TIX)
ev3 = GC.ev_three_ways(tix, 579.0)
bump(2)
sw.append(dict(p=p, p50=lad["p_target"], pz=lad["p_zero"], med=lad["med"],
sunk=ev3["sunk"], at_payout=ev3["at_payout"],
p_pass=tix["p_pass"], p_pay=tix["p_payout"]))
print(f" {p:>7.0%} {lad['p_target']:>9.1%} {lad['p_zero']:>8.1%} {lad['med']:>10.2f} "
f"${ev3['sunk']:>14,.0f} ${ev3['at_payout']:>14,.0f} {tix['p_pass']:>7.1%} "
f"{tix['p_payout']:>9.1%}")
pl.FIRM_DEATH_PER_YEAR = p_saved
SW = pd.DataFrame(sw)
neg = SW[SW["sunk"] <= 0]
if len(neg):
i1 = SW.index[SW["sunk"] <= 0][0]
x0, x1 = SW.loc[i1 - 1, "p"], SW.loc[i1, "p"]
y0, y1 = SW.loc[i1 - 1, "sunk"], SW.loc[i1, "sunk"]
p_be = x0 + (x1 - x0) * y0 / (y0 - y1)
print(f"\n BREAK-EVEN dell'EV (spesa persa, la convenzione conservativa): "
f"p* = **{p_be:.0%}/anno**")
else:
p_be = float("nan")
print(f"\n BREAK-EVEN dell'EV: **oltre {max(PS):.0%}/anno** (EV positivo su tutto lo sweep)")
p50_at_mid = float(np.interp(p_mid, SW["p"], SW["p50"]))
print(f" A p = {p_mid:.0%} (mediana dell'evidenza) P(>=50/g) scende "
f"{SW.loc[SW['p']==0.10,'p50'].iloc[0]:.1%} -> {p50_at_mid:.1%} "
f"({p50_at_mid/max(SW.loc[SW['p']==0.10,'p50'].iloc[0],1e-9)-1:+.0%})")
a3 = "CONFERMATA" if (0.15 <= p_mid <= 0.25 and (np.isnan(p_be) or p_be > p_hi)) else "PARZIALE"
print(f" -> A3 {a3}: la morte-firm vera e' plausibilmente {p_lo:.0%}-{p_hi:.0%}/anno, e il")
print(f" break-even dell'EV sta {'sopra' if (np.isnan(p_be) or p_be > p_hi) else 'DENTRO'} "
f"quella banda.")
print(" 📌 La lettura che conta NON e' l'EV (che regge): e' che P(>=50/g) e' gia' 2,6% e")
print(" l'errore sulla morte-firm la muove del ~{:.0f}% senza toccare nulla d'altro."
.format(abs(p50_at_mid / max(SW.loc[SW['p'] == 0.10, 'p50'].iloc[0], 1e-9) - 1) * 100))
tick("§3")
# ================================= §4 ATTACCO 3 — la frontiera P(>=50/g) contro P(zero)
hr("§4. ATTACCO 3 — LA FRONTIERA: P(>=50/g) e' una soglia sulla CODA DESTRA")
POL = [("LIVE 75/25/0", W_LIVE), ("W_A 38/38/25 (racc.)", W_A),
("38/25/38", {"TP01": 0.38, "SKH01": 0.25, "XS01": 0.38}),
("argmaxJ 25/25/50", W_ARGMAX),
("55/20/25 (book div 25/07)", {"TP01": 0.55, "SKH01": 0.20, "XS01": 0.25})]
LEVS_FR = LEVS
if time.time() - T0 > 0.45 * BUDGET_S:
LEVS_FR = LEVS[::2]
print(f" ⚠ BUDGET: leve della frontiera ridotte da {len(LEVS)} a {len(LEVS_FR)} "
f"(dichiarato).")
fr = []
for nm, w in POL:
fw = GC.fvec_for(w, I, rate, off_m, xs_ann)
Rw, Gw = AP.rg_off(w, I, XSP[ph_m], off_m)
Rw = Rw - fw
for lv in LEVS_FR:
lad = GC.ladder(Rw, Gw, N_LAD_FR, lv, SEED_LAD, refund=False)
bump(1)
fr.append(dict(pol=nm, lev=lv, p50=lad["p_target"], pz=lad["p_zero"],
med=lad["med"], p10g=lad["p_ge10"]))
F = pd.DataFrame(fr)
rho = float(np.corrcoef(F["p50"], F["pz"])[0, 1])
print(f" {len(POL)} politiche x {len(LEVS_FR)} leve = {len(F)} celle, cella d'ancora MEDIANA.")
print(f"\n corr( P(>=50/g) , P(zero) ) sulle {len(F)} celle = **{rho:+.3f}** -> A4 "
+ ("CONFERMATA" if rho > 0.5 else "REFUTATA"))
b50 = F.loc[F["p50"].idxmax()]
bz = F.loc[F["pz"].idxmin()]
bmed = F.loc[F["med"].idxmax()]
b10 = F.loc[F["p10g"].idxmax()]
print(f"\n {'obiettivo massimizzato':>28} {'politica':>26} {'leva':>6} {'P(>=50/g)':>10} "
f"{'P(zero)':>9} {'EUR/g med':>10}")
for lab, r in (("P(>=50 EUR/g) <- il citato", b50), ("P(zero) minima", bz),
("EUR/g mediana", bmed), ("P(>=10 EUR/g)", b10)):
print(f" {lab:>28} {r['pol']:>26} {r['lev']:>6.2f} {r['p50']:>9.1%} "
f"{r['pz']:>8.1%} {r['med']:>10.2f}")
rec = F[(F["pol"] == "W_A 38/38/25 (racc.)")]
rr = rec.loc[rec["p50"].idxmax()]
print(f"\n LA RACCOMANDAZIONE ({rr['pol']} @ {rr['lev']:.2f}x): P(>=50/g) {rr['p50']:.1%}, "
f"P(zero) {rr['pz']:.1%}, EUR/g {rr['med']:.2f}")
dom = F[(F["p50"] >= rr["p50"]) & (F["pz"] <= rr["pz"]) &
((F["p50"] > rr["p50"]) | (F["pz"] < rr["pz"]))]
print(f" Celle che la DOMINANO (>= su P(>=50/g) e <= su P(zero)): **{len(dom)}** su {len(F)}")
if len(dom):
d0 = dom.loc[dom["p50"].idxmax()]
print(f" la migliore: {d0['pol']} @ {d0['lev']:.2f}x -> {d0['p50']:.1%} / {d0['pz']:.1%}")
# frontiera di Pareto
pts = F.sort_values("pz")
par, best = [], -1.0
for _, r in pts.iterrows():
if r["p50"] > best:
par.append(r)
best = r["p50"]
P = pd.DataFrame(par)
print(f"\n FRONTIERA DI PARETO ({len(P)} punti non dominati su {len(F)}):")
print(f" {'P(zero)':>9} {'P(>=50/g)':>10} {'EUR/g med':>10} {'politica':>26} {'leva':>6}")
for _, r in P.iterrows():
star = " <== raccomandazione" if (r["pol"] == rr["pol"] and r["lev"] == rr["lev"]) else ""
print(f" {r['pz']:>8.1%} {r['p50']:>9.1%} {r['med']:>10.2f} {r['pol']:>26} "
f"{r['lev']:>6.2f}{star}")
print("\n 📌 Il prezzo del punto scelto, in unita' comprensibili: passare dal punto a")
print(" P(zero) minima a quello a P(>=50/g) massima costa "
f"{(F['pz'].max()-F['pz'].min())*100:.0f}pp di probabilita' di finire a ZERO per "
f"comprare {(F['p50'].max()-F['p50'].min())*100:.1f}pp di probabilita' di 50 EUR/g.")
tick("§4")
# ============================== §5 ATTACCO 4 — il gate che il canale non ha mai passato
hr("§5. ATTACCO 4 — IL NULL A DRIFT ZERO sulla griglia di 360 celle di PROP-ALLOC")
grid = PA.simplex_grid(("TP01", "SKH01", "XS01"), STEP_SIMPLEX)
n_cells = len(grid) * len(LEVS)
print(f" Griglia di SELEZIONE dichiarata da PROP-ALLOC: {len(grid)} vettori di peso "
f"(passo 1/{STEP_SIMPLEX}) x {len(LEVS)} leve = **{n_cells} celle**.")
print(" Conteggio dei trial al RIALZO, come vuole il progetto: PROP-ALLOC 360 di selezione")
print(" + la seconda firm (360) + PROP-RECAL su 3 finestre + le politiche del 25/07")
print(" -> l'ordine di grandezza del multiple testing sul CANALE e' ~1.000-2.000 celle,")
print(" e nessuno di questi filoni ha mai calcolato un deflated-Sharpe sul canale.")
print("\n IL NULL: stesso pannello, stessa lente, stesse regole, stessa griglia — ma il")
print(" DRIFT del libro azzerato (`R - mean(R)` per ogni vettore di peso). Domanda: quanto")
print(" J estrae un argmax su 360 politiche quando NON c'e' edge? (Con drift zero si passa")
print(" un'eval del +10% per pura varianza: il null NON e' zero.)")
ev_n = PA.boot_idx(len(I), EV_H, N_NULL_J, seed=SEED_EV)
fu_n = PA.boot_idx(len(I), FU_H, N_NULL_J, seed=SEED_FU)
RG = {}
for w in grid:
key = PA.wkey(w)
fw = GC.fvec_for(w, I, rate, off_m, xs_ann)
Rw, Gw = AP.rg_off(w, I, XSP[ph_m], off_m)
RG[key] = (Rw - fw, Gw)
def scan_grid(shift_to_zero: bool, ev_i, fu_i) -> np.ndarray:
out = np.empty(n_cells)
i = 0
for w in grid:
Rw, Gw = RG[PA.wkey(w)]
Rz = Rw - Rw.mean() if shift_to_zero else Rw
for lv in LEVS:
out[i] = PR.obj_rg(Rz, Gw, lv, ev_i, fu_i, factor=DELUCK)["J"]
i += 1
bump(n_cells)
return out
t = time.time()
J_real = scan_grid(False, ev_n, fu_n)
print(f"\n OSSERVATO ({time.time()-t:.0f}s): max-J su {n_cells} celle = **{J_real.max():.3f}** "
f"| mediana {np.median(J_real):.3f} | p90 {np.percentile(J_real,90):.3f}")
el = time.time() - T0
per_scan = max(time.time() - t, 1.0)
n_draws = N_NULL_DRAWS
while n_draws > 2 and el + (n_draws + 1) * per_scan > BUDGET_S:
n_draws -= 1
if n_draws != N_NULL_DRAWS:
print(f" ⚠ BUDGET: a {el:.0f}s con {per_scan:.0f}s a scansione, le estrazioni di null")
print(f" scendono da {N_NULL_DRAWS} a {n_draws}. Dichiarato, non nascosto: la MEDIA")
print(f" del max-J del null e' piu' rumorosa, la sua TAGLIA no.")
nulls = []
for b in range(n_draws):
ev_i = PA.boot_idx(len(I), EV_H, N_NULL_J, seed=9000 + 2 * b)
fu_i = PA.boot_idx(len(I), FU_H, N_NULL_J, seed=9001 + 2 * b)
Jn = scan_grid(True, ev_i, fu_i)
nulls.append(Jn)
print(f" null #{b+1}: max-J {Jn.max():.3f} · mediana {np.median(Jn):.3f} "
f"({time.time()-t:.0f}s)")
N = np.vstack(nulls)
nmax = N.max(axis=1)
print(f"\n NULL A DRIFT ZERO ({n_draws} estrazioni, {N_NULL_J} percorsi ciascuna):")
print(f" max-J atteso dal PURO RUMORE = **{nmax.mean():.3f}** "
f"[min {nmax.min():.3f}, max {nmax.max():.3f}]")
print(f" OSSERVATO {J_real.max():.3f} -> eccesso **{J_real.max()-nmax.mean():+.3f}** "
f"({(J_real.max()/max(nmax.mean(),1e-9)-1)*100:+.0f}%)")
print(f" estrazioni di null che BATTONO l'osservato: {int((nmax>=J_real.max()).sum())}"
f"/{n_draws}")
a5 = "CONFERMATA" if (0.25 <= nmax.mean() <= 0.45) else "REFUTATA"
print(f" -> A5 (max-J del null fra 0,25 e 0,45) {a5}")
# crescita del massimo col numero di celle: la sensibilita' del verdetto al CONTEGGIO
print(f"\n Sensibilita' al CONTEGGIO dei trial (max-J del null su sottoinsiemi casuali):")
rng = np.random.default_rng(4242)
print(f" {'k celle':>9} {'max-J null':>11} {'osservato':>11} {'eccesso':>9}")
for k in (45, 90, 180, 360):
mk = np.array([N[b, rng.choice(n_cells, size=min(k, n_cells), replace=False)].max()
for b in range(n_draws) for _ in range(4)])
ok = np.array([J_real[rng.choice(n_cells, size=min(k, n_cells), replace=False)].max()
for _ in range(20)]).mean()
print(f" {k:>9} {mk.mean():>11.3f} {ok:>11.3f} {ok-mk.mean():>+9.3f}")
# il gate STANDARD del progetto, puntato sul canale — e la sua CECITA' alla leva
import altlib as AL # noqa: E402
sh_w, ret_w = {}, {}
for w in grid:
Rw, Gw = RG[PA.wkey(w)]
Rd = PA.deluck(Rw, DELUCK)
v = float(Rd.std(ddof=1) * np.sqrt(365))
sh_w[PA.wkey(w)] = float(Rd.mean() * 365 / v) if v > 0 else 0.0
ret_w[PA.wkey(w)] = Rd
kb = max(sh_w, key=sh_w.get)
dsr, sr0 = AL.deflated_sharpe(sh_w[kb], list(sh_w.values()), ret_w[kb])
print(f"\n IL GATE STANDARD, per confronto — `altlib.deflated_sharpe` sulla stessa griglia:")
print(f" Sharpe migliore {sh_w[kb]:.3f} ({kb}) · attesa dal rumore su N={len(sh_w)} "
f"trial {sr0:.3f} · **DSR {dsr:.3f} {'PASS' if dsr >= 0.95 else 'FAIL'}**")
print(f" 🚨 Ma N e' **{len(sh_w)}, non {n_cells}**: lo Sharpe e' INVARIANTE ALLA LEVA")
print(f" (`obj_rg` lo calcola su `Rd`, non su `Rd*lev`), quindi le {n_cells-len(sh_w)}")
print(" celle che differiscono SOLO per la leva sono **invisibili** al gate standard.")
print(" E' esattamente la lezione di §33/§53: la leva non la vede nessun gate del")
print(" progetto. Su un conto a BARRIERA la leva e' la variabile che decide.")
# il libro LIVE, che NON e' stato selezionato, come incumbent
fL = GC.fvec_for(W_LIVE, I, rate, off_m, xs_ann)
RL, GL = AP.rg_off(W_LIVE, I, XSP[ph_m], off_m)
jL_all = [PR.obj_rg(RL - fL, GL, lv, ev_n, fu_n, factor=DELUCK)["J"] for lv in LEVS]
bump(len(LEVS))
print(f"\n L'INCUMBENT (libro LIVE 75/25, che NON e' stato selezionato su questa griglia):")
print(f" J max sulle 8 leve = {max(jL_all):.3f} -> anche l'incumbent "
f"{'SUPERA' if max(jL_all) > nmax.mean() else 'NON supera'} il max del null.")
print(" ⚠ CONTROLLO NEGATIVO obbligatorio: una estrazione di null trattata come se fosse")
print(" il candidato deve dare eccesso ~0 contro le altre.")
held = nmax[0]
rest = nmax[1:]
print(f" null #1 come candidato: max-J {held:.3f} contro media delle altre "
f"{rest.mean():.3f} -> eccesso {held-rest.mean():+.3f} "
f"({'OK, ~0' if abs(held-rest.mean()) < 0.05 else 'ATTENZIONE'})")
print("\n 📌 Cosa dice e cosa NON dice: **non** dice che il canale sia rumore — l'eccesso")
print(" e' misurato e positivo. Dice che **una parte non piccola del J pubblicato la")
print(" produce la varianza attraverso una barriera**, e che nessuno l'aveva sottratta.")
tick("§5")
# ================================================================== §6 il verdetto
hr("§6. LA DOMANDA FINALE — se il canale funded fosse un CANDIDATO-SLEEVE, passerebbe?")
ded = J_real.max() - nmax.mean()
checks = [
("edge in-sample (J > incumbent)", dj0 > 0.05,
f"dJ {dj0:+.3f} contro il libro live"),
("deflated / null di selezione", ded > 0.10,
f"eccesso sul max del null a drift zero {ded:+.3f} su {n_cells} celle"),
("robustezza al PARAMETRO (-1 SE)", dj_m1 > 0.05,
f"dJ a -1 SE del drift di XS01 = {dj_m1:+.3f}"),
("robustezza a -2 SE", dj_m2 > 0.05, f"dJ a -2 SE = {dj_m2:+.3f}"),
("assunzione esogena stimata", (not np.isnan(p_be)) and p_be > p_hi,
f"morte-firm: assunta {p_saved:.0%}, evidenza {p_lo:.0%}-{p_hi:.0%}, "
f"break-even {p_be:.0%}" if not np.isnan(p_be) else
f"morte-firm: assunta {p_saved:.0%}, evidenza {p_lo:.0%}-{p_hi:.0%}, break-even >55%"),
("obiettivo non degenere", len(dom) == 0,
f"{len(dom)} celle dominano la raccomandazione su (P(>=50/g), P(zero))"),
("deflated-Sharpe standard (cieco alla leva)", dsr >= 0.95,
f"DSR {dsr:.3f} su N={len(sh_w)} trial visibili di {n_cells} reali"),
("fuori dalla finestra di scoperta", True,
"§21: XS01 regge fuori campione (+1,12), MA a 13 gambe su 19 e a effetto/MDE ~1,0"),
("eseguibilita' verificata al venue", True,
"§30: 13/13 gambe `Trading` su Bybit, min notional $5 — PASS misurato"),
]
print(f" {'gate':>36} {'esito':>8} dettaglio")
npass = 0
for nm, ok, det in checks:
npass += int(ok)
print(f" {nm:>36} {'PASS' if ok else 'FAIL':>8} {det}")
print(f"\n {npass}/{len(checks)} gate superati.")
hr("VERDETTO")
print(f" 1. REPLICA: P(>=50 EUR/g) {m50:.1%} contro il pubblicato {PUB['p50g']:.1%}, "
f"P(zero) {C['pz'].median():.1%} contro {PUB['pzero']:.1%} -> **la macchina e' quella**.")
print(f" 2. IL PILASTRO: SE del drift di XS01 = {se_boot:.1%}/anno. A -1 SE il vantaggio "
f"del canale passa da {dj0:+.3f} a {dj_m1:+.3f} di J e P(>=50/g) da {p50_0:.1%} a "
f"{p50_m1:.1%}.")
print(f" 3. LA MORTE-FIRM: evidenza pubblica {p_lo:.0%}-{p_hi:.0%}/anno contro il "
f"{p_saved:.0%} assunto; l'EV regge (break-even "
f"{'>' + f'{max(PS):.0%}' if np.isnan(p_be) else f'{p_be:.0%}'}), "
f"ma P(>=50/g) scende a {p50_at_mid:.1%}.")
print(f" 4. LA FRONTIERA: corr(P(>=50/g), P(zero)) = {rho:+.3f}; "
f"{len(dom)} celle dominano il punto raccomandato.")
print(f" 5. IL GATE MANCANTE: max-J dal puro rumore su {n_cells} celle = {nmax.mean():.3f}, "
f"osservato {J_real.max():.3f}, eccesso {ded:+.3f}.")
eur_pt = float(C["med"].median())
eur_m1 = float(D[D["k"] == -1.0]["med"].median())
eur_live = float(D[D["k"] == 0.0]["med_live"].median())
print(f"\n IN EUR/GIORNO (mediana, 36 mesi, da 600 euro, funding e fisco dentro):")
print(f" canale funded al drift misurato ... {eur_pt:>6.2f} EUR/g")
print(f" canale funded a -1 SE ............ {eur_m1:>6.2f} EUR/g")
print(f" libro LIVE sullo stesso conto .... {eur_live:>6.2f} EUR/g")
print(f" obiettivo dichiarato ............. {pl.TARGET_EUR_DAY:>6.2f} EUR/g")
print(f"\n Questo filone NON avvicina i 50 EUR/giorno: non produce ritorno, "
f"riduce la fiducia")
print(f" nel numero gia' pubblicato. Il suo effetto sulla rendita attesa e' "
f"**{eur_m1-eur_pt:+.2f} EUR/g**")
print(f" se si crede a -1 SE, e **0,00 EUR/g** se non si cambia nulla (ed e' cio' che "
f"raccomanda).")
print(f"\n [{TRIALS} valutazioni, {time.time()-T0:.0f}s]")
print("=" * 104)
if __name__ == "__main__":
main()