Files
PythagorasGoal/scripts/research/r0724_statarb_deploy_gate.py
T
Adriano Dal Pastro ddc980a097 research(goal50): matematica onesta del target 50eur/g + gate deploy pre-registrato statarb
- r0724_goal50_math: muro capitale (73-228k), leva=rovina, Monte Carlo prop-firm
  sui ritorni reali del book (P(pass) 56-86%, funded 100k mediana 31-42eur/g),
  vault TVL 1-2M. Unica via 'da mesi' = moltiplicare nozionale gestito.
- r0724_statarb_deploy_gate: regola di deploy PRE-REGISTRATA a fwd-day 25
  (decisione 2026-09-27, Sh>=0.5, haircut<0.5pp, 1 proroga max) — anti
  selection-on-forward.
- diario roadmap (sezioni web-research da completare).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 20:55:23 +00:00

80 lines
3.8 KiB
Python

"""r0724_statarb_deploy_gate — gate di deploy PRE-REGISTRATO per STATARB-RESID (2026-07-24).
PERCHE' PRE-REGISTRATO: la regola si fissa a forward-day 25 (oggi), PRIMA di vedere
il giorno 90. Decidere "a occhio" dopo aver visto il numero = selection-on-forward,
lo stesso bias che il progetto ha gia' pagato (gate SELECTION-ON-HOLDOUT, 2026-06-29).
REGOLA (immutabile — ogni modifica va motivata nel diario come violazione):
- Data decisione: 2026-09-27 (90 giorni forward dal 2026-06-29). Non prima.
- Metrica: Sharpe annualizzato di net_modeled su TUTTA la finestra forward
(nessuna sottofinestra), da data/paper_statarb/returns.jsonl.
- Esiti:
Sharpe >= 0.5 -> CANDIDATO AL DEPLOY: proporre peso {10,15,20}% del book
Deribit, giudicato con weights_tilt_null + stima maxDD
combinata < 15%. Deploy solo se il tilt-null passa.
0 <= Sh < 0.5 -> ESTENDI una sola volta di altri 90g (decisione 2026-12-26).
Alla seconda scadenza: o >=0.5 o RITIRO. Niente terza proroga.
Sharpe < 0 -> RITIRO dal forward-monitor (l'edge DSR 0.929 non ha confermato).
- Guardie accessorie (tutte richieste per il deploy):
* fill-haircut cumulato |MODELED - REAL| < 0.5 pp (eseguibilita' reale a $600);
* config invariata (W=45, sgn=+1) — ogni ritocco azzera la finestra;
* maxDD forward < 10% (coerenza col profilo di ricerca, DD backtest ~11%).
Uso: `uv run python scripts/research/r0724_statarb_deploy_gate.py`
(si puo' lanciare in qualsiasi momento: ricorda la data-decisione e valuta lo stato).
"""
from __future__ import annotations
import json
from datetime import date
from pathlib import Path
import numpy as np
ROOT = Path(__file__).resolve().parents[2]
RETURNS = ROOT / "data" / "paper_statarb" / "returns.jsonl"
START = date(2026, 6, 29) # inizio forward (config congelata)
DECISION = date(2026, 9, 27) # 90g forward — PRIMA data utile di decisione
DECISION_EXT = date(2026, 12, 26) # unica proroga ammessa
SH_DEPLOY = 0.5
HAIRCUT_MAX_PP = 0.5
DD_MAX = 0.10
def main() -> None:
rows = [json.loads(x) for x in RETURNS.read_text().splitlines() if x.strip()]
rm = np.array([r["net_modeled"] for r in rows])
rr = np.array([r["net_real"] for r in rows])
n = len(rm)
sh = float(rm.mean() / rm.std() * np.sqrt(365)) if rm.std() > 0 else 0.0
eq = np.cumprod(1 + rm)
dd = float(np.max((np.maximum.accumulate(eq) - eq) / np.maximum.accumulate(eq)))
haircut_pp = abs(float((np.prod(1 + rm) - np.prod(1 + rr)) * 100))
today = date.today()
print("=" * 88)
print(" STATARB-RESID — gate di deploy PRE-REGISTRATO (fissato 2026-07-24, forward-day 25)")
print("=" * 88)
print(f" finestra forward : {rows[0]['dt'][:10]} -> {rows[-1]['dt'][:10]} ({n} barre)")
print(f" Sharpe fwd (mod) : {sh:+.2f} (soglia deploy >= {SH_DEPLOY})")
print(f" maxDD fwd : {dd:.1%} (guardia < {DD_MAX:.0%})")
print(f" fill-haircut cum : {haircut_pp:.2f} pp (guardia < {HAIRCUT_MAX_PP} pp)")
print(f" data decisione : {DECISION} (proroga unica: {DECISION_EXT})")
if today < DECISION:
print(f"\n -> NESSUNA DECISIONE OGGI ({today}): mancano {(DECISION - today).days} giorni.")
print(" Il numero corrente NON autorizza deploy anticipato (regola pre-registrata).")
else:
if sh >= SH_DEPLOY and dd < DD_MAX and haircut_pp < HAIRCUT_MAX_PP:
print("\n -> GATE SUPERATO: procedere con weights_tilt_null sui pesi candidati "
"{10,15,20}% e stima maxDD combinata (<15%) prima del deploy.")
elif sh >= 0:
print("\n -> SOTTO SOGLIA ma >=0: estensione unica fino al "
f"{DECISION_EXT} (se gia' estesa: RITIRO).")
else:
print("\n -> Sharpe forward NEGATIVO: RITIRO dal forward-monitor.")
if __name__ == "__main__":
main()