research(wave-0822): ORTHO-SCREEN 7/7 scartato (e uno screen largo non puo' passare il proprio DSR); XS-LITE falsifica il muro dei 20k di XS01

This commit is contained in:
Adriano Dal Pastro
2026-08-22 17:12:15 +00:00
parent 14c1a75a7e
commit bd5b634209
6 changed files with 256 additions and 79 deletions
+58 -30
View File
@@ -303,6 +303,20 @@ def sizes_from_L(ex: dict, L: pd.Series) -> np.ndarray:
# --------------------------------------------------------------------------- libro
def sizes_of(nm, ex: dict, SZ: dict, VTL: dict, ACT: dict, Lbook: pd.Series | None = None):
"""Vettore di size per-trade di una cella qualsiasi. Un solo posto in cui e' definita:
§8 (eseguibilita'), §9 (deriva) e §10 (null di permutazione) devono usare LA STESSA."""
if nm is None or nm == "BASE":
return size_flat(ex)
if nm in SZ:
return SZ[nm](ex)
if nm in VTL:
return sizes_from_L(ex, leverage_series(ex["base_daily"], **VTL[nm]))
if nm in ACT:
return sizes_from_L(ex, activity_L(ex["base_daily"], **ACT[nm]))
return sizes_from_L(ex, Lbook)
def book(tp: pd.Series, skh: pd.Series) -> pd.Series:
return combine_outer({"TP01": tp, "SKH01": skh}, {"TP01": W_TP, "SKH01": W_SKH})
@@ -498,7 +512,8 @@ def main() -> None:
print(" de-levering (k<1 sul BASELINE che pareggia il maxDD della variante)")
print("-" * 112)
print(f" {'variante':<28}{'wSKH eff':>9}{'dShFULL':>9}{'pos/n':>8}{'dShHOLD':>9}{'pos/n':>8}"
f"{'| ISO dF':>10}{'pos/n':>8}{'ISO dH':>9}{'pos/n':>8}{'dDDpp':>8}{'k_iso':>8}")
f"{'| ISO dF':>10}{'pos/n':>8}{'ISO dH':>9}{'pos/n':>8}{'dDDpp':>8}{'k_iso':>8}"
f"{'null de-lev':>14}")
base_b = BK["BASE"]
RES = {}
for nm in ALL:
@@ -525,7 +540,13 @@ def main() -> None:
print(f" {nm:<28}{we:>9.3f}{dF['median_paired']:>+9.3f}{dF['n_positive']:>5}/{len(offs):<3}"
f"{dH['median_paired']:>+9.3f}{dH['n_positive']:>5}/{len(offs):<3}"
f"{iF['median_paired']:>+10.3f}{iF['n_positive']:>5}/{len(offs):<3}"
f"{iH['median_paired']:>+9.3f}{iH['n_positive']:>5}/{len(offs):<3}{dd:>+8.2f}{ks:>8}")
f"{iH['median_paired']:>+9.3f}{iH['n_positive']:>5}/{len(offs):<3}{dd:>+8.2f}{ks:>8}"
f"{vd:>14}")
print(" ⚠️ NOTA sul null del de-levering: `sh(k*base)` e' IDENTICO a `sh(base)` perche' lo")
print(" Sharpe e' invariante a una costante -> in questa forma il null COINCIDE col confronto")
print(" degli Sharpe, ed e' per questo che qui lo Sharpe e' la metrica che decide e il DD no.")
print(" 'k_iso' resta come diagnostica: quanta leva dovrebbe cedere il baseline per pareggiare")
print(" il maxDD della variante. 'DE-LEVERING' = la variante NON batte quel baseline ridotto.")
print(" wSKH eff = peso EFFETTIVO di SKH nel libro (i nominali restano 75/25: la size lo")
print(" muove). Colonne 'ISO' = confronto vs il baseline RI-SCALATO a quello stesso peso:")
print(" e' li' che si legge la FORMA. Le colonne non-ISO contengono anche il cambio di peso.")
@@ -687,24 +708,10 @@ def main() -> None:
f" anni positivi {npos}/{len(yrs)}")
print()
for nm in top:
if nm in SZ:
szs = np.concatenate([SZ[nm](EX[can][a]) for a in ASSETS])
dys = pd.DatetimeIndex(np.concatenate([EX[can][a]["day_ent"].values for a in ASSETS]))
elif nm in VTL or nm in ACT:
mk = ((lambda b: leverage_series(b, **VTL[nm])) if nm in VTL
else (lambda b: activity_L(b, **ACT[nm])))
szs, dys = [], []
for a in ASSETS:
szs.append(sizes_from_L(EX[can][a], mk(EX[can][a]["base_daily"])))
dys.append(EX[can][a]["day_ent"].values)
szs = np.concatenate(szs); dys = pd.DatetimeIndex(np.concatenate(dys))
else:
L = leverage_series(BK["BASE"][can], BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
szs, dys = [], []
for a in ASSETS:
szs.append(sizes_from_L(EX[can][a], L))
dys.append(EX[can][a]["day_ent"].values)
szs = np.concatenate(szs); dys = pd.DatetimeIndex(np.concatenate(dys))
Lb = (leverage_series(BK["BASE"][can], BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
if nm in BVT else None)
szs = np.concatenate([sizes_of(nm, EX[can][a], SZ, VTL, ACT, Lb) for a in ASSETS])
dys = pd.DatetimeIndex(np.concatenate([EX[can][a]["day_ent"].values for a in ASSETS]))
s = pd.Series(szs, index=dys)
med = s.groupby(s.index.year).median()
rho = float(np.corrcoef(np.arange(len(med)), med.values)[0, 1]) if len(med) > 2 else float("nan")
@@ -715,6 +722,33 @@ def main() -> None:
print(" (la vol crypto e' scesa lungo il campione -> qualunque 1/vol pesa di piu' il")
print(" periodo recente, che e' anche l'hold-out). La riga 'corr col tempo' la misura.")
# noqa
print("\n" + "-" * 112)
print(" 10. NULL DI PERMUTAZIONE DELLA SIZE — la stessa MULTINSIEME di size, riassegnata a")
print(" caso ai trade. Se il vantaggio a iso-peso sopravvive al null, conta QUALE trade")
print(" riceve quale size (informazione); se no, e' solo la DISTRIBUZIONE delle size.")
print("-" * 112)
rng = np.random.default_rng(20260822)
a10 = list(offs[:: max(1, len(offs) // 3)])[:3]
NDRAW = 150
for nm in dict.fromkeys([best_iso, best_sleeve]):
real = float(np.median([sh(BK[nm][o]) - sh(CTRL[nm][o]) for o in a10]))
nul = []
for _ in range(NDRAW):
v = []
for o in a10:
szp = {a: rng.permutation(sizes_of(nm, EX[o][a], SZ, VTL, ACT)) for a in ASSETS}
lg = leg_daily(EX[o], szp)
m_s = vol(lg) / vol(SLE["BASE"][o]) if vol(SLE["BASE"][o]) > 0 else 1.0
v.append(sh(book(TP, lg)) - sh(book(TP, SLE["BASE"][o] * m_s)))
nul.append(float(np.median(v)))
nul = np.asarray(nul)
pc = float((nul < real).mean()) * 100
print(f" {nm:<26} reale {real:+.3f} null mediana {np.median(nul):+.3f} "
f"p90 {np.percentile(nul, 90):+.3f} max {nul.max():+.3f} "
f"-> percentile {pc:.1f} (p ~ {(1 - pc / 100):.3f})")
print(f" {NDRAW} permutazioni x {len(a10)} ancore {a10}; seme fisso 20260822.")
print("\n" + "=" * 112)
print(f" fatto in {time.time()-t0:.0f}s")
print("=" * 112)
@@ -728,19 +762,13 @@ def netted_target(asset: str, ex: dict, nm, SZ, VTL, ACT, BVT, SLE, TP, can, df1
ts1 = df1h["timestamp"].values.astype(np.int64) + 3_600_000
pos = np.zeros(len(ts1))
L1h = np.ones(len(ts1))
if nm is None:
sizes = size_flat(ex)
elif nm in SZ:
sizes = SZ[nm](ex)
elif nm in VTL:
sizes = sizes_from_L(ex, leverage_series(ex["base_daily"], **VTL[nm]))
elif nm in ACT:
sizes = sizes_from_L(ex, activity_L(ex["base_daily"], **ACT[nm]))
else: # BOOKVT
if nm is not None and nm in BVT: # BOOKVT: leva anche sulla gamba TP01
L = leverage_series(book(TP, SLE["BASE"][can]), BVT[nm]["tv"], BVT[nm]["w"], BVT[nm]["cap"])
sizes = sizes_from_L(ex, L)
sizes = sizes_of(nm, ex, SZ, VTL, ACT, L)
idx1h = pd.DatetimeIndex(pd.to_datetime(df1h["timestamp"].values, unit="ms", utc=True))
L1h = L.reindex(idx1h.floor("D")).ffill().fillna(1.0).values
else:
sizes = sizes_of(nm, ex, SZ, VTL, ACT)
t_in, t_out = ex["ts_close"][ex["i_ent"]], ex["ts_close"][ex["i_ex"]]
for k in range(len(t_in)):
j0 = int(np.searchsorted(ts1, t_in[k], side="left"))