"""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()