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:
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user