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:
@@ -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())
|
||||
Reference in New Issue
Block a user