research(wave-0822): lo scettico conferma il gradino di leva ma corregge due contorni — e la lente close-only e' cieca solo sulle regole a UN giorno

This commit is contained in:
Adriano Dal Pastro
2026-08-22 17:36:45 +00:00
parent 5fe931e00d
commit 32ed18222e
3 changed files with 134 additions and 34 deletions
+64 -28
View File
@@ -271,6 +271,15 @@ def main() -> None:
("V1", EXV1, FUN_V1, BK1, CT1)):
lg = legs(EXX, FUN)
base = lg["BASE"]
if tag == "V2":
# controlli di §1(c): L calcolata sulla gamba COMBINATA (cio' che fa il ramo
# NAIVE del bersaglio), applicata nei DUE modi. Se coincidono, il "fantasma"
# non e' un problema di QUANDO si applica la size.
for w in (30, 90):
Lc = V.leverage_series(base, **dict(FROZEN, w=w))
lg[f"NAIVEcomb w{w}"] = base * Lc.reindex(base.index).fillna(1.0)
lg[f"COMBingr w{w}"] = V.leg_daily(
EXX, {a: V.sizes_from_L(EXX[a], Lc) for a in ASSETS})
for nm, s in lg.items():
b, c, m_s = iso_pair(TP, s, base)
BKd.setdefault(nm, {})[o] = b
@@ -386,32 +395,29 @@ def main() -> None:
print(f" {a}: max|dif| = {np.max(np.abs(j['a']-j['b'])):.2e} "
f"Sh ingresso {sh(s_in):.4f} vs Sh moltiplicazione {sh(s_mul):.4f}")
print("\n (c) ALLORA COS'E' IL '+0,04 FANTASMA'? Il controllo NAIVE del bersaglio calcola L")
print(" sulla gamba 50/50 COMBINATA; la versione 'causale' la calcola PER ASSET.")
print(" Terza variante di controllo: L combinata, applicata come size all'INGRESSO.")
lg_base = {o: None for o in offs}
d_comb, d_perass = [], []
for o in offs[: min(6, len(offs))]:
E2 = {a: V.extract(a, o) for a in ASSETS}
base = V.leg_daily(E2, {a: V.size_flat(E2[a]) for a in ASSETS})
Lc = V.leverage_series(base, **FROZEN)
naive = base * Lc.reindex(base.index).fillna(1.0)
comb_in = V.leg_daily(E2, {a: V.sizes_from_L(E2[a], Lc) for a in ASSETS})
per_ass = V.leg_daily(
E2, {a: V.sizes_from_L(E2[a], V.leverage_series(E2[a]["base_daily"], **FROZEN))
for a in ASSETS})
j = pd.concat({"a": naive, "b": comb_in}, axis=1, join="inner").dropna()
d_comb.append(float(np.max(np.abs(j["a"] - j["b"]))))
b1, c1, _ = iso_pair(TP, naive, base)
b2, c2, _ = iso_pair(TP, per_ass, base)
d_perass.append(sh(hold(b1)) - sh(hold(c1)) - (sh(hold(b2)) - sh(hold(c2))))
del E2
print(f" L combinata: 'moltiplica la serie' vs 'size all'ingresso' -> "
f"max|dif| mediano {np.median(d_comb):.2e} (identiche)")
print(f" differenza ISO dShHOLD [L combinata] - [L per asset], mediana appaiata su "
f"{len(d_perass)} ancore: {np.median(d_perass):+.3f}")
print(" -> il divario NAIVE/CAUSALE non e' QUANDO si applica la size, e' SU QUALE")
print(" SERIE si calcola L (gamba combinata vs per asset).")
print("\n (c) ALLORA COS'E' IL '+0,04 FANTASMA'? Il ramo NAIVE del bersaglio calcola L")
print(" sulla gamba 50/50 COMBINATA e MOLTIPLICA la serie; il ramo 'causale' calcola L")
print(" PER ASSET e la applica all'INGRESSO. Sono DUE differenze in una. Le separo:")
for w in (30, 90):
d = []
for o in offs:
j = pd.concat({"a": BK2[f"NAIVEcomb w{w}"][o], "b": BK2[f"COMBingr w{w}"][o]},
axis=1, join="inner").dropna()
d.append(float(np.max(np.abs(j["a"] - j["b"]))))
print(f" w{w}: [L combinata, MOLTIPLICA] vs [L combinata, size all'INGRESSO] -> "
f"max|dif| mediano {np.median(d):.2e} = IDENTICHE")
print(f"\n {'coppia':<38}{'dShFULL':>10}{'dShHOLD':>10} (delta GREZZI vs baseline nudo,")
print(f" {'':<38}{'':>10}{'':>10} la convenzione del §4 del bersaglio)")
for w in (30, 90):
for nm in (f"NAIVEcomb w{w}", f"COMBingr w{w}",
(lead if w == 90 else f"VTL tv20 w{w}")):
gF = A.anchor_luck_delta(lambda o, n=nm: BK2[n][o], lambda o: BK2["BASE"][o], offs,
metric=sh)
gH = A.anchor_luck_delta(lambda o, n=nm: hold(BK2[n][o]),
lambda o: hold(BK2["BASE"][o]), offs, metric=sh)
print(f" {nm:<38}{gF['median_paired']:>+10.3f}{gH['median_paired']:>+10.3f}")
print(" -> il 'fantasma' e' interamente [L combinata] - [L per asset]: una scelta di")
print(" SERIE DI RIFERIMENTO, non un look-ahead. Il ramo NAIVE non e' non-causale.")
# ------------------------------------------------------------------ §2 TEST PRE-REGISTRATO
print("\n" + "-" * L)
@@ -560,7 +566,34 @@ def main() -> None:
# ------------------------------------------------------------------ §5 sintesi
print("\n" + "-" * L)
print(" 5. SINTESI DEI NUMERI CHE CONTANO")
print(" 5. GATE (per il contratto di consegna)")
print("-" * L)
can = offs[0]
legs_can = {}
for nm in ("BASE", lead, "BIN L>=med (0/1)"):
legs_can[nm] = (V.leg_daily(EXV2, {a: V.size_flat(EXV2[a]) for a in ASSETS})
if nm == "BASE"
else V.leg_daily(EXV2, {a: FUN_V2[nm](EXV2[a]) for a in ASSETS}))
nlos = int((EXV2["BTC"]["net"] < 0).sum() + (EXV2["ETH"]["net"] < 0).sum())
ntot = int(len(EXV2["BTC"]["net"]) + len(EXV2["ETH"]["net"]))
for nm, s_ in legs_can.items():
m = A.marginal_vs_tp01(s_)
imp = A.implausible_sharpe(s_, n_trades=ntot, n_losing_trades=nlos)
print(f" {nm:<22} marginal {str(m.get('marginal_verdict')):<9} corr {m.get('corr_full')}"
f" implausible={imp['implausible']} (perdite/attive "
f"{imp.get('loss_frac', 0)*100:.1f}%)")
trials = [float(np.median([sh(BK2[n][o]) for o in offs])) for n in BK2]
dsr_c, sr0 = A.deflated_sharpe(float(np.median([sh(BK2[lead][o]) for o in offs])), trials,
BK2[lead][can])
dsr_b, _ = A.deflated_sharpe(med_F, trials, BK2["BASE"][can])
print(f" deflated-Sharpe: candidato {dsr_c:.3f} / BASELINE {dsr_b:.3f} su {len(trials)} "
f"trial (sd {np.std(trials, ddof=1):.4f}) -> VACUO, lo passa anche il baseline")
print(" null de-levering: DEGENERE per costruzione (sh(k*base) == sh(base)); il suo")
print(" sostituto e' il confronto ISO-PESO usato in tutte le tabelle sopra.")
print(" causalita': §1(a) 50/50 size ricalcolate da dati troncati, max|dif| 0.00e+00.")
print("\n" + "-" * L)
print(" 6. SINTESI DEI NUMERI CHE CONTANO")
print("-" * L)
print(f" fortuna d'ancora del LIBRO BASE: ShFULL canonico "
f"{sh(BK2['BASE'][0]) if 0 in BK2['BASE'] else float('nan'):.3f} vs mediana "
@@ -569,7 +602,10 @@ def main() -> None:
f"{dLEADH['median_paired']:+.3f} HOLD")
print(f" riprodotto dal FILTRO BINARIO: {RES['BIN L>=1 (0/1)']['dF']:+.3f} FULL / "
f"{RES['BIN L>=1 (0/1)']['dH']:+.3f} HOLD")
print(f" controllo di segno (INVERSO): {RES['BIN L<1 (INVERSO)']['dF']:+.3f} FULL")
print(f" riprodotto dal BINARIO alla MEDIANA:{RES['BIN L>=med (0/1)']['dF']:+.3f} FULL / "
f"{RES['BIN L>=med (0/1)']['dH']:+.3f} HOLD ({RES['BIN L>=med (0/1)']['nF']}/{len(offs)} ancore)")
print(f" controllo di segno (INVERSO): {RES['BIN L<1 (INVERSO)']['dF']:+.3f} FULL "
f"({RES['BIN L<1 (INVERSO)']['nF']}/{len(offs)}) -> il filtro e' reale, non un artefatto")
print(f"\n fatto in {time.time()-t0:.0f}s")
print("=" * L)