research(wave-0703): migliora+proteggi VRP01 — 7 filoni, 0 miglioramenti, anchor-audit VRP01 chiuso (4/4 sleeve)

Goal: migliorare la strategia short-vol (famiglia Albimarini/VRP01) e
proteggerla dai DD. Workflow 26 agenti (7 filoni + 2 lenti avversariali
+ scettico incrociato). Esito: NON migliorabile; la protezione DD si
compra SOLO con la size.

- Griglia 288 strutture: nessuna batte VRP01 (DSR 0.000; meta' griglia
  = 3a occorrenza "0-perdite/Sharpe implausibile" dopo CC01/ALB-A).
- 4 overlay DD (exit-spike/SL-MTM/ala-coda/cooldown): 4/4 REFUTED dal
  null de-levering — la protezione crash vive gia' nel gate IV-rank.
- Gate nuovi: 4o fallimento su 4 (l'alpha e' il binario IV-rank>0.30).
- Sizing: 12% deploy ~ 0.27 Kelly onesto (anti-rovina); disambiguazione
  unita' obbligatoria vs 12% peso book (0.014 Kelly, fattore 19x).
- Gate term-structure VIX/VXV su SPX (dSh +0.90, DSR 0.992) = confound
  di modello al 100% -> nuova regola: riprezzare term-structure-consistent
  prima di credere a un gate vol su strutture BS-flat.
- ANCHOR-AUDIT VRP01 CHIUSO: primo sleeve SENZA luck (fase canonica =
  peggiore delle 7 -> numeri di ammissione conservativi). Audit anchor
  ora completo su 4/4 sleeve ancorati.

Book/pesi INVARIATI. Nessun nuovo sleeve. 168 test verdi.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-03 07:05:19 +00:00
parent 76120b59c2
commit 26f8d27a61
9 changed files with 3668 additions and 0 deletions
+426
View File
@@ -0,0 +1,426 @@
"""R0703 VRPIMP-STRUCTGRID — griglia ONESTA di struttura short-vol vs VRP01 canonico.
FILONE 1 (2026-07-03). L'audit ALB-A (r0702_alb_structure) ha testato UNA cella a priori
(z=2.0σ, ali +1σ, tenor 5g). Domanda: nella griglia onesta
distanza z ∈ {1.0, 1.5, 2.0, 2.5}σ × tenor ∈ {3, 5, 7, 10}g × ali dz ∈ {+0.5, +1.0, +2.0}σ
× lato {put-only, call-only, entrambi} × struttura {vertical, condor, diagonal T+1}
esiste una cella che batte VRP01 canonico (put credit spread settimanale Δ-0.28/-0.10, gate
IV-rank) in modo che SOPRAVVIVE a (a) selezione IN-SAMPLE-ONLY, (b) deflated-Sharpe sul numero
TOTALE di celle, (c) banda f, (d) plateau dei vicini, (e) null del de-levering?
MAPPATURA lato×struttura (9 combo nominali -> 6 DISTINTE, per non contare doppio):
vertical×put = VERT-PUT vertical×call = VERT-CALL vertical×both ≡ CONDOR
condor×put ≡ VERT-PUT condor×call ≡ VERT-CALL condor×both = CONDOR
diagonal×{put,call,both} = DIAG-PUT / DIAG-CALL / DIAG-2 (Albimarini)
Totale celle = 4z × 4tenor × 3dz × 6 strutture = 288 (tutte contate nel deflated-Sharpe).
REGOLE RISPETTATE:
- Gate IV-rank CANONICO sempre attivo, NON riottimizzato (vrp>0 AND 0.30<=ivr<=0.90,
identico a VRP01 combo e a r0702_alb_structure gated=True).
- Selezione cella SOLO su Sharpe PRE-holdout (2021-03 .. 2024-12); hold-out 2025-26 mai
guardato per scegliere. DSR (Bailey & LdP, altlib.deflated_sharpe) su tutte le 288 celle.
- Pattern "0-perdite = Sharpe implausibile" (CC01, ALB-A): le celle con < MIN_LOSS_IS
perdite attive in-sample sono ESCLUSE DALLA SELEZIONE E DICHIARATE (coda mai campionata
-> Sharpe non informativo). Il criterio usa SOLO dati in-sample (niente peek).
- Banda f {0.6, 0.8, 1.0, 1.3} + scenario skew (f_put=1.3 / f_call=0.7) su ogni claim
(pricing BS FLAT su DVOL-30g: il deep-OTM e' banda, non stima puntuale).
- Banda d'ancora (regola 2026-07-02): la cella scelta si riporta su TUTTE le fasi di
partenza 0..tenor-1 (il costrutto e' ancorato alla cadenza tenor_d).
- NULL DEL DE-LEVERING (lezione TP01×DVOL): ogni vantaggio di DD della cella si confronta
con VRP01 semplicemente scalato allo stesso DD (Sharpe invariante per scala).
- Confronto apples-to-apples: oltre a VRP01 canonico (motore options_vrp_v2, capitale=K_short,
fee=12.5% del premio) si riporta il BRIDGE (stessa struttura di VRP01 nel motore nuovo:
vert-put z=0.583 dz=0.699 7g, capitale=S0, fee per-gamba) — battere solo VRP01 canonico
ma non il bridge = artefatto di convenzione fee/capitale, non struttura.
MACCHINERIA RIUSATA (non riscritta): motore di r0702_alb_structure (bs_put/bs_call/_fee_frac/
metrics/to_daily_lumped, VALIDATO vs run_structure cella-per-cella in testa al run),
options_vrp_v2.vrp_spread_weekly (VRP01 canonico esatto), altlib.deflated_sharpe/marginal_vs_tp01.
Regola standing: NIENTE short-vol da modello in deploy — l'esito massimo e' conoscenza/LEAD.
uv run python scripts/research/r0703_vrpimp_structgrid.py
"""
from __future__ import annotations
import json
import math
import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
sys.path.insert(0, str(PROJECT_ROOT / "scripts" / "research" / "alt"))
import numpy as np, pandas as pd # noqa: E402
from scipy.stats import norm # noqa: E402
from scripts.research.options_vrp_lab import bs_put, load_series, per_year # noqa: E402
from scripts.research.options_vrp_v2 import vrp_spread_weekly, _ivrank, _rv30 # noqa: E402
from scripts.research.r0702_alb_structure import ( # noqa: E402
bs_call, _fee_frac, run_structure, metrics, to_daily_lumped, DAY, HOLDOUT)
import altlib as al # noqa: E402
SCRATCH = Path("/tmp/claude-1001/-opt-docker-PythagorasGoal/e00896d3-d4bb-4f2a-b471-55a1d88a12ba/scratchpad")
F_SWEEP = (0.6, 0.8, 1.0, 1.3)
F_SKEW = dict(f_put=1.3, f_call=0.7) # skew crypto-shaped: put ricche, call povere
Z_GRID = (1.0, 1.5, 2.0, 2.5)
TENOR_GRID = (3, 5, 7, 10)
DZ_GRID = (0.5, 1.0, 2.0)
STRUCTS = (("same", "put", "VERT-PUT"), ("same", "call", "VERT-CALL"), ("same", "both", "CONDOR"),
("diag", "put", "DIAG-PUT"), ("diag", "call", "DIAG-CALL"), ("diag", "both", "DIAG-2"))
MIN_ACT_IS = 30 # trade attivi minimi in-sample per credere allo Sharpe IS
MIN_LOSS_IS = 3 # perdite attive minime IS: <3 = coda mai campionata (CC01/ALB-A) -> ESCLUSA
CUTS = ("2022-01-01", "2023-01-01", "2024-01-01", "2025-01-01") # persistenza multi-cut
# bridge = la struttura ESATTA di VRP01 dentro il motore nuovo (delta -0.28/-0.10, 7g)
Z_BRIDGE = float(-norm.ppf(0.28)) # ~0.583
DZ_BRIDGE = float(-norm.ppf(0.10)) - Z_BRIDGE # ~0.699
# --------------------------------------------------------------------------- dati + gate cache
_S: dict = {}
def S(asset):
"""(px, dv, idx, skip) con gate canonico VRP01 precomputato (identico a r0702/options_vrp_v2)."""
if asset not in _S:
J = load_series(asset)
px = J["px"].values.astype(float)
dv = (J["dvol"].values / 100.0).astype(float)
n = len(px)
skip = np.zeros(n, dtype=bool)
for i in range(n):
rv = _rv30(px, i)
ivr = _ivrank(dv, i)
skip[i] = ((not np.isnan(rv) and (dv[i] - rv) <= 0)
or (not np.isnan(ivr) and (ivr < 0.30 or ivr > 0.90)))
_S[asset] = (px, dv, J.index, skip)
return _S[asset]
# --------------------------------------------------------------------------- motore generalizzato
def run_cell(asset, expiry, side, z, dz, tenor_d, f_put=1.0, f_call=1.0, offset=0):
"""Vendita sistematica non-overlapping della struttura, cadenza tenor_d, GATE CANONICO SEMPRE.
expiry: 'same' (long stessa scadenza) | 'diag' (long T+1g, mark BS a exit — vega)
side: 'put' | 'call' | 'both'
Identica contabilita' di r0702_alb_structure.run_structure (validata sotto): capitale = S0,
fee Deribit per gamba 0.03% notional cap 12.5% premio, delivery 0.015% su short ITM, exit fee
sulle long residue del diag. offset = fase d'ancora (banda d'ancora)."""
px, dv, idx, skip = S(asset)
n = len(px)
T = tenor_d / 365.25
T_long = T + DAY if expiry == "diag" else T
rets = {}
i = 60 + offset
while i + tenor_d < n:
j = i + tenor_d
if skip[i]:
rets[idx[j]] = 0.0
i = j
continue
S0 = px[i]; sig = dv[i]; m = sig * math.sqrt(T)
S1 = px[j]; sig1 = dv[j]
credit = short_pay = long_val = exit_fee = deliv = 0.0
legs = []
if side in ("put", "both"):
Ks = S0 * math.exp(-z * m); Kl = S0 * math.exp(-(z + dz) * m)
ps = bs_put(S0, Ks, T, sig) / S0 * f_put
pl = bs_put(S0, Kl, T_long, sig) / S0 * f_put
credit += ps - pl; legs += [ps, pl]
short_pay += max(0.0, Ks - S1) / S0
deliv += _fee_frac(max(0.0, Ks - S1) / S0, rate=0.00015)
if expiry == "diag":
lv = bs_put(S1, Kl, DAY, sig1) / S0 * f_put
long_val += lv
exit_fee += _fee_frac(lv, notional_ratio=S1 / S0)
else:
long_val += max(0.0, Kl - S1) / S0
if side in ("call", "both"):
Ks = S0 * math.exp(+z * m); Kl = S0 * math.exp(+(z + dz) * m)
cs = bs_call(S0, Ks, T, sig) / S0 * f_call
cl = bs_call(S0, Kl, T_long, sig) / S0 * f_call
credit += cs - cl; legs += [cs, cl]
short_pay += max(0.0, S1 - Ks) / S0
deliv += _fee_frac(max(0.0, S1 - Ks) / S0, rate=0.00015)
if expiry == "diag":
lv = bs_call(S1, Kl, DAY, sig1) / S0 * f_call
long_val += lv
exit_fee += _fee_frac(lv, notional_ratio=S1 / S0)
else:
long_val += max(0.0, S1 - Kl) / S0
entry_fee = sum(_fee_frac(v) for v in legs)
rets[idx[j]] = credit - short_pay + long_val - entry_fee - exit_fee - deliv
i = j
return pd.Series(rets)
def book_cell(expiry, side, z, dz, tenor_d, **kw):
rB = run_cell("BTC", expiry, side, z, dz, tenor_d, **kw)
rE = run_cell("ETH", expiry, side, z, dz, tenor_d, **kw)
return pd.concat({"B": rB, "E": rE}, axis=1, join="inner").mean(axis=1)
def vrp01_book(f):
return pd.concat({a[0]: vrp_spread_weekly(a, defined_risk=True, f=f, gate_vrp=True,
gate_ivr=0.30, crash_skip=0.90)
for a in ("BTC", "ETH")}, axis=1, join="inner").mean(axis=1)
# --------------------------------------------------------------------------- utilita' report
def _sh_window(r, tenor_d, start=None, end=None):
w = r
if start is not None:
w = w[w.index >= pd.Timestamp(start, tz="UTC")]
if end is not None:
w = w[w.index < pd.Timestamp(end, tz="UTC")]
ppy = 365.25 / tenor_d
return float(w.mean() / w.std() * np.sqrt(ppy)) if len(w) > 5 and w.std() > 0 else float("nan")
def dd_of(r, lam=1.0):
eq = np.cumprod(1 + lam * r.values)
pk = np.maximum.accumulate(eq)
return float(np.max((pk - eq) / pk))
def scale_to_dd(r, dd_target):
"""λ tale che il maxDD di λ·r == dd_target (null del de-levering)."""
lo, hi = 0.01, 3.0
for _ in range(60):
mid = 0.5 * (lo + hi)
if dd_of(r, mid) > dd_target:
hi = mid
else:
lo = mid
return 0.5 * (lo + hi)
def validate_engine():
"""run_cell deve riprodurre ESATTAMENTE run_structure (motore ALB-A validato) su 3 kind."""
print(" [validazione motore] run_cell vs r0702_alb_structure.run_structure (z=2, dz=1, 5g, gated):")
ok = True
for kind, (expiry, side) in (("diag", ("diag", "both")), ("condor", ("same", "both")),
("vert", ("same", "put"))):
for a in ("BTC", "ETH"):
ref = run_structure(a, kind, z=2.0, dz=1.0, tenor_d=5, gated=True)
new = run_cell(a, expiry, side, 2.0, 1.0, 5)
d = float((ref - new).abs().max()) if len(ref) == len(new) else float("inf")
ok &= d < 1e-12
print(f" {kind:<7}{a}: n={len(new):>4} max|Δ|={d:.2e}")
if not ok:
raise SystemExit("ENGINE MISMATCH: run_cell non riproduce run_structure — stop.")
print(" -> motore identico (riuso validato, non riscrittura).")
def main():
print("=" * 112)
print(" R0703 VRPIMP-STRUCTGRID — griglia onesta 288 celle di struttura short-vol vs VRP01 canonico")
print(" Gate IV-rank canonico SEMPRE attivo (mai riottimizzato). Selezione IN-SAMPLE-ONLY (pre-2025).")
print(" ⚠️ SKEW: pricing BS FLAT su DVOL-30g -> banda f {0.6,0.8,1.0,1.3} + scenario fp=1.3/fc=0.7.")
print(" Regola standing: NIENTE short-vol da modello in deploy — esito massimo = conoscenza/LEAD.")
print("=" * 112)
validate_engine()
# ------------------------------------------------------------- (1) VRP01 canonico + bridge
print("\n (1) BASELINE — VRP01 canonico (options_vrp_v2 COMBO) e bridge motore-nuovo, banda f")
hdr = (f" {'riga':<38} {'ShF':>6} {'ShIS':>6} {'ShH':>6} {'CAGR':>7} {'maxDD':>6} "
f"{'worst':>7} {'win%':>5} {'att%':>5}")
print(hdr)
vrp = {}
for f in F_SWEEP:
vrp[f] = vrp01_book(f)
mm = metrics(vrp[f], 7); mi = metrics(vrp[f][vrp[f].index < HOLDOUT], 7)
print(f" VRP01 canonico f={f:<4} {'':<16} {mm['sh']:>6.2f} {mi['sh']:>6.2f} {mm['sh_h']:>6.2f} "
f"{mm['cagr']*100:>+6.1f}% {mm['dd']*100:>5.1f}% {mm['worst']*100:>+6.2f}% "
f"{mm['win']*100:>4.0f}% {mm['act']*100:>4.0f}%")
bridge = {}
for f in F_SWEEP:
bridge[f] = book_cell("same", "put", Z_BRIDGE, DZ_BRIDGE, 7, f_put=f, f_call=f)
mm = metrics(bridge[f], 7); mi = metrics(bridge[f][bridge[f].index < HOLDOUT], 7)
print(f" bridge vert-put Δ-0.28/-0.10 7g f={f:<4} {mm['sh']:>6.2f} {mi['sh']:>6.2f} {mm['sh_h']:>6.2f} "
f"{mm['cagr']*100:>+6.1f}% {mm['dd']*100:>5.1f}% {mm['worst']*100:>+6.2f}% "
f"{mm['win']*100:>4.0f}% {mm['act']*100:>4.0f}%")
print(" (bridge = stessa struttura di VRP01 nel motore-griglia: e' il confronto apples-to-apples;")
print(" battere VRP01 ma non il bridge = artefatto di convenzione fee/capitale, non struttura)")
# ------------------------------------------------------------- (2) griglia 288 celle, f=1.0
print(f"\n (2) GRIGLIA {len(STRUCTS)}x{len(Z_GRID)}x{len(DZ_GRID)}x{len(TENOR_GRID)} = "
f"{len(STRUCTS)*len(Z_GRID)*len(DZ_GRID)*len(TENOR_GRID)} celle (f=1.0, gate canonico)")
cells = {}
for expiry, side, lab in STRUCTS:
for z in Z_GRID:
for dz in DZ_GRID:
for tn in TENOR_GRID:
r = book_cell(expiry, side, z, dz, tn)
r_is = r[r.index < HOLDOUT]
act_is = r_is[r_is != 0]
rec = dict(expiry=expiry, side=side, lab=lab, z=z, dz=dz, tn=tn, r=r,
mi=metrics(r_is, tn), mm=metrics(r, tn),
nact_is=int(len(act_is)), nloss_is=int((act_is < 0).sum()))
rec["eligible"] = (rec["nact_is"] >= MIN_ACT_IS and rec["nloss_is"] >= MIN_LOSS_IS)
cells[(lab, z, dz, tn)] = rec
all_full_sh = [c["mm"]["sh"] for c in cells.values()]
all_is_sh = [c["mi"]["sh"] for c in cells.values()]
n_cells = len(cells)
inel = [c for c in cells.values() if not c["eligible"]]
print(f" celle totali {n_cells} | ESCLUSE dalla selezione (implausibili: <{MIN_LOSS_IS} perdite IS "
f"o <{MIN_ACT_IS} trade IS): {len(inel)} — dichiarate sotto, contate comunque nel DSR")
# il pattern '0-perdite': cosa avremmo scelto SENZA il filtro
naive = max(cells.values(), key=lambda c: c["mi"]["sh"])
print(f"\n [pattern CC01/ALB-A] best IS SENZA filtro implausibilita': {naive['lab']} z={naive['z']} "
f"dz={naive['dz']} {naive['tn']}g -> ShIS {naive['mi']['sh']:.2f} (perdite IS: {naive['nloss_is']}, "
f"trade IS: {naive['nact_is']}) | suo hold-out ShH {naive['mm']['sh_h']:+.2f}")
top_inel = sorted(inel, key=lambda c: c["mi"]["sh"], reverse=True)[:8]
print(" top celle ESCLUSE (ShIS alto MA coda mai campionata in-sample -> Sharpe non informativo):")
for c in top_inel:
print(f" {c['lab']:<10} z={c['z']} dz={c['dz']} {c['tn']:>2}g ShIS {c['mi']['sh']:>6.2f} "
f"perdite-IS {c['nloss_is']:>2} su {c['nact_is']:>3} trade -> ShH {c['mm']['sh_h']:>+6.2f}")
# ------------------------------------------------------------- (3) selezione in-sample-only
elig = [c for c in cells.values() if c["eligible"]]
ch = max(elig, key=lambda c: c["mi"]["sh"])
print(f"\n (3) SELEZIONE IN-SAMPLE-ONLY (fra le {len(elig)} eleggibili) + top-10")
print(f" {'cella':<34} {'ShIS':>6} {'ShF':>6} {'ShH':>6} {'DD':>6} {'worst':>7} {'lossIS':>7}")
for c in sorted(elig, key=lambda c: c["mi"]["sh"], reverse=True)[:10]:
mark = " <== SCELTA" if c is ch else ""
print(f" {c['lab']:<10} z={c['z']} dz={c['dz']} tenor={c['tn']:>2}g{'':<6} {c['mi']['sh']:>6.2f} "
f"{c['mm']['sh']:>6.2f} {c['mm']['sh_h']:>6.2f} {c['mm']['dd']*100:>5.1f}% "
f"{c['mm']['worst']*100:>+6.2f}% {c['nloss_is']:>4}/{c['nact_is']:<4}{mark}")
tn = ch["tn"]
dsr_full, sr0_full = al.deflated_sharpe(ch["mm"]["sh"], all_full_sh, ch["r"], dpy=365.25 / tn)
r_is = ch["r"][ch["r"].index < HOLDOUT]
dsr_is, sr0_is = al.deflated_sharpe(ch["mi"]["sh"], all_is_sh, r_is, dpy=365.25 / tn)
print(f"\n DSR cella scelta (N={n_cells} trial): FULL {dsr_full:.3f} (null-max ~{sr0_full:.2f}) | "
f"IS {dsr_is:.3f} (null-max ~{sr0_is:.2f}) | PASS richiede >= 0.95")
# nota anti-hindsight: la cella col miglior HOLD-OUT fra le eleggibili NON e' selezionabile
# (selection-on-holdout, gate 2026-06-29); la riporto solo per chiudere la domanda ovvia.
hb = max(elig, key=lambda c: c["mm"]["sh_h"])
dsr_hb, _ = al.deflated_sharpe(hb["mm"]["sh"], all_full_sh, hb["r"], dpy=365.25 / hb["tn"])
rank_is = 1 + sum(1 for c in elig if c["mi"]["sh"] > hb["mi"]["sh"])
print(f" [anti-hindsight] best HOLD-OUT fra le eleggibili: {hb['lab']} z={hb['z']} dz={hb['dz']} "
f"{hb['tn']}g (ShIS {hb['mi']['sh']:.2f}, rank-IS #{rank_is}, ShH {hb['mm']['sh_h']:.2f}, "
f"DSR {dsr_hb:.3f}) — sceglierla = selection-on-holdout, VIETATO; e comunque DSR<0.95.")
# ------------------------------------------------------------- (4) cella scelta: banda f vs VRP01
print(f"\n (4) CELLA SCELTA {ch['lab']} z={ch['z']} dz={ch['dz']} {tn}g — banda f vs VRP01 e bridge")
print(f" {'f':<22} {'cella ShF/ShH':>16} {'VRP01 ShF/ShH':>16} {'bridge ShF/ShH':>16} "
f"{'cella DD/worst':>17} {'VRP01 DD/worst':>17}")
ch_f = {}
beats_vrp = beats_bridge = True
for f in F_SWEEP:
rr = book_cell(ch["expiry"], ch["side"], ch["z"], ch["dz"], tn, f_put=f, f_call=f)
ch_f[f] = rr
m = metrics(rr, tn); v = metrics(vrp[f], 7); b = metrics(bridge[f], 7)
beats_vrp &= (m["sh"] > v["sh"]) and (m["sh_h"] > v["sh_h"])
beats_bridge &= (m["sh"] > b["sh"]) and (m["sh_h"] > b["sh_h"])
print(f" f={f:<20} {m['sh']:>7.2f}/{m['sh_h']:>6.2f} {v['sh']:>8.2f}/{v['sh_h']:>6.2f} "
f"{b['sh']:>8.2f}/{b['sh_h']:>6.2f} {m['dd']*100:>7.1f}%/{m['worst']*100:>+6.2f}% "
f"{v['dd']*100:>7.1f}%/{v['worst']*100:>+6.2f}%")
rr = book_cell(ch["expiry"], ch["side"], ch["z"], ch["dz"], tn, **F_SKEW)
m = metrics(rr, tn)
print(f" SKEW fp=1.3/fc=0.7 {m['sh']:>7.2f}/{m['sh_h']:>6.2f} (VRP01/bridge non hanno lato call)")
py_c = per_year(ch_f[1.0]); py_v = per_year(vrp[1.0])
print(" per-anno cella f=1.0: " + " ".join(f"{y}:{v*100:+5.1f}%" for y, v in sorted(py_c.items())))
print(" per-anno VRP01 f=1.0: " + " ".join(f"{y}:{v*100:+5.1f}%" for y, v in sorted(py_v.items())))
# persistenza multi-cut del presunto vantaggio (ΔSh cella - bridge, finestre [cut, end))
print(" multi-cut ΔSh (cella - bridge | cella - VRP01) su [cut, fine):")
for cut in CUTS:
d_b = _sh_window(ch_f[1.0], tn, start=cut) - _sh_window(bridge[1.0], 7, start=cut)
d_v = _sh_window(ch_f[1.0], tn, start=cut) - _sh_window(vrp[1.0], 7, start=cut)
print(f" {cut}: {d_b:+.2f} | {d_v:+.2f}")
# ------------------------------------------------------------- (5) banda d'ancora
print(f"\n (5) BANDA D'ANCORA — cella scelta su tutte le {tn} fasi di partenza (offset 0..{tn-1})")
anch = []
for o in range(tn):
ro = book_cell(ch["expiry"], ch["side"], ch["z"], ch["dz"], tn, offset=o)
mo = metrics(ro, tn)
anch.append((o, mo["sh"], mo["sh_h"]))
print(f" offset {o}: ShF {mo['sh']:>5.2f} ShH {mo['sh_h']:>+5.2f}")
shf = [a[1] for a in anch]; shh = [a[2] for a in anch]
print(f" banda ShF [{min(shf):.2f}, {max(shf):.2f}] mediana {np.median(shf):.2f} | "
f"ShH [{min(shh):+.2f}, {max(shh):+.2f}] mediana {np.median(shh):+.2f}")
# ------------------------------------------------------------- (6) plateau dei vicini
print(f"\n (6) PLATEAU — slice {ch['lab']} dz={ch['dz']}: matrice z × tenor (ShIS / ShH)")
print(" " + "".join(f"{t:>14}g" for t in TENOR_GRID))
for z in Z_GRID:
rowtxt = f" z={z:<4}"
for t in TENOR_GRID:
c = cells[(ch["lab"], z, ch["dz"], t)]
star = "*" if (z == ch["z"] and t == tn) else " "
rowtxt += f" {c['mi']['sh']:>5.2f}/{c['mm']['sh_h']:>+5.2f}{star}"
print(rowtxt)
print(" vicini dz (a z/tenor scelti): " + " ".join(
f"dz={d}: ShIS {cells[(ch['lab'], ch['z'], d, tn)]['mi']['sh']:.2f}/"
f"ShH {cells[(ch['lab'], ch['z'], d, tn)]['mm']['sh_h']:+.2f}" for d in DZ_GRID))
neigh = []
zi, ti, di = Z_GRID.index(ch["z"]), TENOR_GRID.index(tn), DZ_GRID.index(ch["dz"])
for (gi, grid, mk) in ((zi, Z_GRID, "z"), (ti, TENOR_GRID, "tn"), (di, DZ_GRID, "dz")):
for step in (-1, +1):
k = gi + step
if 0 <= k < len(grid):
key = dict(z=ch["z"], tn=tn, dz=ch["dz"]); key[mk] = grid[k]
neigh.append(cells[(ch["lab"], key["z"], key["dz"], key["tn"])])
n_pos = sum(1 for c in neigh if c["mi"]["sh"] > 0 and c["mm"]["sh_h"] > 0)
print(f" vicini adiacenti (±1 passo per asse): {len(neigh)} | con ShIS>0 E ShH>0: {n_pos}")
# ------------------------------------------------------------- (7) null del de-levering
print("\n (7) NULL DEL DE-LEVERING — il vantaggio DD della cella e' replicabile scalando VRP01?")
m_c = metrics(ch_f[1.0], tn); m_v = metrics(vrp[1.0], 7)
lam = scale_to_dd(vrp[1.0], m_c["dd"])
scaled = lam * vrp[1.0]
m_s = metrics(scaled, 7)
print(f" cella: Sh {m_c['sh']:.2f} / ShH {m_c['sh_h']:.2f} DD {m_c['dd']*100:.1f}% "
f"worst {m_c['worst']*100:+.2f}% CAGR {m_c['cagr']*100:+.1f}%")
print(f" VRP01 pieno: Sh {m_v['sh']:.2f} / ShH {m_v['sh_h']:.2f} DD {m_v['dd']*100:.1f}% "
f"worst {m_v['worst']*100:+.2f}% CAGR {m_v['cagr']*100:+.1f}%")
print(f" VRP01 × λ={lam:.2f}: Sh {m_s['sh']:.2f} / ShH {m_s['sh_h']:.2f} DD {m_s['dd']*100:.1f}% "
f"worst {m_s['worst']*100:+.2f}% CAGR {m_s['cagr']*100:+.1f}%")
delever_kills = (m_c["dd"] < m_v["dd"]) and (m_s["sh"] >= m_c["sh"]) and (m_s["sh_h"] >= m_c["sh_h"])
print(" -> lo scaling lascia lo Sharpe invariato: ogni vantaggio di DD e' replicabile con λ,"
f" la cella vale SOLO se Sh/ShH superiori. delever_null_kills={delever_kills}")
# ------------------------------------------------------------- (8) marginale/corr
print("\n (8) CORRELAZIONE + MARGINALE (informativo, non promozione: regola standing short-vol)")
d_c = to_daily_lumped(ch_f[1.0]); d_v = to_daily_lumped(vrp[1.0])
w_c = (1 + d_c).resample("168h", origin="epoch").prod() - 1 # origin comune (lezione '7D')
w_v = (1 + d_v).resample("168h", origin="epoch").prod() - 1
Jw = pd.concat({"c": w_c, "v": w_v}, axis=1, join="inner").dropna()
print(f" corr settimanale cella~VRP01: {Jw['c'].corr(Jw['v']):+.2f} "
f"(alta = stesso trade in altri vestiti)")
mv = al.marginal_vs_tp01(d_c)
print(f" marginal_vs_tp01[cella]: verdict={mv.get('marginal_verdict')} corr={mv.get('corr_full')} "
f"IS-Sh={mv.get('cand_insample_sharpe')} insample_edge={mv.get('has_insample_edge')} "
f"hedge={mv.get('is_hedge')} robust_oos={mv.get('robust_oos')}")
# ------------------------------------------------------------- (9) verdetto
print("\n (9) VERDETTO")
dsr_pass = bool(np.isfinite(dsr_full) and dsr_full >= 0.95 and np.isfinite(dsr_is) and dsr_is >= 0.95)
wins = beats_vrp and beats_bridge and dsr_pass and not delever_kills
print(f" batte VRP01 su tutta la banda f (ShF e ShH): {beats_vrp}")
print(f" batte il bridge (stesso motore) su tutta la banda f: {beats_bridge}")
print(f" DSR>=0.95 su {n_cells} celle (FULL {dsr_full:.3f} / IS {dsr_is:.3f}): {dsr_pass}")
print(f" sopravvive al null del de-levering: {not delever_kills}")
print(f" ==> {'ESISTE una cella che batte VRP01 onestamente' if wins else 'NESSUNA cella batte VRP01 onestamente'}")
print(" (esecuzione: comunque STAT-MODE — niente short-vol da modello in deploy;")
print(" muri di size Deribit invariati dal filone capital-scaling: spread ETH ~2.6k+, BTC ~4.7k+)")
# dump metriche per il report
SCRATCH.mkdir(parents=True, exist_ok=True)
dump = {f"{k[0]}|z{k[1]}|dz{k[2]}|t{k[3]}": dict(
is_sh=c["mi"]["sh"], full_sh=c["mm"]["sh"], hold_sh=c["mm"]["sh_h"], dd=c["mm"]["dd"],
worst=c["mm"]["worst"], nact_is=c["nact_is"], nloss_is=c["nloss_is"], eligible=c["eligible"])
for k, c in cells.items()}
(SCRATCH / "r0703_structgrid_results.json").write_text(json.dumps(dump, indent=1))
print(f"\n [dump] {SCRATCH / 'r0703_structgrid_results.json'}")
if __name__ == "__main__":
main()