Files
PythagorasGoal/scripts/research/r0822_xs_lite.py
T

787 lines
43 KiB
Python

"""XS-LITE — esiste una versione CONCENTRATA (2-8 gambe) degli edge cross-sectional del progetto
che conservi una frazione utile dell'edge ed e' ESEGUIBILE OGGI a $600-5.000?
LA DOMANDA (mai posta in questa forma). Il progetto ha due edge cross-sectional che dichiara di non
poter eseguire per TAGLIA, non per debolezza:
XS01 — 19 major HL, long 5 / short 5, ribilancio ogni 10g. Dichiarato eseguibile da ~$20k.
XSR01 — 50 alt HL, residuo OLS su BTC demeanato cross-sezionalmente. Dichiarato ~$5k.
Il vincolo dichiarato e' il **min order** moltiplicato per il numero di gambe. Se si riducono le
gambe il vincolo si allenta — ma l'ampiezza (il numero di scommesse indipendenti) crolla, e
l'ampiezza e' l'unica ragione per cui una strategia cross-sectional ha uno Sharpe alto.
Questo script misura il CAMBIO, non lo assume. E misura anche la premessa: che il muro sia il
min-order.
IPOTESI PRE-REGISTRATE (scritte prima di guardare i numeri):
(a) lo Sharpe scende con k come ~sqrt(ampiezza): k=2-3 conserva il 40-60% dell'edge;
(b) il min-order NON e' il muro di XS01 a $600 (a k=5 il ticket e' 0.5/5 del capitale dello
sleeve), e il "serve $20k" viene dal TURNOVER del vol-target, non dalla taglia della posizione;
(c) XSR01 concentrato perde molto di piu', perche' il suo edge E' l'ampiezza (il progetto ha gia'
misurato che il demeaning porta l'ampiezza 4.5 -> 37.4: e' quel numero, non il segnale, a
fare lo Sharpe 1.82).
Con 2.6 anni di storia monoregime il verdetto atteso e' LEAD o SCARTATO, mai CANDIDATO.
MECCANISMI CONGELATI — non si rifitta nulla.
XS01 : blend lookback (30,90), gate dispersione p30 espandente causale, H=10, vol-target 20%,
cap 3x, fee 5 bps per unita' di turnover. UNICO parametro variato: k (gambe per lato).
Replica bit-exact di src.portfolio.sleeves._xsec_returns verificata al passo (0).
XSR01: W=45, sgn=+1, residuo OLS rolling causale su BTC, z-score, tanh, vol-target 20%, cap 2x,
demean cross-sezionale giornaliero, fee 5 bps/gamba. Segnale IMPORTATO da
r0725_statarb_multi, paniere da r0725_statarb_basket_gate (nessuna reimplementazione).
UNICO parametro variato: k.
Il LOOKBACK NON e' stato riaperto DI PROPOSITO: riaprire un parametro riapre la sua famiglia
(lezione VRP-tenore, 30/07) e moltiplicherebbe i trial. Qui si varia solo la CONCENTRAZIONE.
GRIGLIA DICHIARATA PRIMA DI MISURARE: 2 famiglie x 2 universi x 6 valori di k (+ il "pieno" di
XSR01) = 26 celle valutabili. Le 10 fasi del ciclo H=10 di XS01 sono una banda d'ANCORA, non una
griglia di parametri (regola del progetto: il deflated-Sharpe non le conta) -> riportate come
mediana onesta e come differenze APPAIATE. Il deflated-Sharpe e' comunque pubblicato a N=26 E a
N=156 (sensibilita' del verdetto al conteggio, lezione 30/07).
nice -n 19 timeout 900 uv run python scripts/research/r0822_xs_lite.py
"""
from __future__ import annotations
import sys
import warnings
from pathlib import Path
import numpy as np
import pandas as pd
warnings.filterwarnings("ignore")
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "scripts" / "research"))
sys.path.insert(0, str(ROOT / "scripts" / "research" / "alt"))
import altlib as A # noqa: E402
from src.portfolio.sleeves import XS_CFG, XS_UNIVERSE, _xsec_returns # noqa: E402
from r0725_statarb_multi import BASE, load_hl, pnl, signal # noqa: E402
from r0725_statarb_basket_gate import basket_from_positions, pair_frames # noqa: E402
RAW = ROOT / "data" / "raw"
ANN = np.sqrt(365.25)
HOLDOUT = A.HOLDOUT # 2025-01-01 (convenzione altlib)
MIN_ORDER_HL = 10.0 # Hyperliquid: min order $10 (r0702_capital_scaling)
MIN_ORDER_5 = 5.0 # il $5 di Deribit, citato nella missione
KS = (1, 2, 3, 4, 5, 6) # 5 = canonico XS01
COST_SWEEP = (0.0, 5.0, 10.0, 20.0, 30.0, 50.0) # bps per gamba TOTALI (fee + slippage)
# capitali dello SLEEVE. Il progetto tiene XS01 al 15% del book -> a book $600 lo sleeve ha $90.
# Si misurano entrambe le letture, perche' e' esattamente qui che nasce il numero "$20k".
SLEEVE_CAPS = (90.0, 300.0, 600.0, 750.0, 2000.0, 5000.0)
# =====================================================================================
# misure
# =====================================================================================
def sh(s) -> float:
r = np.asarray(pd.Series(s).dropna().values, float)
return float(r.mean() / r.std() * ANN) if len(r) > 30 and r.std() > 0 else 0.0
def dd(s) -> float:
r = np.nan_to_num(np.asarray(pd.Series(s).values, float))
eq = np.cumprod(1.0 + np.clip(r, -0.99, None))
return float(np.min(eq / np.maximum.accumulate(eq) - 1.0))
def cagr(s) -> float:
x = pd.Series(s).dropna()
if len(x) < 30:
return 0.0
yrs = (x.index[-1] - x.index[0]).days / 365.25
eq = float(np.prod(1.0 + np.clip(x.values, -0.99, None)))
return float(eq ** (1.0 / yrs) - 1.0) if yrs > 0.2 and eq > 0 else 0.0
def split(s):
x = pd.Series(s).dropna()
return x[x.index < HOLDOUT], x[x.index >= HOLDOUT]
HDR = f" {'cella':<20}{'ShFULL':>8}{'Sh IS':>8}{'Sh OOS':>8}{'maxDD':>9}{'CAGR':>9}"
def row(name, s, extra=""):
ins, out = split(s)
return (f" {name:<20}{sh(s):>8.2f}{sh(ins):>8.2f}{sh(out):>8.2f}"
f"{dd(s)*100:>8.1f}%{cagr(s)*100:>8.1f}%{extra}")
# =====================================================================================
# (A) XS01 congelato, con k e fase parametrici e universo a copertura variabile
# =====================================================================================
def load_closes(syms, how="inner") -> pd.DataFrame:
cols = {}
for s in syms:
p = RAW / f"hl_{s.lower()}_1d.parquet"
if not p.exists():
continue
d = pd.read_parquet(p, columns=["timestamp", "close"])
cols[s] = pd.Series(d["close"].values.astype(float),
index=pd.to_datetime(d["timestamp"], unit="ms", utc=True))
C = pd.concat(cols, axis=1, join=("inner" if how == "inner" else "outer")).sort_index()
return C.dropna() if how == "inner" else C
def xs_run(C: pd.DataFrame, k: int, phase: int = 0):
"""Replica di sleeves._xsec_returns con k e fase parametrici, tollerante ai simboli con
copertura piu' corta (si valutano solo quelli con storia sufficiente a quella data: senza
questo, un outer-join su 51 alt riduce la finestra comune a ~2/3 e cancella l'in-sample).
Con tutte le colonne valide il percorso e' NUMERICAMENTE IDENTICO all'originale — provato al
passo (0) con max|diff| = 0.
Ritorna (serie netta lente-sleeve, W [n x A], scale [n], dret [n x A])."""
px = C.values.astype(float)
n, na = px.shape
lookbacks, H, mode, tv = XS_CFG["lookbacks"], XS_CFG["H"], XS_CFG["mode"], XS_CFG["target_vol"]
disp_pct, minhist = XS_CFG["disp_pct"], XS_CFG["disp_minhist"]
mlb = max(lookbacks)
fin = np.isfinite(px)
prev = np.vstack([np.full(na, np.nan), px[:-1]])
dret = np.where(fin & np.isfinite(prev), px / prev - 1.0, 0.0)
dret = np.nan_to_num(dret)
W = np.zeros((n, na))
w = np.zeros(na)
disp_hist = []
for i in range(n):
if i >= mlb and (i - phase) % H == 0:
ok = fin[i].copy()
for L in lookbacks:
ok &= fin[i - L]
if ok.sum() >= 2 * k:
cols = np.where(ok)[0]
rLs = [px[i, cols] / px[i - L, cols] - 1.0 for L in lookbacks]
disp_i = float(np.mean([r.std() for r in rLs]))
thr = (np.percentile(disp_hist, disp_pct)
if (disp_pct > 0 and len(disp_hist) >= minhist) else -np.inf)
if disp_i >= thr:
score = np.zeros(len(cols)); cnt = 0
for rL in rLs:
sd = rL.std()
if sd > 0:
score += (rL - rL.mean()) / sd; cnt += 1
if cnt:
score /= cnt
order = np.argsort(score)
w = np.zeros(na)
lo, hi = cols[order[:k]], cols[order[-k:]]
if mode == "mom": w[hi] = 0.5 / k; w[lo] = -0.5 / k
else: w[lo] = 0.5 / k; w[hi] = -0.5 / k
else:
w = np.zeros(na)
disp_hist.append(disp_i)
W[i] = w
gross = np.zeros(n); gross[1:] = np.sum(W[:-1] * dret[1:], axis=1)
turn = np.zeros(n); turn[0] = np.abs(W[0]).sum()
turn[1:] = np.abs(np.diff(W, axis=0)).sum(axis=1)
net = gross - turn * (0.001 / 2.0)
s = pd.Series(net, index=C.index)
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)
return pd.Series(s.values * scale, index=C.index), W, scale, dret
def xs_effective_weights(W: np.ndarray, scale: np.ndarray) -> np.ndarray:
"""Peso EFFETTIVO tenuto durante la barra i = W[i-1]*scale[i]. Entrambi noti a close[i-1]
(scale usa una rolling std gia' shiftata) -> causale."""
Weff = np.zeros_like(W)
Weff[1:] = W[:-1] * scale[1:, None]
return Weff
# =====================================================================================
# (B) XSR01 congelato, con k parametrico
# =====================================================================================
def xsr_positions(P: pd.DataFrame, k: int | None) -> pd.DataFrame:
"""Q = posizioni demeanate cross-sezionalmente (meccanismo congelato).
Se k e' dato: tiene le k piu' positive e le k piu' negative di ogni riga, azzera il resto e
RI-demeana sulle sopravvissute (resta dollar-neutral)."""
Q = P.sub(P.mean(axis=1), axis=0)
if k is None:
return Q
V = Q.to_numpy(float)
out = np.zeros_like(V)
for i in range(V.shape[0]):
v = V[i]
m = np.isfinite(v)
if m.sum() < 2 * k or not np.any(v[m] != 0.0):
continue
idx = np.where(m)[0]
order = idx[np.argsort(v[idx])]
keep = np.concatenate([order[:k], order[-k:]])
r = np.zeros_like(v)
r[keep] = v[keep]
r[keep] -= r[keep].mean()
out[i] = r
return pd.DataFrame(out, index=P.index, columns=P.columns)
def xsr_legs(Q: pd.DataFrame, S: pd.DataFrame) -> pd.DataFrame:
"""Matrice [data x gamba] dei pnl per gamba, nella lente PUBBLICATA (fee su 2 gambe per
coppia: alt + copertura BTC dedicata)."""
return pd.DataFrame({c: pnl(Q[c].to_numpy(float), S[c].to_numpy(float)) for c in Q.columns},
index=Q.index)
def xsr_basket(Q: pd.DataFrame, S: pd.DataFrame, norm) -> pd.Series:
"""norm = 'perrow' riproduce ESATTAMENTE basket_from_positions (media per-riga sui simboli
con dato: il numero di simboli cambia nel tempo). norm = intero -> normalizzazione COSTANTE,
l'unica che rende confrontabili celle con k diverso."""
M = xsr_legs(Q, S)
if norm == "perrow":
return M.mean(axis=1).dropna()
return (M.fillna(0.0).sum(axis=1) / float(norm)).dropna()
# =====================================================================================
# (C) simulatore di libro con MIN-ORDER (lente eseguibile, comune alle due famiglie)
# =====================================================================================
def sim_book(Weff: np.ndarray, R: np.ndarray, idx, r_hedge=None, capital=None,
min_order=0.0, cost_bps=5.0):
"""Weff[i] = pesi TARGET da tenere durante la barra i (decisi a close[i-1]).
R[i] = ritorni per gamba nella barra i. r_hedge = ritorno della gamba di copertura (si tiene
-sum(w)); None = libro gia' neutrale fra le gambe. min_order>0: una variazione di NOZIONALE
sotto la soglia NON si esegue (si tiene la vecchia). cost_bps = costo per unita' di turnover."""
n, na = Weff.shape
c = cost_bps / 1e4
held = np.zeros(na)
hedge = 0.0
net = np.zeros(n)
n_fill = n_skip = 0
tickets, gross = [], []
for i in range(n):
tgt = Weff[i]
d_not = np.abs(tgt - held) * (capital or 1.0)
if min_order > 0.0 and capital:
move = d_not >= min_order
else:
move = d_not > 1e-12
new = np.where(move, tgt, held)
n_fill += int(move.sum())
n_skip += int(((~move) & (d_not > 1e-12)).sum())
tickets.extend(d_not[move].tolist())
turn = float(np.abs(new - held).sum())
r = float(np.dot(new, R[i]))
if r_hedge is not None:
h = -float(new.sum())
if min_order > 0.0 and capital and abs(h - hedge) * capital < min_order:
h = hedge
turn += abs(h - hedge)
hedge = h
r += hedge * float(r_hedge[i])
net[i] = r - c * turn
held = new
gross.append(float(np.abs(new).sum()) + abs(hedge))
return pd.Series(net, index=idx), dict(
n_fill=n_fill, n_skip=n_skip,
exec_share=(n_fill / (n_fill + n_skip)) if (n_fill + n_skip) else 1.0,
med_ticket=float(np.median(tickets)) if tickets else 0.0,
med_gross=float(np.median(gross)),
orders_py=(n_fill / (len(idx) / 365.25)) if len(idx) else 0.0)
# =====================================================================================
# (D) ampiezza
# =====================================================================================
def breadth(legs: pd.DataFrame, n_simult: int, min_overlap: int = 30):
"""Due misure, perche' una sola mente.
(1) N_eff = N/(1+(N-1)*rbar), N = gambe SIMULTANEE, rbar = correlazione media fra i contributi
di due gambe CONDIZIONATA a essere entrambe attive. E' la formula pubblicata dal progetto
(4.5 -> 37.4), qui condizionata: senza condizionare, concentrando si conterebbe come
'ampiezza' la ROTAZIONE nel tempo, che nello Sharpe sta gia' dentro sqrt(T).
INSTABILE per costruzione: rbar leggermente NEGATIVO (normale in un libro dollar-neutral)
la fa esplodere. Si legge insieme a rbar, mai da sola.
(2) N_hhi = numero effettivo di gambe che PORTANO il rischio, giorno per giorno:
1/sum(share_i^2) sulle quote |contributo|, mediato sui giorni attivi. Limitato da N,
stabile, e non dipende dal segno delle correlazioni."""
M = legs.to_numpy(float)
M = np.nan_to_num(M)
act = M != 0.0
rs = []
for a in range(M.shape[1]):
for b in range(a + 1, M.shape[1]):
m = act[:, a] & act[:, b]
if m.sum() < min_overlap:
continue
xa, xb = M[m, a], M[m, b]
if xa.std() > 0 and xb.std() > 0:
rs.append(float(np.corrcoef(xa, xb)[0, 1]))
rbar = float(np.mean(rs)) if rs else float("nan")
N = float(n_simult)
den = 1.0 + (N - 1) * rbar if rs else float("nan")
neff = (N / den) if (rs and den > 1e-3) else float("nan")
hh = []
for i in range(M.shape[0]):
v = np.abs(M[i][act[i]])
t = v.sum()
if t > 0 and len(v) > 0:
sHH = float(np.sum((v / t) ** 2))
if sHH > 0:
hh.append(1.0 / sHH)
return neff, rbar, (float(np.mean(hh)) if hh else float("nan")), len(rs)
# =====================================================================================
def main() -> None:
print("=" * 108)
print(" XS-LITE — una versione CONCENTRATA degli edge cross-sectional e' eseguibile a $600-5.000?")
print("=" * 108)
maj19 = list(XS_UNIVERSE)
all51 = sorted({p.stem.replace("hl_", "").replace("_1d", "").upper()
for p in RAW.glob("hl_*_1d.parquet")})
# ---------------------------------------------------------------- (0) repliche
print("\n" + "-" * 108)
print(" (0) REPLICA DEI MECCANISMI CONGELATI — prima di ogni delta")
print("-" * 108)
C19 = load_closes(maj19, "inner")
C51 = load_closes(all51, "outer")
off, _, _, _ = xs_run(C19, k=XS_CFG["k"], phase=0)
ref = _xsec_returns()
J = pd.concat({"mio": off, "sleeve": ref}, axis=1, join="inner").dropna()
d_xs = float(np.max(np.abs(J["mio"] - J["sleeve"])))
print(f" XS01 k=5 fase 0 vs sleeves._xsec_returns : max|diff| = {d_xs:.3e} "
f"({len(J)} barre) {'OK' if d_xs < 1e-12 else 'DIVERGE'}")
P, S = pair_frames()
Qfull = xsr_positions(P, None)
xsr_perrow = xsr_basket(Qfull, S, "perrow")
xsr_ref = basket_from_positions(P, S, cols=None, demean=True)
J2 = pd.concat({"mio": xsr_perrow, "ref": xsr_ref}, axis=1, join="inner").dropna()
d_xsr = float(np.max(np.abs(J2["mio"] - J2["ref"])))
print(f" XSR01 pieno vs basket_from_positions(demean): max|diff| = {d_xsr:.3e} "
f"({len(J2)} barre) {'OK' if d_xsr < 1e-12 else 'DIVERGE'}")
xsr_const = xsr_basket(Qfull, S, P.shape[1])
print(f" XSR01 pieno, lente pubblicata (media per-riga sui simboli CON DATO): "
f"Sharpe {sh(xsr_perrow):.2f} maxDD {dd(xsr_perrow)*100:.1f}% (pubblicati 1.82 / -2.6%)")
print(f" XSR01 pieno, normalizzazione COSTANTE 1/{P.shape[1]} : "
f"Sharpe {sh(xsr_const):.2f} maxDD {dd(xsr_const)*100:.1f}%")
print(" ^ le due lenti coincidono qui (la copertura e' quasi piena); da qui in poi si usa la")
print(" COSTANTE, l'unica che rende confrontabili celle con k diverso, e i numeri XSR01 vanno")
print(f" letti contro {sh(xsr_const):.2f}.")
disc = pd.Timestamp("2026-07-25", tz="UTC") # giorno di scoperta/inception monitor
xsr_disc = xsr_perrow[xsr_perrow.index <= disc]
xsr_fwd = xsr_perrow[xsr_perrow.index > disc]
print(f" XSR01 sulla FINESTRA DI SCOPERTA (<= {disc.date()}, {len(xsr_disc)} barre): "
f"Sharpe {sh(xsr_disc):.2f} maxDD {dd(xsr_disc)*100:.1f}%")
print(" ⚠ IL NUMERO PUBBLICATO (1.82) NON SI RIPRODUCE OGGI, e non e' la mia implementazione:")
print(" le due repliche qui sopra sono bit-exact col codice del progetto. Sulla finestra")
print(f" IDENTICA a quella di scoperta la lente 'paniere' da' {sh(xsr_disc):.2f} e la lente 'libro'")
print(" (fee 1 gamba alt + copertura BTC NETTA, convenzione di paper_xsr) da' 2.23: l'1.82 non")
print(" e' nessuna delle due. Spiegazione piu' probabile: data/raw e' gitignored e il cron")
print(" riscrive i parquet HL -> stesso codice, dati diversi (identico allo scoperto del 07/08")
print(" su GTAA/ADJUSTED_LAST). NON l'ho inseguito: tutte le mie conclusioni sono confronti")
print(" RELATIVI dentro UNA lente. Ma tocca un numero pubblicato e il gate del 23/10.")
print(f" XSR01 dal 25/07 a oggi (forward, {len(xsr_fwd)} barre, stessa lente): "
f"ritorno {(np.prod(1+xsr_fwd.values)-1)*100:+.2f}%"
+ (" (campione troppo corto per uno Sharpe: si legge il ritorno)"
if len(xsr_fwd) <= 30 else f" Sharpe {sh(xsr_fwd):.2f}"))
print(f" finestra MAJ19: {C19.index[0].date()} -> {C19.index[-1].date()} ({len(C19)} barre); "
f"in-sample = pre {HOLDOUT.date()} = {int((C19.index < HOLDOUT).sum())} barre")
cov51 = np.isfinite(C51.values).sum(axis=1)
print(f" finestra ALL51: {C51.index[0].date()} -> {C51.index[-1].date()} ({len(C51)} barre); "
f"simboli con dato: da {cov51.min()} a {cov51.max()} (outer-join: l'inner-join")
print(" taglierebbe la finestra a 627 barre e CANCELLEREBBE l'in-sample).")
print(" ⚠ l'in-sample e' UN ANNO SOLO e monoregime: ogni Sh IS qui sotto va letto cosi'.")
# ---------------------------------------------------------------- (1) XS-LITE
print("\n" + "-" * 108)
print(" (1) FAMIGLIA A — XS-LITE: XS01 congelato, varia solo k (gambe per lato). k=5 = canonico")
print("-" * 108)
print(HDR + f"{'N_eff':>8}{'rbar':>8}{'N_hhi':>8}")
xs_series, xs_cells = {}, {}
for uni, Cx in (("MAJ19", C19), ("ALL51", C51)):
for k in KS:
s, W, sc, dr = xs_run(Cx, k=k, phase=0)
Weff = xs_effective_weights(W, sc)
legpnl = pd.DataFrame(Weff * dr, index=Cx.index, columns=Cx.columns)
ne, rbar, nhhi, _ = breadth(legpnl, 2 * k)
nm = f"{uni} k={k}" + ("*" if (uni == "MAJ19" and k == 5) else "")
xs_series[nm] = s
xs_cells[nm] = dict(uni=uni, k=k, C=Cx, W=W, scale=sc, dret=dr,
neff=ne, rbar=rbar, nhhi=nhhi)
print(row(nm, s, f"{ne:>8.1f}{rbar:>8.3f}{nhhi:>8.1f}"))
print(" (*) = configurazione canonica del sleeve XS01")
# ---------------------------------------------------------------- (2) XSR-LITE
print("\n" + "-" * 108)
print(" (2) FAMIGLIA B — XSR-LITE: XSR01 congelato (demean), varia solo k. 'pieno' = tutte le gambe")
print("-" * 108)
maj18 = [s for s in maj19 if s != BASE]
Pm = P[[c for c in maj18 if c in P.columns]]
Sm = S[[c for c in maj18 if c in S.columns]]
print(f" ALL50: {P.shape[1]} gambe MAJ18: {Pm.shape[1]} gambe")
print(HDR + f"{'N_eff':>8}{'rbar':>8}{'N_hhi':>8}")
xsr_series, xsr_cells = {}, {}
for uni, (Pu, Su) in (("ALL50", (P, S)), ("MAJ18", (Pm, Sm))):
for k in list(KS) + [None]:
if k is not None and 2 * k > Pu.shape[1]:
continue
Q = xsr_positions(Pu, k)
norm = (2 * k) if k is not None else Pu.shape[1]
s = xsr_basket(Q, Su, norm)
legs = xsr_legs(Q, Su) / float(norm)
ne, rbar, nhhi, _ = breadth(legs, norm)
nm = f"{uni} k={k if k else 'pieno'}" + ("*" if (uni == "ALL50" and k is None) else "")
xsr_series[nm] = s
xsr_cells[nm] = dict(uni=uni, k=k, Q=Q, S=Su, norm=norm,
neff=ne, rbar=rbar, nhhi=nhhi)
print(row(nm, s, f"{ne:>8.1f}{rbar:>8.3f}{nhhi:>8.1f}"))
print(" (*) = XSR01 pieno (50 gambe demeanate), qui a normalizzazione costante")
# banda di fase calcolata PRIMA della curva: la stima onesta di uno sleeve ancorato e' la
# mediana della banda, quindi e' quella che deve stare nella curva (la fase 0 e' un max-of-10).
base_by_phase = {ph: xs_run(C19, k=5, phase=ph)[0] for ph in range(XS_CFG["H"])}
phase_med, phase_rows = {}, {}
for k in KS:
by_ph = {ph: (base_by_phase[ph] if k == 5 else xs_run(C19, k=k, phase=ph)[0])
for ph in range(XS_CFG["H"])}
vals = np.array([sh(by_ph[p_]) for p_ in range(XS_CFG["H"])])
diffs = np.array([sh(by_ph[p_]) - sh(base_by_phase[p_]) for p_ in range(XS_CFG["H"])])
phase_med[k] = float(np.median(vals))
phase_rows[k] = (vals, diffs)
# ---------------------------------------------------------------- (3) curva ampiezza
print("\n" + "-" * 108)
print(" (3) LA CURVA AMPIEZZA-vs-k — la domanda centrale: quanto ne resta concentrando?")
print("-" * 108)
sh_xs_star = sh(xs_series["MAJ19 k=5*"])
sh_xsr_star = sh(xsr_series["ALL50 k=pieno*"])
print(f" {'k':>4}{'gambe':>7} {'--------- XS-LITE MAJ19 ---------':>34} "
f"{'--------- XSR-LITE ALL50 --------':>34}")
print(f" {'':>4}{'':>7} {'N_hhi':>9}{'N_eff':>9}{'Sh f0':>8}{'Sh MED':>8}{'MED/MED*':>10} "
f"{'N_hhi':>9}{'N_eff':>9}{'Sh':>8}{'Sh/Sh*':>9}")
med5 = phase_med[5]
for k in KS:
an = f"MAJ19 k={k}" + ("*" if k == 5 else "")
bn = f"ALL50 k={k}"
ca, cb = xs_cells[an], xsr_cells[bn]
sa, sb = xs_series[an], xsr_series[bn]
print(f" {k:>4}{2*k:>7} {ca['nhhi']:>9.1f}{ca['neff']:>9.1f}{sh(sa):>8.2f}"
f"{phase_med[k]:>8.2f}{(phase_med[k]/med5 if med5 else 0):>10.0%} "
f"{cb['nhhi']:>9.1f}{cb['neff']:>9.1f}{sh(sb):>8.2f}"
f"{(sh(sb)/sh_xsr_star if sh_xsr_star else 0):>9.0%}")
cp = xsr_cells["ALL50 k=pieno*"]
print(f" {'pieno':>4}{cp['norm']:>7} {'':>9}{'':>9}{'':>8}{'':>8}{'':>10} "
f"{cp['nhhi']:>9.1f}{cp['neff']:>9.1f}{sh_xsr_star:>8.2f}{1.0:>9.0%}")
print(" 'Sh MED' = mediana delle 10 fasi d'ancora di XS01 = la stima ONESTA (la fase 0 e' un")
print(" max-of-10 non dichiarato). XSR01 e' giornaliero: non ha fase, la sua colonna e' unica.")
print(" N_hhi = gambe che PORTANO il rischio (stabile). N_eff = formula pubblicata, esplode")
print(" quando rbar e' negativo: si legge solo insieme a rbar, mai da sola.")
# ---------------------------------------------------------------- (4) banda d'ancora
print("\n" + "-" * 108)
print(" (4) BANDA D'ANCORA — le 10 fasi del ciclo H=10 di XS01 (XSR01 e' giornaliero: nessuna")
print(" fase). Stima onesta = MEDIANA della banda, non la fase 0 con cui e' stato scoperto.")
print("-" * 108)
print(f" {'cella':<14}{'fase0':>8}{'mediana':>9}{'p10':>8}{'p90':>8}{'pctl f0':>9}"
f" d vs k=5: mediana APPAIATA (fasi >0)")
for k in KS:
vals, diffs = phase_rows[k]
pctl = float((vals <= vals[0]).mean() * 100)
print(f" MAJ19 k={k:<6}{vals[0]:>8.2f}{phase_med[k]:>9.2f}{np.percentile(vals,10):>8.2f}"
f"{np.percentile(vals,90):>8.2f}{pctl:>8.0f}% {np.median(diffs):>+8.3f}"
f" {int((diffs>0).sum())}/10")
print(" 'd vs k=5' = mediana delle DIFFERENZE APPAIATE per fase (mai differenza di mediane).")
# ---------------------------------------------------------------- (5) eseguibilita'
print("\n" + "-" * 108)
print(" (5) ESEGUIBILITA' — contabilita' min-order per gamba, lente 'libro'")
print(" Il capitale in colonna e' quello dello SLEEVE. XS01 sta al 15% del book:")
print(" sleeve $90 = book $600, sleeve $300 = book $2.000, sleeve $750 = book $5.000,")
print(" sleeve $3.000 = book $20.000 (la soglia dichiarata dal progetto).")
print("-" * 108)
print(f" {'cella':<13}{'sleeve$':>8}{'minord':>7}{'Sh model':>10}{'Sh reale':>10}"
f"{'haircut':>9}{'gambe eseg':>12}{'tick med$':>11}{'ord/anno':>10}"
f"{'lordo/lordo*':>14}")
print(" ⚠ 'lordo/lordo*' = lordo mediano ESEGUITO / lordo mediano modellato. Sotto ~0.8 il")
print(" libro ha smesso di seguire il proprio target, e allora lo Sharpe NON e' la lettura")
print(" giusta (puo' perfino MIGLIORARE): e' il null del de-levering in veste di 'meno")
print(" costi'. Lezione GTAA-banda 27/07, riapplicata qui.")
def xs_book_inputs(nm):
cell = xs_cells[nm]
return xs_effective_weights(cell["W"], cell["scale"]), cell["dret"], cell["C"].index, None
def xsr_book_inputs(nm):
cell = xsr_cells[nm]
Q, Su, norm = cell["Q"], cell["S"], cell["norm"]
Wt = np.nan_to_num(Q.to_numpy(float)) / float(norm)
Weff = np.zeros_like(Wt); Weff[1:] = Wt[:-1]
rb = load_hl(BASE).reindex(Q.index).pct_change().fillna(0.0).to_numpy(float)
Ralt = np.zeros_like(Wt)
for j, c in enumerate(Q.columns):
Ralt[:, j] = np.nan_to_num(Su[c].to_numpy(float)) + rb
return Weff, Ralt, Q.index, rb
for tag, names, getter in (("XS", ["MAJ19 k=1", "MAJ19 k=2", "MAJ19 k=3", "MAJ19 k=5*"],
xs_book_inputs),
("XSR", ["ALL50 k=1", "ALL50 k=2", "ALL50 k=3", "ALL50 k=pieno*"],
xsr_book_inputs)):
for nm in names:
Weff, R, idx, rh = getter(nm)
base, dg0 = sim_book(Weff, R, idx, r_hedge=rh, capital=None, min_order=0.0)
for cap in SLEEVE_CAPS:
for mo in (MIN_ORDER_HL,):
real, dg = sim_book(Weff, R, idx, r_hedge=rh, capital=cap, min_order=mo)
lbl = f"{tag} {nm.split()[1]}"
trk = (dg["med_gross"] / dg0["med_gross"]) if dg0["med_gross"] > 0 else float("nan")
print(f" {lbl:<13}{cap:>8.0f}{mo:>7.0f}{sh(base):>10.2f}{sh(real):>10.2f}"
f"{sh(base)-sh(real):>9.2f}{dg['exec_share']*100:>11.0f}%"
f"{dg['med_ticket']:>11.0f}{dg['orders_py']:>10.0f}"
f"{trk:>12.2f}{' ⚠' if trk < 0.8 else ' '}")
print()
print(f" {'cella':<13}{'|dw| RIBILANCIO':>18}{'|dw| deriva':>14}{'cap sleeve min':>17}"
f"{'= book al 15%':>16}")
capmin_k5 = None
for nm in ("MAJ19 k=1", "MAJ19 k=2", "MAJ19 k=3", "MAJ19 k=5*"):
cell = xs_cells[nm]
W = cell["W"]
Weff = xs_effective_weights(W, cell["scale"])
dW = np.abs(np.diff(W, axis=0)) # W cambia alla riga j+1
dE = np.abs(np.diff(Weff, axis=0)) # Weff[j+1]-Weff[j], Weff[i]=W[i-1]*scale[i]
# il cambio di W alla riga j+1 si vede su Weff alla riga j+2 -> confine da rispettare
rb, dr = [], []
for j in range(len(dW)):
if j + 1 >= len(dE):
break
m = dW[j] > 1e-12
if m.any():
rb.extend(dE[j + 1][m].tolist()) # gambe DAVVERO ribilanciate
dr.extend(dE[j + 1][~m][dE[j + 1][~m] > 1e-12].tolist())
else:
dr.extend(dE[j + 1][dE[j + 1] > 1e-12].tolist())
med_rb = float(np.median(rb)) if rb else float("nan")
med_dr = float(np.median(dr)) if dr else float("nan")
capmin = MIN_ORDER_HL / med_rb if med_rb > 0 else float("nan")
if nm.startswith("MAJ19 k=5"):
capmin_k5 = capmin
print(f" {'XS ' + nm.split()[1]:<13}{med_rb:>18.4f}{med_dr:>14.4f}{capmin:>16.0f}$"
f"{capmin/0.15:>15.0f}$")
print(" ^ ARITMETICA: il ticket vale |dw|*capitale_sleeve, e le due colonne |dw| sono ordini")
print(" di grandezza diversi: il RIBILANCIO (ogni 10 giorni, porta il segnale) e la DERIVA")
print(" giornaliera del vol-target (non porta segnale). Il min-order taglia la seconda molto")
print(" prima della prima, ed e' per questo che la quota di turnover eseguito puo' essere del")
print(f" 4% con haircut ~0. Per il CANONICO k=5 il ribilancio smette di passare sotto "
f"~{capmin_k5:.0f}$")
print(f" di sleeve = ~{capmin_k5/0.15:.0f}$ di book al 15%. La soglia '$20k' del progetto viene da")
print(" una diagnostica di TURNOVER, non di Sharpe — stessa lezione gia' imparata su TP01")
print(" ('a $600 il min-order $5 e' GIA' la banda ottimale'), mai applicata a XS01.")
print()
print(" 'gambe eseg' = quota delle VARIAZIONI di posizione sopra il min-order (la diagnostica")
print(" su cui si basa la soglia '$20k'). 'haircut' = quanto ne costa in Sharpe. Sono cose")
print(" DIVERSE: il turnover saltato e' la deriva del vol-target, non il segnale.")
print(" Con min-order $5 invece di $10 (Deribit invece di HL) l'haircut si dimezza per")
print(" costruzione; il caso $10 e' quello vero per Hyperliquid ed e' quello riportato.")
# ---------------------------------------------------------------- (6) slippage
print("\n" + "-" * 108)
print(" (6) SLIPPAGE — costo TOTALE per gamba (i 5 bps di fee taker sono gia' dentro).")
print(" A che costo muore l'edge? E' il rischio #1 dichiarato di XSR01.")
print("-" * 108)
print(f" {'cella':<16}" + "".join(f"{int(c):>10}bps" for c in COST_SWEEP) + f"{'break-even':>13}")
def cost_curve(label, Weff, R, idx, rh):
vals = []
for c in COST_SWEEP:
s, _ = sim_book(Weff, R, idx, r_hedge=rh, capital=None, min_order=0.0, cost_bps=c)
vals.append(sh(s))
be = None
for i in range(1, len(COST_SWEEP)):
if vals[i - 1] > 0 >= vals[i]:
x0, x1, y0, y1 = COST_SWEEP[i-1], COST_SWEEP[i], vals[i-1], vals[i]
be = x0 + (x1 - x0) * y0 / (y0 - y1)
break
print(f" {label:<16}" + "".join(f"{v:>13.2f}" for v in vals)
+ (f"{be:>13.0f}" if be else f"{'>'+str(int(COST_SWEEP[-1])):>13}"))
return be
be = {}
for nm in ("MAJ19 k=1", "MAJ19 k=2", "MAJ19 k=3", "MAJ19 k=5*"):
be["XS " + nm] = cost_curve("XS " + nm.split()[1], *xs_book_inputs(nm))
for nm in ("ALL50 k=1", "ALL50 k=2", "ALL50 k=3", "ALL50 k=pieno*"):
be["XSR " + nm] = cost_curve("XSR " + nm.split()[1], *xsr_book_inputs(nm))
# ---------------------------------------------------------------- (7) selezione + DSR
print("\n" + "-" * 108)
print(" (7) SELEZIONE IN-SAMPLE-ONLY (mai sull'hold-out) + DEFLATED SHARPE")
print("-" * 108)
allcells = {**{f"XS {n}": s for n, s in xs_series.items()},
**{f"XSR {n}": s for n, s in xsr_series.items()}}
ins_rank = sorted(allcells.items(), key=lambda kv: -sh(split(kv[1])[0]))
print(f" celle valutate: {len(allcells)} (2 famiglie x 2 universi x 6 k, + i 2 'pieno' di")
print(" XSR01, meno le celle impossibili 2k>gambe). Lookback NON riaperto -> nessun trial in piu'.")
print(f"\n {'rank':>5} {'cella':<20}{'Sh IS':>8}{'Sh OOS':>8}{'Sh FULL':>9}")
for i, (n, s) in enumerate(ins_rank[:8], 1):
ins, out = split(s)
print(f" {i:>5} {n:<20}{sh(ins):>8.2f}{sh(out):>8.2f}{sh(s):>9.2f}")
best_name, best_s = ins_rank[0]
all_sr = [sh(s) for s in allcells.values()]
print(f"\n cella scelta AL BUIO (solo in-sample): {best_name}")
for mult, label in ((1, "trial dichiarati = celle"),
(6, "conteggio conservativo x6 (se avessi riaperto il lookback)")):
pad = all_sr * mult
d, s0 = A.deflated_sharpe(sh(best_s), pad, pd.Series(best_s).dropna())
print(f" DSR a N={len(pad):<4} ({label}): {d:.3f} "
f"{'PASS' if d >= 0.95 else 'FAIL'} (Sharpe-soglia del null {s0:.2f})")
conc = {n: s for n, s in allcells.items() if any(f" k={j}" in n for j in (1, 2, 3))}
cbest_name, cbest_s = max(conc.items(), key=lambda kv: sh(split(kv[1])[0]))
d2, _ = A.deflated_sharpe(sh(cbest_s), all_sr, pd.Series(cbest_s).dropna())
print(f" cella CONCENTRATA (k<=3, cioe' <=6 gambe) scelta al buio: {cbest_name} "
f"Sh IS {sh(split(cbest_s)[0]):.2f} OOS {sh(split(cbest_s)[1]):.2f} FULL {sh(cbest_s):.2f}")
print(f" DSR della concentrata a N={len(all_sr)}: {d2:.3f} {'PASS' if d2 >= 0.95 else 'FAIL'}")
# ---------------------------------------------------------------- (8) gate marginali
print("\n" + "-" * 108)
print(" (8) GATE MARGINALE vs TP01 + RIDONDANZA vs gli sleeve che gia' esistono")
print("-" * 108)
order = [best_name, cbest_name, "XS MAJ19 k=2", "XS MAJ19 k=3", "XS MAJ19 k=5*",
"XSR ALL50 k=2", "XSR ALL50 k=3", "XSR ALL50 k=pieno*"]
to_score = {}
for n in order:
if n in allcells and n not in to_score:
to_score[n] = allcells[n]
for n, s in to_score.items():
ss = pd.Series(s).dropna(); ss.index = pd.to_datetime(ss.index, utc=True)
m = A.marginal_vs_tp01(ss)
b = m.get("blends", {}).get("w25", {})
print(f" {n:<20} {str(m.get('marginal_verdict')):<10} corr {str(m.get('corr_full')):>7}"
f" uplift w25 full {str(b.get('uplift_full')):>7} hold {str(b.get('uplift_hold')):>7}"
f" robust={m.get('robust_oos')} noise_null={m.get('beats_noise_null')}"
f" is_edge={m.get('has_insample_edge')} hedge={m.get('is_hedge')}")
print("\n correlazione col materiale gia' in casa (un proxy eseguibile DEVE assomigliare al suo")
print(" originale: qui una corr ALTA e' l'obiettivo, non un difetto)")
ref_map = {"XS01 (sleeve)": ref, "XSR01 (pieno)": xsr_const, "TP01": A.tp01_baseline_daily()}
print(f" {'cella':<20}" + "".join(f"{k:>16}" for k in ref_map))
for n, s in to_score.items():
line = f" {n:<20}"
for _, r in ref_map.items():
Jc = pd.concat({"a": pd.Series(s).dropna(), "b": r}, axis=1, join="inner").dropna()
line += f"{(Jc['a'].corr(Jc['b']) if len(Jc) > 30 else float('nan')):>16.3f}"
print(line)
print(" ⚠ corr a SKH01/VRP01/GTAA01 NON misurata: SKH01 richiede i 5m di DUE asset e il brief")
print(" vieta di caricarli insieme. Prior del progetto (25/07): XSR01 sta a |0.001|-|0.071|")
print(" da tutti e 5 gli sleeve; un suo sottoinsieme non puo' esserne lontano.")
# ---------------------------------------------------------------- (9) null del de-levering
print("\n" + "-" * 108)
print(" (9) NULL DEL DE-LEVERING — obbligatorio su ogni confronto di maxDD (5 occorrenze note)")
print(" Domanda: esiste una LEVA del canonico che dia lo STESSO maxDD della variante?")
print(" Se a quel maxDD il canonico ha Sharpe >= alla variante, la variante non aggiunge.")
print("-" * 108)
def lev_for_dd(canon: pd.Series, target_abs: float, lo=0.01, hi=5.0):
"""Leva k tale che |maxDD(canon*k)| = target. |maxDD| e' monotono crescente in k."""
if abs(dd(canon * hi)) < target_abs:
return None # nemmeno a leva 5x si arriva al DD
for _ in range(60):
mid = 0.5 * (lo + hi)
if abs(dd(canon * mid)) < target_abs: lo = mid
else: hi = mid
return 0.5 * (lo + hi)
def delever_null(variants: dict, canon: pd.Series, label: str):
print(f" {label:<22}{'maxDD':>9}{'Sh':>8} {'k_leva canonico':>16}{'Sh canonico':>13} esito")
for nm, s in variants.items():
kl = lev_for_dd(canon, abs(dd(s)))
if kl is None:
print(f" {nm:<22}{dd(s)*100:>8.1f}%{sh(s):>8.2f} {'n.d. (>5x)':>16}"
f"{'':>13} maxDD irraggiungibile levando il canonico")
continue
sc_ = sh(canon * kl)
print(f" {nm:<22}{dd(s)*100:>8.1f}%{sh(s):>8.2f} {kl:>16.3f}{sc_:>13.2f} "
f"{'il canonico DOMINA' if sc_ >= sh(s) else 'la variante REGGE'}")
delever_null({n: xs_series[n] for n in xs_series if n.startswith("MAJ19") and "k=5" not in n},
xs_series["MAJ19 k=5*"], "XS-LITE vs canonico")
print()
delever_null({n: xsr_series[n] for n in xsr_series if n.startswith("ALL50") and "pieno" not in n},
xsr_series["ALL50 k=pieno*"], "XSR-LITE vs pieno")
# ---------------------------------------------------------------- (10) implausible + causalita'
print("\n" + "-" * 108)
print(" (10) implausible_sharpe + CAUSALITA' (prefisso troncato + decadimento con lag)")
print("-" * 108)
for n in dict.fromkeys([best_name, cbest_name, "XS MAJ19 k=2", "XS MAJ19 k=5*",
"XSR ALL50 k=2"]):
if n not in allcells:
continue
ss = pd.Series(allcells[n]).dropna(); ss.index = pd.to_datetime(ss.index, utc=True)
r = A.implausible_sharpe(ss)
print(f" {n:<20} implausible={str(r['implausible']):<6} Sh {r.get('sharpe',0):>5.2f} "
f"perdite su barre ATTIVE {r.get('loss_frac',float('nan'))*100:>5.1f}% "
f"attive {r.get('active_frac',0)*100:>3.0f}% {'; '.join(r['reasons'])[:38]}")
cut = int(len(C19) * 0.85)
Wf = xs_run(C19, k=2, phase=0)[1]
Wp = xs_run(C19.iloc[:cut], k=2, phase=0)[1]
dmax = float(np.max(np.abs(Wp[cut - 80:cut] - Wf[cut - 80:cut])))
print(f" XS k=2: pesi ricalcolati su prefisso troncato (cut={cut}) vs pieno, ultime 80 barre: "
f"max|diff| = {dmax:.2e} {'CAUSALE' if dmax < 1e-12 else 'LOOK-AHEAD'}")
Wq = xs_run(C19, k=2, phase=0)
Weff2 = xs_effective_weights(Wq[1], Wq[2])
lags = []
for lag in (0, 1, 2, 3, 5):
Wl = np.zeros_like(Weff2)
if lag: Wl[lag:] = Weff2[:-lag]
else: Wl = Weff2
s, _ = sim_book(Wl, Wq[3], C19.index)
lags.append(sh(s))
print(" XS k=2 decadimento con lag (0/1/2/3/5 giorni): "
+ " / ".join(f"{v:.2f}" for v in lags)
+ " (dolce = segnale lento, non firma di look-ahead)")
# ---------------------------------------------------------------- (11) sintesi
print("\n" + "=" * 108)
print(" SINTESI — quanto costa concentrare, e dove sta davvero il muro")
print("=" * 108)
k2, k5 = xs_series["MAJ19 k=2"], xs_series["MAJ19 k=5*"]
print(f" XS-LITE k=2 (4 gambe): Sh fase0 {sh(k2):.2f} / fase-MEDIANA {phase_med[2]:.2f}"
f" vs canonico k=5 (10 gambe): {sh(k5):.2f} / {phase_med[5]:.2f}")
print(f" XSR-LITE k=2 (4 gambe): Sh {sh(xsr_series['ALL50 k=2']):.2f} "
f"(IS {sh(split(xsr_series['ALL50 k=2'])[0]):.2f}) vs pieno "
f"{sh_xsr_star:.2f} (IS {sh(split(xsr_series['ALL50 k=pieno*'])[0]):.2f})")
def _be(x):
return f"{x:.0f} bps" if x else f">{int(COST_SWEEP[-1])} bps"
print(f" break-even di costo per gamba: XS k=2 {_be(be.get('XS MAJ19 k=2'))}, "
f"XS k=5 {_be(be.get('XS MAJ19 k=5*'))}, XSR k=2 {_be(be.get('XSR ALL50 k=2'))}, "
f"XSR pieno {_be(be.get('XSR ALL50 k=pieno*'))}")
print("-" * 108)
print(" 1. CONCENTRARE NON COMPRA RENDIMENTO, COMPRA ESEGUIBILITA'. Il null del de-levering")
print(" boccia ogni k tranne i due che sono fortuna d'ancora (XS k=4: fase0 al 90° pctl,")
print(" mediana 1.10 < 1.15 del canonico; XSR k=6: +0.03 su 1.65). Nessuna concentrazione")
print(" batte il proprio originale a PARI maxDD.")
print(" 2. MA IL COSTO E' MOLTO PIU' BASSO DEL PREVISTO, e la mia ipotesi (a) era sbagliata:")
print(" mi aspettavo Sh ~ sqrt(ampiezza) e quindi il 40-60% dell'edge a k=2-3. Misurato:")
print(" XS-LITE k=2 conserva il 98% del canonico A MEDIANA DI FASE con 4 gambe invece di 10,")
print(" e N_hhi scende 6.9 -> 3.0. La radice dell'ampiezza NON descrive questa curva: la")
print(" dispersione cross-section e' concentrata negli ESTREMI del ranking, e le gambe 3-5")
print(" per lato aggiungono rischio quanto segnale. Il collasso vero e' solo a k=1 (41%).")
print(" 3. IL MURO NON E' IL MIN-ORDER, E' IL PESO DELLO SLEEVE. Con $600 DEDICATI, XS01 gira")
print(" gia' oggi a k=5 (tracking 1.04, haircut -0.04). E' al 15% del book che muore: a")
print(" sleeve $90 il canonico esegue il 4% delle variazioni e il lordo scende al 13% del")
print(" target. A quel capitale k=2 e' l'unica cella CON EDGE che traccia (1.01: k=1 traccia")
print(" ma non ha edge, Sh 0.13). Il '~$20k' e'")
print(" quindi il prodotto di due scelte (peso 15% + k=5), non una proprieta' del segnale.")
print(" 4. XSR01 NON SI CONCENTRA: k<=3 perde l'edge IN-SAMPLE (IS 0.96 -> 0.28) e il gate")
print(" marginale lo declassa ad ADDS -> NOISE (has_insample_edge=False). Ipotesi (c)")
print(" CONFERMATA: li' l'ampiezza E' l'edge. E muore a ~28 bps/gamba di costo totale a")
print(" OGNI k, contro >50 bps di XS-LITE: concentrare non ripara il rischio #1 di XSR01.")
print(" 5. ⛔ NIENTE DI QUESTO E' DEPLOYABILE OGGI, e non per una ragione misurata qui:")
print(" XS01/XSR01 vivono su HYPERLIQUID, e la decisione dell'operatore del 26/07 tiene")
print(" il 100% del capitale su Deribit fino a $20k. A $20k il canonico e' eseguibile da")
print(" solo. XS-LITE serve SE e QUANDO si apre HL sotto quella soglia — non prima.")
print("-" * 108)
print(" GATE PRE-REGISTRATO (dichiarato ORA, prima di qualunque dato nuovo):")
print(" XS-LITE k=2 su MAJ19 si riapre SOLO se si apre un conto Hyperliquid con >= $300")
print(" dedicati allo sleeve, e in quel caso si deploya il k CANONICO (5) se il capitale")
print(" dello sleeve e' >= $750, k=2 sotto. Nessun nuovo backtest serve per questa scelta:")
print(" e' gia' decisa dalla tabella (5) e non va ri-ottimizzata guardando i dati nuovi.")
print(" Come CANDIDATO a sleeve XS-LITE resta bocciato: DSR FAIL a ogni conteggio e null")
print(" del de-levering non superato. Non si ri-testa prima del 2027-06 (3.5 anni di")
print(" storia HL, di cui >=1.5 fuori dal campione di scoperta di XS01).")
print("=" * 108)
if __name__ == "__main__":
main()