research(capitale): il lump-sum vale 2.45x, e la protezione dalla rovina non passa da GTAA01

Quattro filoni chiesti dall'operatore ("proposte"). Book, pesi, config: INVARIATI.

1. LUMP-SUM + VENUE (r0727_lumpsum_split.py). Tutte le traiettorie del 25-26/07 avevano
   START=600 cablato: mai misurato un versamento iniziale, mentre ~10k EUR stanno fermi
   altrove. Macchineria validata: con lump 0 riproduce IDENTICI i numeri del 26/07.
   - 10k EUR oggi e mai piu' nulla -> traguardo 17.2a, P 62%, rendita 61.58 EUR/g
   - equivalenza onesta: +154 EUR/mese per 13 anni = 24.523 EUR, cioe' 2.45x
     (la prima stesura misurava i versamenti risparmiati: numero giusto, domanda sbagliata)
   - col rischio venue: a 11.500$ lo split e' possibile (quota IB 26%, non 25%) e taglia
     P(perso tutto) da 18.4% a 3.5% a p=1%, costando 1.9-2.6pp di P(arrivare)
   - SPLIT-CASSA: seconda gamba ferma costa altri 0.6-0.8pp e protegge IDENTICO
     -> la protezione non e' bloccata dal PRIIPs: serve un CONTO, non uno sleeve

2. FEE WATCH (scripts/live/fee_watch.py). Nuovo schema Deribit dal 1 agosto senza numeri
   pubblicati -> sorvegliante invece di promemoria. Legge il tier base dall'endpoint
   pubblico (oggi taker 5.00 bps), applica la regola congelata e allerta sui cambiamenti.

3. MONITOR HEALTH (src/live/monitor_health.py). Tre gate pre-registrati si decidono su
   serie forward di cui una sola era sorvegliata. Misura coda E buchi interni: una serie
   bucata ma fresca passa qualunque guardia di freschezza.

4. BANDA GTAA01 25% VALIDATA (r0727_gtaa_band_gate.py). 30 celle, 29.9 anni, dpy=252.
   Non e' selection-on-holdout (4/30 IS, 5/30 OOS), DSR 0.999, tracking OK ma AL BORDO.
   Il modo di fallire non e' il de-levering (la vol non scende) ma la perdita di tracking.
   Impatto sul book: zero -> REBAL_BAND_USD non toccato, si applica al deploy.

Aggiunto anche il bullet edge_watch, cablato il 26/07 e mai finito in CLAUDE.md.

Test: 56 nuovi, 504/504 verdi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-07-27 14:14:39 +00:00
parent 3f0812c7fc
commit fd05307c96
13 changed files with 1963 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python
"""monitor_health.py — i forward-monitor stanno registrando? Riporta e allerta, non tocca nulla.
Tre gate pre-registrati (STATARB 27/09, XSR01 23/10, DVOLSPREAD 24/10) si decideranno leggendo
serie forward che, tranne una, **nessuno sorvegliava**. Un monitor fermo produce silenzio, e il
silenzio in una serie di ritorni si legge come "zero", cioe' come una misura. Non lo e'.
Vedi `src/live/monitor_health.py` per le due misure (coda + buchi interni), le cadenze per
monitor e la soglia di copertura 0.80 (la stessa del veto d'integrita' di DVOLSPREAD).
uv run python scripts/live/monitor_health.py # report
uv run python scripts/live/monitor_health.py --quiet # stampa/allerta solo se scatta
"""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from src.live.monitor_health import MIN_COVERAGE, alerts_from, check_all # noqa: E402
from src.live.notifier import notify # noqa: E402
def main() -> int:
rows = check_all(ROOT)
alerts = alerts_from(rows)
if "--quiet" not in sys.argv or alerts:
print("=" * 92)
print(" MONITOR HEALTH — i forward-monitor stanno ancora registrando?")
print("=" * 92)
print(f"\n {'monitor':<20}{'stato':>10}{'barre':>8}{'attese':>8}"
f"{'copert.':>10}{'eta ultima':>13} gate che ne dipende")
for r in rows:
cov = f"{r['coverage']:.0%}" if r["coverage"] is not None else "-"
exp = f"{r['expected']}" if r["expected"] is not None else "-"
age = f"{r['age_h']:.0f}h" if r["age_h"] is not None else "-"
gate = (r["gate"] or "").split("")[0]
print(f" {r['name']:<20}{r['status']:>10}{r['n_bars']:>8}{exp:>8}"
f"{cov:>10}{age:>13} {gate}")
print(f"\n soglia di copertura {MIN_COVERAGE:.0%} (= veto d'integrita' di DVOLSPREAD) · "
f"'NUOVO' = troppo giovane per un giudizio, non 'OK'")
for r in rows:
if r["why"] and r["status"] != "OK":
print(f" {r['name']}: {r['why']}")
if alerts:
notify("🩺 MONITOR HEALTH — un forward-monitor non sta registrando",
{f"alert {i+1}": a for i, a in enumerate(alerts)})
for a in alerts:
print(f" ALERT: {a}")
return 2
return 0
if __name__ == "__main__":
raise SystemExit(main())