gate XSR01: riscrittura DICHIARATA (opzione A dell'operatore) + haircut con script

Decisione operatore 26/08, a 58 giorni dall'esito, in direzione che stringe:
(1) capitale deploy $5k -> $20k — riconcilia il gate (25/07) con la decisione
vincolante "100% Deribit fino a $20k" (26/07), posteriore, che governa (M28);
deploy XSR01 e scelta del venue ora coincidono in un punto solo.
(2) gamba haircut: numero decisivo da r0826_xsr_haircut.py (N11) a pavimento
$10 (il vero, HL-EXEC), citato con la frazione di ordini eseguiti (P7).
Misurato: FULL 968 barre floor $10 -> haircut -1,1% con 22% di eseguiti (la
guardia da sola era vacua: un libro fermo ha haircut piccolo); ticket mediano
$3,34/gamba, 84% sotto $10 — sostituisce il "$14,41" senza script.
(3) contesto 1.82 -> 1.79 (lente dei gate). Soglie numeriche INVARIATE.

Chiude il debito S5.3. Diario 2026-08-26-xsr01-gate-riscritto.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B9UyJLHzR7EJzxR3iQ3RN1
This commit is contained in:
Adriano Dal Pastro
2026-08-26 11:04:57 +00:00
parent d597fc64e8
commit 3034bfdc58
5 changed files with 230 additions and 18 deletions
+26 -4
View File
@@ -11,6 +11,23 @@ deflated-Sharpe 0.985, corr ~0 a tutti e 5 gli sleeve. Sopravvive a tre null fee
test di lag. NON e' nel book per tre motivi dichiarati: storia corta e monotona crescente,
`weights_tilt_null` fallito, e margine di costo sottile con slippage NON modellato.
⚠️ MODIFICA DICHIARATA 2026-08-26 (diario `2026-08-26-xsr01-gate-riscritto.md`) — decisa
dall'operatore PRIMA di vedere l'esito, a 58 giorni dalla data, e in direzione che STRINGE:
1. CAPITALE per il deploy: $5.000 -> $20.000. Non e' tuning sull'esito: riconcilia il gate
(scritto il 25/07) con la decisione vincolante "100% Deribit fino a $20k" (26/07), che e'
POSTERIORE e lo governa — sotto $20k nessun capitale esce da Deribit, quindi il criterio
a $5k autorizzava una cosa che un'altra decisione gia' vietava (M28).
2. GAMBA HAIRCUT: il numero decisivo alla decisione e' quello dello script committato
`r0826_xsr_haircut.py` a pavimento $10 (il pavimento VERO misurato, HL-EXEC 22/08 — il
libro REAL-$5000 del monitor gira a $5 ed e' ottimista per costruzione), CITATO ACCANTO
alla frazione di ordini eseguiti (P7): a $10 si esegue ~1 ordine su 5, e un haircut
piccolo con pochi ordini eseguiti non e' eseguibilita', e' un libro fermo. La SOGLIA
resta il 40% pre-registrato: nessuna soglia nuova viene scritta oggi coi dati in mano.
3. Il riferimento "in-sample 1.82" era una TERZA lente (XSR-REPRO 22/08): la lente dei gate
da' 1.79 alla scoperta. Corretto il contesto, non il criterio.
La serie forward e' quella RIGENERATA il 26/08 (advance() riparato, §5.1): stessa finestra,
stesso forward-day 0, barre finalmente VERE.
REGOLA (immutabile — ogni modifica va motivata nel diario come violazione):
- Data decisione: 2026-10-23 (90 giorni forward dal 2026-07-25). Non prima.
- Metrica primaria: Sharpe annualizzato di `net_modeled` su TUTTA la finestra forward.
@@ -22,7 +39,7 @@ REGOLA (immutabile — ogni modifica va motivata nel diario come violazione):
- Esiti:
Sharpe >= 1.0 AND haircut$5000 <= 40% -> CANDIDATO SLEEVE: proporre peso {5,10}% e
giudicarlo con `weights_tilt_null` (che oggi NON passa) + maxDD combinato.
Deploy solo se il tilt-null passa E il capitale e' >= $5000.
Deploy solo se il tilt-null passa E il capitale e' >= $20.000 (mod. 26/08).
0.3 <= Sh < 1.0 -> ESTENDI una sola volta di 90g (2027-01-21).
Sharpe < 0.3 OR haircut > 40% -> RITIRO dal forward-monitor.
- Guardie accessorie: config invariata (il test `tests/test_paper_xsr.py` la blocca);
@@ -47,7 +64,8 @@ DECISION_EXT = date(2027, 1, 21)
SH_DEPLOY = 1.0
SH_RETIRE = 0.3
HAIRCUT_MAX = 0.40
IS_SHARPE_NET = 1.82 # riferimento in-sample, per contesto
CAPITALE_DEPLOY = 20_000.0 # mod. dichiarata 26/08: riconcilia col muro "100% Deribit" (26/07)
IS_SHARPE_NET = 1.79 # lente dei gate alla scoperta (il "1.82" era una terza lente)
def main() -> None:
@@ -78,7 +96,10 @@ def main() -> None:
print(f" Sharpe fwd (mod) : {sh:+.2f} (in-sample netta era {IS_SHARPE_NET:.2f})")
print(f" maxDD fwd : {dd:.1%}")
print(f" ritorno MODELED : {tot_m*100:+.2f}% REAL-$5000: {tot_5*100:+.2f}%")
print(f" haircut eseguib. : {haircut*100:.1f}% (guardia <= {HAIRCUT_MAX*100:.0f}%)")
print(f" haircut monitor : {haircut*100:.1f}% (pavimento $5 — ottimista per costruzione)")
print(f" guardia <= {HAIRCUT_MAX*100:.0f}%: il numero DECISIVO e' quello di "
f"`r0826_xsr_haircut.py` a pavimento $10,")
print( " citato accanto alla frazione di ordini eseguiti (mod. 26/08)")
print(f" data decisione : {DECISION} (proroga unica: {DECISION_EXT})")
if today < DECISION:
@@ -89,7 +110,8 @@ def main() -> None:
print("\n -> RITIRO: l'haircut di eseguibilita' supera la guardia. E' costo, non edge.")
elif sh >= SH_DEPLOY:
print("\n -> CANDIDATO SLEEVE: proporre peso {5,10}% e passarlo a weights_tilt_null "
"(oggi NON passa) + maxDD combinato. Deploy solo con capitale >= $5000.")
f"(oggi NON passa) + maxDD combinato. Deploy solo con capitale >= "
f"${CAPITALE_DEPLOY:,.0f} (mod. 26/08, allineato a '100% Deribit fino a $20k').")
elif sh >= SH_RETIRE:
print(f"\n -> SOTTO SOGLIA ma >= {SH_RETIRE}: estensione unica fino al {DECISION_EXT}.")
else:
+139
View File
@@ -0,0 +1,139 @@
"""r0826_xsr_haircut.py — l'haircut di eseguibilita' di XSR01 a $5.000, MISURATO con uno script.
PERCHE' ESISTE. La seconda gamba del gate XSR01 (23/10) e' "haircut a $5.000 <= 40%", ma:
(a) il numero pubblicato all'ammissione ($14,41 di ticket/gamba) NON ha uno script committato
che lo riproduca ed e' ~2,4x ottimista (XSR-REPRO 22/08: mediano vero $3,33/gamba);
(b) il libro REAL-$5000 del monitor gira con pavimento $5, ma il pavimento VERO misurato del
venue e' $10 (HL-EXEC 22/08) — e a $10 si esegue ~1 ordine su 5;
(c) il paradosso dello strumento: con POCHI ordini eseguiti il libro reale resta vicino al
modellato nei periodi calmi -> l'haircut misurato dal monitor puo' sembrare piccolo
proprio quando l'eseguibilita' e' pessima. La frazione di ordini eseguiti va letta
ACCANTO all'haircut, mai al suo posto (P7: uno "zero" si legge accanto alla quota di
campione utilizzabile).
COSA FA. Replay dei libri XSR01 col codice di PRODUZIONE (`paper_xsr._step`, nessuna
reimplementazione — il metodo dell'audit 22/08), capitale $5.000, pavimenti $5 e $10, su due
finestre: FULL (tutte le barre chiuse, ~2,6 anni: la risoluzione) e FORWARD (dal forward-day 0
del gate, 2026-07-25: cio' che il gate legge). Sole barre CHIUSE (paper_guard).
E' lo script che il gate del 23/10 cita come strumento DECISIVO per la gamba haircut
(modifica dichiarata del 2026-08-26, diario `2026-08-26-xsr01-gate-riscritto.md`).
uv run python scripts/research/r0826_xsr_haircut.py
"""
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
import numpy as np
import pandas as pd
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from src.live.paper_guard import MS_1D, nuove_chiuse # noqa: E402
CAP = 5_000.0
PAVIMENTI = (5.0, 10.0) # $5 = il pavimento del monitor · $10 = il pavimento VERO (HL-EXEC)
ANN = float(np.sqrt(365.0))
def _px():
spec = importlib.util.spec_from_file_location("_hx_paper_xsr",
ROOT / "scripts" / "live" / "paper_xsr.py")
m = importlib.util.module_from_spec(spec)
spec.loader.exec_module(m)
return m
def _sh(r: np.ndarray) -> float:
return float(r.mean() / r.std() * ANN) if len(r) > 1 and r.std() > 0 else float("nan")
def replay(px, idx: list[int], W, R, rb, n_gambe: int, min_order: float | None) -> dict:
bk = px._book(CAP, n_gambe)
net = []
for i in idx:
net.append(px._step(bk, W[i], R[i], float(rb[i]), min_order))
net = np.asarray(net)
tot = float(np.prod(1 + net) - 1)
n_ordini = bk["n_fill"] + bk["n_skip"]
return dict(net=net, tot=tot, sh=_sh(net),
frazione_eseguita=(bk["n_fill"] / n_ordini if n_ordini else float("nan")))
def misura(px, idx: list[int], W, R, rb, n_gambe: int) -> dict:
"""Per una finestra: MODELED + un libro reale per pavimento, con l'haircut del gate."""
out = dict(modeled=replay(px, idx, W, R, rb, n_gambe, None))
tot_m = out["modeled"]["tot"]
for f in PAVIMENTI:
r = replay(px, idx, W, R, rb, n_gambe, f)
r["haircut"] = (tot_m - r["tot"]) / abs(tot_m) if tot_m != 0 else float("nan")
out[f] = r
return out
def ticket_stats(W, idx: list[int]) -> dict:
"""Taglia degli ordini per gamba a $5.000: |Δw| x capitale a ogni ribilancio."""
t = []
prev = np.zeros(W.shape[1])
for i in idx:
w = np.nan_to_num(W[i])
d = np.abs(w - prev) * CAP
t.extend(d[d > 0].tolist())
prev = w
t = np.asarray(t)
return dict(mediano=float(np.median(t)), medio=float(np.mean(t)),
sotto5=float((t < 5.0).mean()), sotto10=float((t < 10.0).mean()), n=len(t))
def main() -> None:
print("=" * 96)
print(f" XSR01 — haircut di eseguibilita' a ${CAP:,.0f}, replay col codice di produzione")
print("=" * 96)
px = _px()
ts, dt, W, R, rb, syms = px.build_panel()
st = json.loads((ROOT / "data" / "paper_xsr" / "state.json").read_text())
chiuse = nuove_chiuse(ts, 0, MS_1D)
fwd = [i for i in chiuse if ts[i] > st["start_ts"]]
Wv = np.nan_to_num(np.asarray(W, float))
Rv = np.nan_to_num(np.asarray(R, float))
tk = ticket_stats(Wv, chiuse)
print(f"\n TICKET PER GAMBA a ${CAP:,.0f} (riproduce/sostituisce il '$14,41' senza script):")
print(f" mediano ${tk['mediano']:.2f} · medio ${tk['medio']:.2f} · "
f"sotto $5: {tk['sotto5']:.0%} · sotto $10: {tk['sotto10']:.0%} "
f"({tk['n']:,} ordini su {len(chiuse)} barre)")
for nome, idx in (("FULL (tutte le barre chiuse)", chiuse), ("FORWARD (dal 2026-07-25)", fwd)):
if len(idx) < 5:
print(f"\n {nome}: {len(idx)} barre — troppo corta, nessun numero")
continue
m = misura(px, idx, Wv, Rv, rb, len(syms))
print(f"\n {nome}{len(idx)} barre "
f"({pd.Timestamp(int(ts[idx[0]]), unit='ms', tz='UTC').date()} -> "
f"{pd.Timestamp(int(ts[idx[-1]]), unit='ms', tz='UTC').date()})")
print(f" {'libro':<18} {'tot':>9} {'Sharpe':>8} {'haircut':>9} {'ordini eseguiti':>17}")
print(" " + "-" * 66)
print(f" {'MODELED':<18} {m['modeled']['tot']:>8.2%} {m['modeled']['sh']:>8.2f} "
f"{'':>9} {'':>17}")
for f in PAVIMENTI:
r = m[f]
print(f" {'REAL floor $%.0f' % f:<18} {r['tot']:>8.2%} {r['sh']:>8.2f} "
f"{r['haircut']:>8.1%} {r['frazione_eseguita']:>16.0%}")
if nome.startswith("FORWARD"):
h10 = m[10.0]["haircut"]
fe10 = m[10.0]["frazione_eseguita"]
print(f"\n VERDETTO gate (gamba haircut, pavimento VERO $10): "
f"{h10:+.1%} contro guardia 40%"
f" -> {'SFONDA (RITIRO a prescindere)' if abs(h10) > 0.40 else 'dentro la guardia'}")
print(f" ⚠️ da leggere ACCANTO: ordini eseguiti {fe10:.0%} — un haircut piccolo "
f"con pochi ordini\n eseguiti non e' eseguibilita', e' un libro che non "
f"si muove (P7).")
if __name__ == "__main__":
main()