research(wave-0822): VOL-SIZE — il p-value del null di permutazione si cita col segno, non col decimale (3 ancore su 23)

This commit is contained in:
Adriano Dal Pastro
2026-08-22 17:24:10 +00:00
parent e8bbb92f8a
commit f975272ec8
4 changed files with 550 additions and 22 deletions
+53 -14
View File
@@ -466,35 +466,54 @@ def main() -> None:
print(f"\n[3] XS01 — soglia PUBBLICATA ~$20.000 (origine: stima a occhio, 'rumore arrotondamento')")
Wxs, dret, C, cols, dif = xs01_pesi()
print(f" prova d'identita' col sleeve ufficiale `_xsec_returns()`: max|diff| = {dif:.3e}")
from src.portfolio.sleeves import XS_CFG, _xsec_returns
off_xs = _xsec_returns()
m_off = metriche(off_xs.values, pd.DatetimeIndex(off_xs.index))
gross_xs = np.abs(Wxs).sum(axis=1)
att = gross_xs > 1e-9
dW = np.abs(np.diff(Wxs, axis=0, prepend=np.zeros((1, Wxs.shape[1]))))
tk_nz = dW[dW > 1e-9]
# DUE popolazioni di ordini, e vanno separate: il RIBILANCIAMENTO del segnale (ogni H=10 giorni,
# cambia il paniere 5+5) e la DERIVA del vol-target (ogni giorno, micro-aggiustamenti).
H = XS_CFG["H"]
is_reb = np.zeros(len(Wxs), bool); is_reb[::H] = True
reb = dW[is_reb]; reb = reb[reb > 1e-9]
drift = dW[~is_reb]; drift = drift[drift > 1e-9]
print(f" sleeve ufficiale `_xsec_returns()`: Sharpe {m_off['sharpe']:.2f} "
f"maxDD {m_off['maxdd']:.1f}% CAGR {m_off['cagr']:.1f}%")
print(f" gambe simultanee: {int((np.abs(Wxs) > 1e-9).sum(axis=1)[att].max())} "
f"(k=5 long + 5 short); lordo mediano {np.median(gross_xs[att]):.2f}x il capitale "
f"(vol-target, cap 3x)")
print(f" peso mediano mosso per gamba per ribilanciamento: {np.median(tk_nz)*100:.2f}% "
f"del capitale; 10° pctl {np.percentile(tk_nz,10)*100:.2f}%")
print(f"\n ticket per gamba (mediano) e % di gambe ESEGUIBILI, per capitale allocato a XS01:")
print(f" {'cap XS01':>10}{'ticket med':>12}{'ticket p10':>12}"
f"{'>=$5 [D]':>10}{'>=$10 [C]':>11}{'lotto ko':>10}")
print(f"\n DUE popolazioni di ordini (separarle e' il punto: non hanno la stessa taglia):")
print(f" RIBILANCIAMENTO (ogni {H}g, cambia il paniere): n={len(reb)} "
f"peso mosso mediano {np.median(reb)*100:.2f}% p10 {np.percentile(reb,10)*100:.2f}%")
print(f" DERIVA vol-target (giornaliera) : n={len(drift)} "
f"peso mosso mediano {np.median(drift)*100:.3f}% p10 {np.percentile(drift,10)*100:.3f}%")
print(f" -> {100*len(drift)/max(len(reb)+len(drift),1):.0f}% degli ordini sono DERIVA, "
f"ed e' la deriva che il pavimento taglia.")
print(f"\n ticket per gamba e % di ordini RICHIESTI eseguibili, per capitale allocato a XS01")
print(f" (conto = capitale/0.15, perche' XS01 pesa 15% del book di ricerca):")
print(f" {'cap XS01':>10}{'conto @15%':>12}{'tick reb':>10}{'tick drift':>12}"
f"{'>=$5 [D]':>10}{'>=$10 [C]':>11}{'reb>=$10':>10}")
R_xs = dret
idx = C.index
base = None
for cap in CAPITALI:
med = np.median(tk_nz) * cap
p10 = np.percentile(tk_nz, 10) * cap
pct5 = 100.0 * float((tk_nz * cap >= MIN_ORDER_ASSUNTO).mean())
pct10 = 100.0 * float((tk_nz * cap >= MIN_ORDER_HL).mean())
lot = np.array([meta.loc[s, "lot_usd"] if s in meta.index else 0.0 for s in cols])
lotko = 100.0 * float((tk_nz * cap < np.median(lot)).mean())
print(f" {cap:>10,.0f}{med:>12.2f}{p10:>12.2f}{pct5:>9.0f}%{pct10:>10.0f}%{lotko:>9.1f}%")
pr10 = 100.0 * float((reb * cap >= MIN_ORDER_HL).mean())
print(f" {cap:>10,.0f}{cap/0.15:>12,.0f}{np.median(reb)*cap:>10.2f}"
f"{np.median(drift)*cap:>12.2f}{pct5:>9.0f}%{pct10:>10.0f}%{pr10:>9.0f}%")
lot_xs = np.array([float(meta.loc[s, "lot_usd"]) if s in meta.index else 0.0 for s in cols])
px_xs = np.array([float(meta.loc[s, "markPx"]) if s in meta.index else np.nan for s in cols])
fee_xs_mod = 0.001 / 2.0 # [D] cio' che il sleeve modella: 5 bps/lato
print(f"\n haircut di eseguibilita' (Sharpe modellato - Sharpe realistico), fee {fee_xs_mod*1e4:.1f} bps/lato:")
print(f"\n haircut di eseguibilita' (Sharpe modellato - Sharpe realistico), fee {fee_xs_mod*1e4:.1f} bps/lato.")
print(f" NB il 'Sh mod' qui INCLUDE la fee sulla deriva del vol-target, che lo sleeve "
f"ufficiale NON addebita")
print(f" (`turn=|dW|` prima dello scaling): e' il motivo per cui sta sotto il "
f"{m_off['sharpe']:.2f} pubblicato.")
print(f" {'cap XS01':>10}{'Sh mod':>9}{'Sh $5 [D]':>11}{'Sh $10 [C]':>12}"
f"{'haircut $10':>13}{'esegui%':>9}")
f"{'haircut $10':>13}{'ordini fatti':>14}")
for cap in CAPITALI:
m0 = sim_libro(Wxs, R_xs, None, cap, None, None, None, fee_xs_mod)
m5 = sim_libro(Wxs, R_xs, None, cap, MIN_ORDER_ASSUNTO, None, None, fee_xs_mod)
@@ -506,9 +525,29 @@ def main() -> None:
# ---------------------------------------------------------------- 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 build_panel # stessa costruzione del monitor in produzione
from scripts.live.paper_xsr import FEE_LEG, MIN_ORDER, _book, _step, build_panel
ts, dtx, Wx, Rx, rbx, sx = build_panel()
idxx = pd.DatetimeIndex(dtx)
# PROVA D'IDENTITA' col monitor IN PRODUZIONE: sim_libro deve riprodurre paper_xsr._step
# barra per barra. Senza questa, i numeri qui sotto sarebbero di un'altra macchina.
for mo in (None, MIN_ORDER):
bk = _book(5000.0, len(sx))
ref = np.array([_step(bk, Wx[i], Rx[i], float(rbx[i]), mo) for i in range(len(Wx))])
mine = sim_libro(Wx, Rx, rbx, 5000.0, mo, None, None, FEE_LEG)["net"]
print(f" identita' vs scripts/live/paper_xsr._step (min_order={mo}): "
f"max|diff| = {np.abs(ref - mine).max():.3e}")
assert abs(FEE_LEG - FEE_LEG_MODELLO) < 1e-12, "la config congelata di XSR01 e' cambiata"
assert abs(MIN_ORDER - MIN_ORDER_ASSUNTO) < 1e-12, "il min-order del monitor e' cambiato"
# RICONCILIAZIONE col numero PUBBLICATO (1.82): la scoperta (r0725_statarb_basket_gate,
# basket_from_positions) addebita "2 gambe per coppia" = 50 alt + 50 BTC. Ma il demeaning
# ANNULLA la gamba BTC (sum dei pesi = 0): non si tradano 50 BTC, se ne trada UNA di taglia
# zero. Il monitor in produzione lo sa (`d_btc = |sum(w_new) - sum(w_held)|` ~ 0) -> il
# pubblicato SOVRASTIMA le fee di ~2x.
net_x2 = sim_libro(Wx, Rx, rbx, 5000.0, None, None, None, 2 * FEE_LEG_MODELLO)["net"]
print(f" riconciliazione col pubblicato 1.82: a fee RADDOPPIATA (= convenzione della "
f"scoperta, 2 gambe/coppia) Sharpe {metriche(net_x2, idxx)['sharpe']:.2f}")
lot_x = np.array([float(meta.loc[s, "lot_usd"]) if s in meta.index else 0.0 for s in sx])
px_x = np.array([float(meta.loc[s, "markPx"]) if s in meta.index else np.nan for s in sx])
dWx = np.abs(np.diff(Wx, axis=0, prepend=np.zeros((1, Wx.shape[1]))))
@@ -516,7 +555,7 @@ def main() -> None:
print(f" gambe {len(sx)} lordo mediano {np.median(np.abs(Wx).sum(axis=1)):.2f}x "
f"peso mosso mediano/gamba {np.median(tkx)*100:.3f}% p10 {np.percentile(tkx,10)*100:.3f}%")
print(f"\n {'cap':>9}{'ticket med':>12}{'Sh mod':>9}{'Sh $5 [D]':>11}{'Sh $10 [C]':>12}"
f"{'haircut $5':>12}{'haircut $10':>13}{'esegui%':>9}")
f"{'haircut $5':>12}{'haircut $10':>13}{'ordini fatti':>14}")
hc10_5000 = np.nan
for cap in CAPITALI:
m0 = sim_libro(Wx, Rx, rbx, cap, None, None, None, FEE_LEG_MODELLO)