research(wave-0822): HL-EXEC refuta il muro dei 20k di XS01 e lo slippage come rischio #1 — e il 20k di venue e' un'altra cosa

This commit is contained in:
Adriano Dal Pastro
2026-08-22 17:33:55 +00:00
parent ea22a0e20c
commit 090129359b
7 changed files with 920 additions and 31 deletions
+31 -5
View File
@@ -312,7 +312,7 @@ def metriche(net: np.ndarray, idx: pd.DatetimeIndex) -> dict:
# ==================================================================================================
# 4. XS01 — ricostruzione dei PESI (il sleeve espone solo i ritorni) + prova d'identita'
# ==================================================================================================
def xs01_pesi():
def xs01_pesi(phase: int = 0):
from src.portfolio.sleeves import XS_CFG, XS_UNIVERSE, _xsec_returns
cols = {}
for sym in XS_UNIVERSE:
@@ -334,7 +334,7 @@ def xs01_pesi():
w = np.zeros(A)
hist: list[float] = []
for i in range(n):
if i >= mlb and i % H == 0:
if i >= mlb and i % H == phase:
rLs = [px[i] / px[i - L] - 1.0 for L in lb]
di = float(np.mean([r.std() for r in rLs]))
thr = np.percentile(hist, dp) if (dp > 0 and len(hist) >= mh) else -np.inf
@@ -361,9 +361,12 @@ def xs01_pesi():
rv = s.rolling(30, min_periods=15).std().shift(1) * np.sqrt(365.25)
scale = np.clip(np.nan_to_num(tv / rv.replace(0, np.nan).values, nan=0.0), 0, 3.0)
# prova d'identita' col sleeve UFFICIALE (max|diff| deve essere 0.0)
off = _xsec_returns()
dif = float(np.abs(pd.Series(s.values * scale, index=C.index).reindex(off.index).values
- off.values).max())
if phase == 0:
off = _xsec_returns()
dif = float(np.abs(pd.Series(s.values * scale, index=C.index).reindex(off.index).values
- off.values).max())
else:
dif = float("nan")
# posizione TENUTA durante la barra i = W[i-1]*scale[i] => posta a fine barra i: W[i]*scale[i+1]
pos_scale = np.concatenate([scale[1:], scale[-1:]])
return W * pos_scale[:, None], dret, C, list(C.columns), dif
@@ -541,6 +544,29 @@ def main() -> None:
f"{hc:>12.0f}%{m10['pct_eseguite']:>8.0f}% ord "
f"{m10['pct_nozionale']:>4.0f}% ntl")
# -------- fortuna di FASE: l'haircut e' un DELTA, e in questo progetto ogni delta misurato
# su una griglia ancorata eredita la fortuna dell'ancora (lezione 2026-07-26). XS01 ribilancia
# ogni H=10 giorni -> 10 fasi. Statistica giusta: MEDIANA DELLE DIFFERENZE APPAIATE.
print(f"\n [gate anchor] haircut per FASE del ciclo H={H} (pavimento $10, "
f"mediana delle differenze appaiate):")
print(f" {'fase':>6}{'Sh mod':>9}{'Sh $10':>9}{'haircut':>10} (cap XS01 $600)")
hb = []
for ph in range(H):
Wp, dp_, Cp, colsp, _ = xs01_pesi(ph)
lp = np.array([float(meta.loc[x, "lot_usd"]) if x in meta.index else 0.0 for x in colsp])
pp = np.array([float(meta.loc[x, "markPx"]) if x in meta.index else np.nan for x in colsp])
s0 = metriche(sim_libro(Wp, dp_, None, 600.0, None, None, None, fee_xs_mod)["net"], Cp.index)["sharpe"]
s1 = metriche(sim_libro(Wp, dp_, None, 600.0, MIN_ORDER_HL, lp, pp, fee_xs_mod)["net"], Cp.index)["sharpe"]
hb.append(s0 - s1)
print(f" {ph:>6}{s0:>9.2f}{s1:>9.2f}{s0-s1:>+10.3f}")
hb = np.array(hb)
print(f" mediana appaiata {np.median(hb):+.3f} Sharpe banda [{hb.min():+.3f}, {hb.max():+.3f}]"
f" fasi con danno >0.10: {int((hb > 0.10).sum())}/{H}")
print(f" -> il pavimento HL non e' un costo per XS01 a NESSUNA fase, non solo alla canonica.")
print(f" (sottoprodotto: la colonna 'Sh mod' REPLICA il phase-luck del 2026-07-02 — la fase")
print(f" canonica 0 sta in alto e la MEDIANA delle fasi e' ben sotto: e' l'audit di XS01,")
print(f" ritrovato per caso da un'altra strada.)")
# ---------------------------------------------------------------- 4. XSR01
print(f"\n[4] XSR01 — soglia PUBBLICATA ~$5.000, gate 2026-10-23 con haircut a $5.000 <= 40%")
from scripts.live.paper_xsr import FEE_LEG, MIN_ORDER, _book, _step, build_panel