Commit Graph

102 Commits

Author SHA1 Message Date
Adriano Dal Pastro 12dc04c969 analista: modello di default a opus-5
Sonnet-5 ha prodotto due errori di ragionamento in due giri: una frase su un
merge di cui nessuno gli aveva parlato, e un round-trip corretto sulla pagina
dichiarato inesistente, con una spiegazione inventata per il proprio dubbio.
Nessuno dei due contiene una cifra nuova, quindi numeri_non_supportati() non
li vede: e' il buco dichiarato quando la guardia e' stata scritta.

Primo giro con opus-5 sulla stessa giornata: nessuna affermazione inventata,
e le affermazioni numeriche verificate a mano contro il DB tornano tutte
(fill 1 contro 2/5/4/3 dei giorni precedenti, equity ferma a $597.12 dal 13
al 18/08, target BTC 189 -> 115). Resta un'imprecisione di nome: chiama
"target" un valore che nella fonte era la POSIZIONE. Il numero e' della
fonte, la classe di errore e' cambiata.

E ha prodotto una riformulazione che le regole non possono dare: la
concentrazione del P&L in 7 giorni ha una lettura alternativa altrettanto
compatibile — quei sette giorni sono anche gli UNICI in cui il libro e'
stato a mercato, quindi la finestra non separa l'edge dal beta a un rialzo
del 22-29%.

⚠️ Il campione e' di due osservazioni contro una: e' un tentativo di
abbassare un tasso, non una garanzia, ed e' scritto cosi' nel sorgente.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 19:47:11 +00:00
Adriano Dal Pastro 782c0ce4bc analista: manda l'analisi giornaliera su Telegram, con l'esito registrato
La notifica porta una testata coi numeri che si leggono senza aprire nulla
(equity, delta del giorno, cumulato, posizioni, leva, fill e round-trip) e
sotto l'analisi del modello.

Il trasporto Telegram e' pero' il punto singolo di guasto gia' misurato in
questo progetto: un tentativo, nessun retry, esito mai registrato, 6,9% di
invii persi (2/29). Su un messaggio al giorno sono ~25 messaggi persi
all'anno, quindi qui sono state fatte due delle tre riparazioni dichiarate
il 2026-08-23 e mai eseguite:

(a) `send(text, tentativi=1)` — retry OPZIONALE con backoff. Il default resta
    1, cosi' il comportamento e' invariato per tutti i chiamanti esistenti:
    alzarlo per tutti cambierebbe la latenza degli allarmi di venue_watch e
    book_execute su un percorso con soldi veri, e non e' una modifica da fare
    di straforo dentro un'altra funzionalita'. L'analista chiede 3.
(b) `ultimo_errore()` — il motivo si registra nel punto in cui l'eccezione
    veniva ingoiata, e NON sopravvive a un invio riuscito. Regola gia'
    codificata il 29/07 su un altro percorso e mai applicata al notifier.

La terza (marcare `alerted=True` solo a invio riuscito in venue_watch) cambia
il comportamento degli allarmi e resta una decisione dell'operatore.

L'esito finisce nel DB in tre stati: inviata / non configurato / FALLITA col
motivo. Un invio perso che non lascia traccia, il giorno dopo, non si
distingue da "non e' successo niente".

E se l'analisi manca, il messaggio parte lo stesso dicendo PERCHE': senza
quel ramo un guasto del modello si leggerebbe come una giornata senza nulla
da dire. Taglio a 4096 caratteri dichiarato, mai silenzioso; HTML del modello
neutralizzato.

708 test passano. Strategia, pesi, config INVARIATI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 19:40:56 +00:00
Adriano Dal Pastro f5d9409213 analista di bordo: un modello scrive la prosa del giorno, in un campo suo
Aggiunto il quarto livello della pagina, tenuto separato dagli altri tre:
  numeri   -> misurati dal feed e dal DB
  Lettura  -> regole deterministiche, ognuna col suo id
  Analisi  -> questo: prosa di un modello, che puo' sbagliare
  Nota     -> l'operatore

NON scrive dentro `nota`, che era la richiesta letterale: quel campo e'
dell'operatore, ed e' cio' che a rileggere il giornale fra sei mesi permette
di sapere chi ha scritto cosa. L'agente ha `analisi`, marcato col modello,
con l'ora e con l'esito del controllo sui numeri.

Gira via `claude -p` (verificato con env -i che risponda nell'ambiente nudo
di cron), una chiamata al giorno sul giorno CHIUSO, tolte le tool.

Tre guardie, una per ogni modo in cui una prosa generata rovina un registro:
- NUMERO INVENTATO: numeri_non_supportati() estrae ogni cifra dall'analisi e
  verifica che compaia in cio' che il modello ha ricevuto. Oltre tre numeri
  liberi l'analisi e' RIFIUTATA e la pagina resta senza. E' un controllo
  debole per costruzione, e lo dichiara: prende l'invenzione, non il
  ragionamento sbagliato.
- COMMENTO DI SE': senza_analisi() toglie dalla pagina la sezione dell'agente
  prima di dargliela. Al primo giro reale il modello aveva letto la propria
  uscita precedente e prodotto un paragrafo sull'avviso che si era preso il
  giorno prima — un ciclo di retroazione che in poche settimane avrebbe
  riempito il giornale di meta-commento, e che nessun controllo automatico
  puo' distinguere da prosa valida.
- ANALISI DI IERI SPACCIATA PER OGGI: se il modello non risponde, la pagina
  resta VUOTA e il perche' viene registrato (stato + motivo). Il silenzio non
  diventa continuita'.

Corretto anche un falso positivo mio: il tripwire validava sulla sola pagina
mentre il prompt include anche il blocco storico, quindi bocciava un'equity
vera. Una guardia piu' stretta del contratto produce allarmi che si impara a
ignorare.

Ogni guardia ha un test in entrambe le direzioni. 695 test passano.
Strategia, pesi, config INVARIATI. Nessun ordine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 17:46:29 +00:00
Adriano Dal Pastro 1803e0ac9f giornale: lettura ragionata a regole dichiarate e tracciabili
Non prosa libera: dodici regole, ognuna con un id stampato accanto alla riga
che ha prodotto. Combinano solo numeri gia' presenti nella pagina, tacciono
sul non misurato e non prevedono niente. Il campo `nota` resta l'unico posto
dove puo' finire un giudizio umano.

Le regole: stato del libro e PERCHE' e' flat (componente per componente),
disaccordo fra orizzonti del trend contro esposizione TP01, incoerenza
(trend su ma libro fuori), leva contro il tetto, P&L del giorno, costo che
supera il movimento, concentrazione del cumulato, drawdown dal picco,
implicita contro realizzata col gate IV-rank di VRP01, giornata oltre 2
deviazioni, giri mancanti e feed vecchio, e la taglia del campione.

Ogni regola ha DUE test: uno che la accende e uno che la tiene spenta. Una
regola che si accende sempre non sta leggendo niente, una che non si accende
mai e' indistinguibile da una rotta.

Tre difetti corretti prima di pubblicare, tutti trovati scrivendo i test:
- il tetto di leva era RIDICHIARATO (0.5 cablato) invece che letto da
  config/live.json — quinta occorrenza dello schema che il progetto paga da
  luglio: un sorvegliante che ridichiara il proprio bersaglio continua a
  passare il giorno che il bersaglio cambia. Ora deriva, e se il config non
  si legge lo dice invece di inventare un tetto.
- l'IV-rank era il percentile a UN ANNO etichettato col nome del gate di
  VRP01, che usa un percentile ESPANDENTE. Due statistiche diverse, e oggi
  danno il verdetto OPPOSTO: 0.52 (sopra la soglia, "il sleeve venderebbe")
  contro 0.18 (sotto, sleeve fermo). Il valore giusto combacia con quanto
  gia' misurato il 30/07: 0/8 settimane passano il gate.
- la concentrazione si accendeva su $2,08 di cumulato: vera e inutile. Ora
  ha una soglia di rilevanza, o e' una riga che insegna a saltare la sezione.

62 voci rigenerate. Strategia, pesi, config INVARIATI. 675 test passano.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 13:36:05 +00:00
Adriano Dal Pastro 10c373075c libro di bordo: DB dei trade allineato col tempo + giornale giornaliero
I trade erano salvati, ma non allineati col tempo: book_execute.py scriveva
ts_utc = pd.Timestamp(r['last_data']), cioe' la data della BARRA DI SEGNALE.
19 righe su 19 a 00:00:00, e un trade (ETH 0.04 @ 1869.74) registrato SEI
GIORNI prima di essere eseguito — fill vero 2026-07-14T14:00, scritto 08/07.
L'ora vera esisteva solo in logs/cron_book.log, che e' gitignored, fuori dal
backup e ruotabile: la cronologia reale del libro live viveva in un file che
una rotazione avrebbe cancellato senza che nessuno se ne accorgesse.

- src/live/tradesdb.py: parser del cron log (ora vera + contesto del segnale),
  FIFO con fee pro-quota, riconciliazione a tre fonti, sqlite in data/live/
  (dentro il perimetro del backup). Le tre fonti si INCROCIANO e non si
  sovrascrivono: reconcile() riporta le divergenze e non ripara niente da solo.
  Il venue e' autorevole ma TRONCA (1 trade su BTC, 0 su ETH): dichiarato.
- scripts/live/trades_db.py: --sync (idempotente, in cron_book ogni ora),
  --report, --reconcile.
- src/live/journal.py + scripts/live/journal.py: una voce al giorno in
  docs/journal/YYYY-MM-DD.md — mercato (ritorni, RV30, TSMOM sugli orizzonti
  di produzione, DVOL con eta'), libro (TP01/SKH01, target, posizione, leva),
  P&L (equity del venue come autorita', scomposizione locale), salute.
  NIENTE narrativa automatica: il campo `nota` e' l'unico posto per il testo
  libero ed e' dell'operatore, mai riscritto da un ricalcolo.
- book_execute.py: ts_utc = ora vera del fill, bar_ts = barra. Test di
  regressione sulla sorgente: se qualcuno rimette last_data, il test lo dice.
- 62 voci di giornale ricostruite dall'arming a oggi.

Tre difetti trovati dai test mentre scrivevo, non a occhio: il renderer cadeva
in KeyError se mancava il blocco mercato (un giornale che non si scrive non e'
un giornale); "24 giri attesi" su un giorno IN CORSO produceva un allarme a
ogni esecuzione; e libro e P&L leggevano due istanti diversi, quindi la stessa
pagina mostrava due equity.

Strategia, pesi, config INVARIATI. Nessun ordine. 659 test passano.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 13:13:02 +00:00
Adriano Dal Pastro c932fab304 venue_watch: disciplina degli allarmi, specifiche contratto controllate, terza referenza
Il 18/08 sono usciti quattro 🚨 identici con 'PRIMO PASSO: prelievo di prova'
per una manutenzione Deribit annunciata, e tutti e quattro DOPO che il book
aveva gia' ripreso a eseguire. Il book si era comportato bene (due giri di
astensione, 'non eseguo a cieco'); il difetto era negli allarmi.

1. Il blocco piattaforma era un if secco senza memoria, accanto a un rilevatore
   tarato con cura che allerta una volta per streak. Ora passa da lock_step(),
   pura e testata: manutenzione entro tolleranza = un solo avviso morbido, che
   sfora = un solo 🚨 ('ha SFORATO'), blocco inspiegato = 🚨 subito, rientro
   annunciato una volta. public/status illeggibile NON e' un rientro.

2. Il messaggio diceva 'locked=true' cablato mentre il parser accetta anche
   'partial': dichiarava un valore che non aveva letto, e il runbook manda a
   controllare proprio quel campo. Ora stampa e salva il valore grezzo.

3. Deribit ha cambiato tick e size dei perpetual lineari USDC il 18/08 e la
   tabella _CONTRACT, cablata a mano, non se n'era accorta. Nessun ordine
   rifiutato solo perche' i cambi erano riduzioni: e' andata bene per la
   direzione, non perche' ce ne fossimo accorti. Tabella aggiornata ai valori
   verificati e aggiunto check_specs(), che gira nel venue_watch orario (fuori
   dal percorso ordini) e dichiara la direzione: 'granularita'' = conforme,
   'rifiuto' = il venue rifiuta. La tabella dichiarata resta l'autorita' per
   costruire un ordine, il venue e' il controllore.

4. Aggiunta Kraken come terza referenza: Coinbase ha comprato Deribit, e una
   referenza che e' la casa madre non misura piu' se Deribit scolla dal mondo.
   THRESHOLD_BPS e PERSIST_HOURS invariati, ma il consenso ora e' su tre serie
   e quel numero non e' ri-misurato: dichiarato nel codice e nel diario. La
   direzione dell'errore e' 'allerta di meno', non 'grida al lupo'.

Test 23 -> 35 su venue_watch, suite intera 618 verdi. Book, pesi e config
invariati; dry-run del book verificato. Diario: docs/diary/2026-08-19-*.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 10:10:55 +00:00
Adriano Dal Pastro d55eb13533 feat(chain): assorbita la raccolta catena opzioni, cerbero-bite dismesso
cerbero-bite viene eliminato. L'unica sua parte irreversibile e' il DATO:
una catena opzioni non si ricostruisce a posteriori (Deribit non serve book
storici, non c'e' un secondo venue). Il codice si riscrive; le ore non
raccolte no.

ASSORBITO
- scripts/live/collect_chain.py + scripts/cron_chain.sh (cron 25 * * * *):
  raccolta propria, ~570 strumenti/giro, ~3 min.
- scripts/analysis/import_cb_archive.py: archivio 1.23M righe (2026-05-01+)
  + market_snapshots 17.402 righe (2026-03-26+: dealer gamma, gamma flip,
  rischio liquidazioni, funding cross — dati che non abbiamo altrove).
- snapshot sqlite integrale in /opt/docker/backups/manual/ (SHA256).

NON ASSORBITO, con motivo: motore credit-spread ETH (regola "niente
short-vol da modello in deploy", conto a $52 contro minimo $720), GUI, kill
switch/dead-man/audit (abbiamo venue_watch/edge_watch/monitor_health/
fee_watch), dvol_history (fetch_dvol.py ha storia PIU' LUNGA: 2020+ contro
2026-05), decisions/positions (0 posizioni).

TRE DIFETTI DI BITE NON REPLICATI, tutti misurati il 30/07:
1. una chiamata per strumento invece di due (get_order_book?depth=3 da' gia'
   quote+greche+IV+OI+book+underlying) + prefiltro OI in una chiamata sola:
   551 -> ~290 chiamate per asset;
2. pacing invece di raffica. Il carico non e' mai stato il problema: 570
   chiamate/ora = 0.16/s DISTRIBUITE; bite le sparava in 26s (~44/s) e si
   auto-saturava il rate limit per-IP (12.186 risposte 429 in 26h, 96% al
   minuto :00). Primo giro reale: 574 chiamate, 0 risposte 429. Il minuto :25
   e' scelto: :00 era la raffica, :07 e' cron_book (feed 5m di SKH01).
3. quote_status esplicito {ok, no_quote, error} e book_depth NULL su errore
   mai 0. "Book vuoto" e "chiamata fallita" sono cose diverse: e' per questo
   che il guasto del 29/07 (50% di quote perse, 38 ore) non produsse alcun
   segnale. Le righe ereditate restano 'unknown': bite non lo registrava e a
   posteriori non e' ricostruibile.

Battuta di cuore in data/chain_collect/runs.jsonl anche a giro fallito,
sorvegliata da monitor_health (1h, max_age 3h): un collettore fermo non
produce niente, e il niente si legge come "nessun dato quel giorno".

Difetto trovato per strada: due formati ISO nella stessa colonna (92 righe
di backfill senza microsecondi). pd.to_datetime senza `format` ne inferisce
uno solo e manda gli altri a NaT -> il dropna a valle li toglieva in
silenzio, e la serie di contesto perdeva 5 settimane slittando dal 26/03 al
01/05. Corretto con format="ISO8601" e scarto RUMOROSO.

Book, pesi, config, strategia INVARIATI. 537 test verdi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 20:14:34 +00:00
Adriano Dal Pastro 7d64dd4c2b live(feed): l'allerta funzionava, la sua CAUSA era una riga cablata
Il 29/07 il feed 5m di SKH01 e' ricaduto sul certificato in 6 giri orari su 8
(eta' 265->685 min, +60 a ogni giro = firma esatta del fallback): latenza
d'uscita da ~1h a ~11h, book flat, nessuna posizione esposta. L'allerta del
26/07 ha segnalato 6/6, poi ha stampato un perche' che non aveva misurato —
la nota "fetch pubblico KO" era cablata, identica in ogni caso, compreso
quello in cui la coda fresca E' attaccata e il vecchio e' il certificato.

E la causa vera non era recuperabile per costruzione: _fetch_recent_5m ingoia
l'eccezione di pagina con un break e a prima pagina fallita ritorna un frame
vuoto, indistinguibile da "il venue non ha barre".

Cablato: livefeed.last_fetch_error() (registra E logga nel punto in cui
l'errore viene ingoiato) -> book_report.skh_feed_errors -> allerta con la
causa. Stesso buco chiuso sul ramo gemello "conto offline", che la ragione
l'aveva gia' in mark_src e non la stampava mai.

La causa del 29/07 resta IGNOTA e va citata cosi': una prima stesura la
attribuiva a un rate limit per-IP come se fosse un fatto -> rimossa, sarebbe
stato lo stesso difetto che stavo correggendo scritto meglio. Cron spostato
al minuto :07 come ripiego da UNA osservazione, dichiarato tale.

Test 11 -> 16 (incluso il caso a meta' paginazione: coda parziale attaccata,
mancano le barre PIU' recenti). Book/pesi/config/strategia INVARIATI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 12:20:42 +00:00
Adriano Dal Pastro fd05307c96 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>
2026-07-27 14:14:39 +00:00
Adriano Dal Pastro 95caeb87da feat(live): allerta sul salto di equity — conferma il versamento, segnala un prelievo
La verifica "il cap si adegua?" esisteva solo come sorveglianza di sessione, e il
versamento slitta di giorni: una verifica che vive in una chat non e' una verifica. Resa
permanente e generalizzata.

`write_equity_watermark` ora ritorna {prev, new, pct} quando il salto fra due letture
consecutive supera EQUITY_JUMP_ALERT = 10%; `book_report` lo espone come `equity_jump` e
`book_execute` manda un Telegram con il NUOVO DIMENSIONAMENTO accanto (cap/asset, nozionale
lordo, leva), cosi' il messaggio si legge senza aprire il repo.

Il book ha vol ~0.4%/giorno: un salto del 10% fra due giri orari non puo' venire dal
trading. Quindi l'allerta copre DUE casi con un meccanismo solo:
  - VERSAMENTO: conferma che e' atterrato e che il sizing lo ha seguito;
  - USCITA DI FONDI: un prelievo che non hai chiesto, o una perdita anomala. E' questo il
    caso che conta di piu', ed e' il motivo per cui la soglia e' a due code.

Prima lettura in assoluto -> nessun allarme (senza un "prima" non c'e' un salto).
Il watermark si aggiorna ANCHE quando allerta, o il cap resterebbe indietro (test cablato).

411 test verdi (+7). Strategia, pesi, cron, config INVARIATI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 21:23:28 +00:00
Adriano Dal Pastro 8b21d29e69 fix(dashboard): taglia del book letta dal conto, non cablata
Il cruscotto dichiarava "cap $300/asset · capitale reale ≈ $600" come testo fisso: sarebbe
diventato falso al primo deposito, sulla pagina che si guarda per capire cosa sta girando.
Ora legge equity reale + max_notional_per_asset_frac + disaster_sl_pct dalla config.

Reso dinamico solo il testo di stato del book LIVE. I $600/$2000 restanti in dashboard.py
sono i capitali d'inizio CONGELATI dei libri paper (forward-monitor): quelli devono
restare fissi o le serie perdono continuita'.

Verificato il percorso di ESECUZIONE: nessuna assunzione cablata sulla taglia da $600
(book.py / shadow.py / book_execute.py). Reso: "capitale reale $596.92 · cap $298/asset ·
disaster-SL on-book −30%".

391 test verdi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 20:53:57 +00:00
Adriano Dal Pastro b023cc2bdf fix(live): cap di fallback legato all'ultima equity osservata + cap config 300 -> 3000
L'operatore ha autorizzato "si alza il cap a 3000". Verificato PRIMA di eseguire: il
deposito non era ancora arrivato (equity reale $596.92), e alzare il cap in quel momento
sarebbe stato pericoloso NEL VERSO OPPOSTO.

IL PROBLEMA. Quando l'equity reale non e' leggibile, shadow_report ripiega su paper_cap =
$2.000 NOMINALI, che non e' il conto vero: il sizing diventa 0.5 x 2000 x (...) = fino a
$1.000/asset, e il cap fisso e' l'unica cosa che impedisce a quel nominale di diventare
leva reale.
  cap $300  -> fallback $600 lordi su $597 = 1.00x  OK
  cap $3000 -> fallback $2.000 lordi su $597 = 3.35x  NO
Cioe' il cap sarebbe stato troppo alto proprio nel momento in cui non si sa quanto c'e'
sul conto, e con disaster_sl_pct -30% quella e' la configurazione peggiore possibile.

LA CORREZIONE. Invece di alzare un numero da ricordare, il cap di fallback e' legato al
conto: cap_fallback = min(cap_fisso_di_config, ultima_equity_reale_osservata * frac), con
watermark in data/live/equity_seen.json scritto da book_report ogni volta che l'equity
reale e' leggibile. Il cap di config torna a essere un TETTO DICHIARATO.
Senza watermark (primo avvio, file cancellato) -> CAP_UNKNOWN_USD = $300: non si sa niente
del conto, si usa la taglia storicamente sicura.

VERIFICATO SUL CONTO VERO, nei due regimi:
  oggi, watermark $596.92    ->   $298.46/asset = leva 1.00x
  dopo il versamento, $6.047 -> $3,000.00/asset = leva 0.99x
Sicuro in entrambi gli ordini di eventi, senza dipendere da un'azione manuale al deposito.

Questo CHIUDE l'azione pre-registrata il 2026-07-02 ("al deposito alzare il cap a
equity/2"), rimasta ineseguita per 24 giorni — non eseguendola, ma rendendola non
necessaria.

REGOLA: un parametro di sicurezza che va aggiornato a mano a ogni cambio di scala e' un
difetto, non una configurazione. Lo stesso numero era sbagliato in un verso prima del
deposito e nell'altro dopo: la soluzione non era scegliere il valore giusto, era legarlo
alla grandezza che lo determina.

Guardie: tests/test_cap_watermark.py (11), A DUE LATI — il cap non puo' ne' superare il
conto reale (leva nascosta) ne' restare sotto dopo un deposito (strozzatura).
Dry-run sul conto reale: cap/asset $298, book flat, nessun ordine. 391 test verdi (+11).

Strategia, pesi, cron INVARIATI. Cambia solo config/live.json e il calcolo del cap di
fallback.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 20:44:27 +00:00
Adriano Dal Pastro ab5bcace16 feat: VENUE WATCH — tripwire di fallimento exchange, cablato live
Risposta a "trova un sistema di protezione da fallimento exchange" SOTTO IL VINCOLO
della decisione appena presa (100% Deribit fino a $20k). Se non si puo' ridurre
l'ESPOSIZIONE, l'unica leva e' il TEMPO: il modello di rischio del mattino assumeva il
salto a zero istantaneo, ma i fallimenti reali non lo sono (Mt.Gox mesi, FTX ~72h, e
misurato qui: Bitfinex 2018-19 dislocato per 2.324 ore consecutive).

SEGNALE: un venue che gata i prelievi rompe l'ARBITRAGGIO -> il prezzo si stacca dal
consenso e ci resta. E' |scarto|, non il segno (Mt.Gox a premio, un venue in fuga a
sconto: stessa cosa). Consenso = venue USD indipendenti (Coinbase, Bitstamp), mai USDT.
Deribit sta a 3 bps dal consenso in mediana su 8 anni (65.043 ore BTC + 64.541 ETH).

TARATURA CONGELATA: 100 bps persistenti 4h a segno costante. Criterio DICHIARATO PRIMA,
perche' i due ovvi sbagliano in versi opposti (provati entrambi): "minimi bps" -> 25/24h
consuma 24 delle ~72h di FTX; "minime ore" -> 500/2h MANCA FTX (margine 0.6x). Regola:
zero falsi allarmi in 8 anni + margine >=3x sul caso storico piu' debole -> soglia
<=100bps -> poi minima latenza. Margine 3x FTX / 5x Quadriga / 10-20x Mt.Gox, zero falsi
allarmi con crash COVID, maggio 2021, LUNA e novembre 2022 inclusi.

CONTROLLO POSITIVO SUPERATO (un rilevatore tarato per non segnalare e' indistinguibile da
uno rotto): puntato su Bitfinex 2018-19 scatta 22 volte, episodio piu' lungo 2.324h a
+447bps. 22 dove il problema c'era, 0 su Deribit. E la durata risponde alla domanda vera:
un venue gated resta dislocato per settimane, quindi 4h di latenza sono trascurabili.

ECONOMIA: falso allarme = 0.248% atteso (flat 3g misurato sul book reale a ogni data
d'inizio); vero positivo = 100% salvato. Break-even p > (falsi/anno) x 0.00248: a 1 ogni
8 anni serve p > 0.031%. Il valore sta nella SPECIFICITA', non nella sensibilita'.

CABLATO: src/live/venue_watch.py (nucleo puro) + scripts/live/venue_watch.py, in
cron_book.sh PRIMA di book_execute (se Deribit e' in stress l'allarme deve partire anche
quando l'esecuzione fallisce per la stessa ragione). Tre stati OK/ALERT/BLIND — "non
vedo" non e' "va bene". ALLERTA, NON BLOCCA: l'azione e' prelevare (manuale; una chiave
con permesso di prelievo sarebbe essa stessa un rischio) e bloccare non protegge un saldo
che e' a rischio anche stando flat. Runbook pre-deciso nel docstring.

NON COPRE, e non e' un argomento per riaprire il 26/07: un fallimento SENZA finestra
(furto chiavi, sequestro, exit-scam) non lo prende nessun tripwire.

ERRORI CATTURATI IN SESSIONE:
- break-even calcolato sul p5 invece che sulla media (8.3x piu' severo, conclusione
  ribaltata);
- ipotesi meccanica sbagliata: credevo che i crash dislocassero a segno ALTERNATO. Falso,
  sono a segno costante anche loro (perp sotto spot per ore in cascata). A separare sono
  ampiezza e durata, non il segno;
- la prima corsa tronco' il campione da 8 anni a 29 GIORNI per un inner-join con Kraken
  (che serve solo ~700 candele) e la copertura era gia' stampata a video: una diagnostica
  stampata NON e' un controllo. Ora c'e' una guardia che ferma lo script. 2a occorrenza
  in un giorno dopo GTAA01;
- il controllo positivo era finito dentro il ramo `else` -> non girava mai, cioe'
  esattamente il difetto che doveva prevenire.

Book, pesi, config INVARIATI. 359 test verdi (+23).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 19:38:19 +00:00
Adriano Dal Pastro 031b71bf54 ops(live): sorveglianza freschezza feed SKH + correzione dei docstring sulla latenza d'uscita
T1 (TP di SKH01 come limit resting on-book) NON e' stato implementato, per misura.
Leggendo il codice di produzione: TP01 e SKH01 tradano lo stesso strumento con una
sola posizione netta Deribit, quindi un ordine on-book al livello di SKH chiuderebbe
anche quota TP01. Misurati i due ostacoli: (A) segno compatibile nel 97% dei trade
che escono in TP = risolvibile; (B) divergenza modello/live apparentemente bloccante.

Ma (B) non esiste: resample_5m NON scarta il bin 230m in corso (21 barre 5m su 46
nell'ultimo bin) e _skyhook_positions ci itera dentro -> il live rileva gia' SL/TP
intra-barra, entro ~1h dal tocco. I docstring che dicevano "usa solo barre chiuse" e
"latenza fino alla chiusura della barra 230m" erano FALSI e hanno guidato tre analisi
(02/07, 24/07, T1). Corretti sul posto.

Conseguenza: la lente `hourly` sottostima il path live di +0.081 Sharpe FULL di book
(23/23 offset, banda appaiata); il live vero sta sopra il canonical sul FULL, e il fix
richiesto sarebbe un declassamento (+0.054 vs +0.081) in cambio di ordini parziali sul
netto in un percorso con soldi veri.

Cablato invece il problema vero trovato per strada: fresh_5m fallisce in SILENZIO
(fallback al certificato, rigenerato 1x/giorno) -> la latenza d'uscita di SKH01 passa
da ~1h a ~1 giorno senza segnalazione, e nessun controllo esistente scatta (il gate di
staleness guarda il feed di TP01). Stesso schema del feed-freeze del 14/07.

  * livefeed.feed_age_minutes: pura, eta' dalla CHIUSURA della barra, None = non
    misurata, clamp sugli skew d'orologio
  * book_report espone skh_feed_age_min (max fra gli asset)
  * book_execute stampa lo stato e allerta su Telegram sopra skh_feed_max_age_min (30m)

Scelta dichiarata: ALLERTA, NON blocca. Bloccare fermerebbe anche TP01 (nettato sullo
stesso strumento) per un guasto di rete; forzare SKH flat chiuderebbe posizioni buone
su un glitch.

Follow-up dichiarato: la stessa barra parziale tocca gli INGRESSI (ent[n-1] da breakout
non confermato). Disaccordo in 1 bin su 112, ma con 3 entry nel campione la taglia non
e' stimabile. E' un cambio di strategia, non di strumentazione -> misura dedicata prima.

Strategia, pesi e cadenza del cron INVARIATI. Nessun ordine inviato. Suite 266 verdi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 20:20:01 +00:00
Adriano Dal Pastro 67f7b89e4c chore(live): ritira paper_trend inerte -> Old/ — sostituito da paper_portfolio
Il paper trader standalone TP01 (paper_trend.py) era inerte dal 2026-06-19
(n_bars=0), non in cron, e sostituito da paper_portfolio (TP01+XS01, gira ogni
giorno). Archiviato in Old/scripts/live/ e stato congelato rimosso.

Book live INTATTO: shadow.py legge PAPER_STATE con guardia .exists() -> degrada
a FALLBACK_CAPITAL=2000 (identico allo stato congelato) e paper_pos=None. Dry-run
di book_execute identico prima/dopo (conto online, HOLD su BTC/ETH).

- git mv scripts/live/paper_trend.py -> Old/scripts/live/paper_trend.py
- rm data/paper_trend/ (state inerte, gitignored)
- CLAUDE.md: 3 riferimenti -> paper_portfolio + nota di ritiro
- live_trend.py + shadow.py: hint/commento fallback legacy aggiornati

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 15:42:29 +00:00
Adriano Dal Pastro cf7de40dc0 feat(live): cap/asset dinamico = equity/2 — operazionalizza la decisione frontier (inerte a $600)
Il cap notional per-asset non e' piu' fisso a $300: con max_notional_per_asset_frac
in config diventa equity/2, cosi' cresce col capitale e un deposito futuro non resta
strozzato (frontiera 2026-07-03). Guardrail: dinamico SOLO con equity reale fidata;
su fallback/offline si torna al cap fisso (protezione downside quando E e' ignota).
Live dry-run: cap $299 a equity $598 -> inerte oggi. Suite 172 passed (+4 test).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 09:42:13 +00:00
Adriano Dal Pastro ccf5e38101 feat(dashboard): banner alert operativi del book live (SKH/posizione/equity)
Il dashboard non mostrava nessuno dei tre segnali di health introdotti nei
commit 31369b3 (skh_error) e 5670469 (pos_error/eq_fallback): finivano solo su
Telegram + log cron, invisibili a chi guarda il monitor. pos_error/eq_fallback
erano gia' in shadow_report (usato dal dashboard) ma ignorati dal template;
skh_error non era nemmeno recuperato (il dashboard usa shadow_report, non
book_report).

Fix:
- _alerts_banner(): helper puro (verde "nessun alert" se pulito, rosso con una
  riga per errore) che rispecchia i tre alert di book_execute.
- build(): raccoglie pos_error/eq_fallback dallo shadow gia' fetchato + skh_error
  da book_report(offline=True) (feed certificato, nessuna rete extra).
- html(): renderizza il banner in cima alla sezione ① LIVE.
- tests/test_dashboard.py: +4 (verde, 3 alert, parziale, chiave-ignota).

Suite 160/160. Render end-to-end verde (conto sano $598.06 flat). Chiude la
copertura: i 3 pattern di errore silenzioso ora visibili su log + Telegram + dashboard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:47:35 +00:00
Adriano Dal Pastro 567046953d fix(book): gate fail-safe posizione + diagnostica equity — niente errori silenziosi nel path live
Terza+quarta chiusura del pattern "eccezione ingoiata -> stato safe silenzioso"
in src/live, dopo skh_error (31369b3). Emerse durante la verifica del gate SKH01.

Opzione A (gate fail-safe posizione):
- shadow._positions: se la read della posizione reale Deribit lancia, assume flat
  MA ora ritorna un pos_error esplicito (prima solo una note mai propagata).
- Propagato shadow_report -> book_report -> book_execute: se ONLINE ma posizione
  IGNOTA, l'esecutore NON opera a cieco (return + alert), come gia' per 'online'.

Opzione B (diagnostica equity, no halt):
- shadow._equity/shadow_report: se ONLINE ma equity reale non leggibile, il book
  ripiega su paper_cap (~$2000) invece del conto reale (~$598) -> sovradimensiona
  ~33%, ma l'hard-cap $300/asset limita il downside. Nuovo flag eq_fallback ->
  book_execute stampa warning + alert Telegram MA prosegue (niente gate: la scelta
  e' solo diagnostica, l'hard-cap gia' protegge).

Test: +8 (4 gate A, 4 diagnostica B). Suite 156/156. Path live pulito
(skh_error/pos_error/eq_fallback = None). Diario 2026-07-01-book-live-error-surfacing.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:39:59 +00:00
Adriano Dal Pastro 31369b358c fix(book): esponi skh_error nel book live — niente flat SKH silenzioso
book_report scriveva skh_error in un dict locale MAI incluso nel return ->
r.get("skh_error") era sempre None. E book_execute non lo leggeva comunque.
Risultato: se il feed SKH (fresh_5m) fallisse, il book forzava SKH a flat in
silenzio, indistinguibile da un flat legittimo -> entry SKH reale mancato,
nessun alert.

Fix:
- src/live/book.py: skh_error come variabile esplicita, esposta nel dict di
  ritorno (None normalmente). Il fail-safe (SKH->flat, TP01 indipendente sul
  suo feed certificato) resta invariato.
- scripts/live/book_execute.py: emette la riga di log + alert Telegram quando
  skh_error e' presente.
- tests: book_report cattura-e-flagga l'errore; book_execute lo fa emergere
  (log + notify). Suite 148/148.

Contesto: verifica del gate SKH01 dopo 193 run flat dal 06-23 (gate SANO —
335/341 entry storici, shorta i crash; flat legittimo: ultimo entry 06-06
chiuso ~06-08 pre-arming). Questo chiude il rischio latente scoperto durante
la verifica.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 22:26:02 +00:00
Adriano Dal Pastro ee82e0a056 feat(dashboard): box forward-monitor STATARB-RESID (lead ortogonale+eseguibile)
Aggiunge il forward-monitor STATARB-RESID al dashboard accanto a PREVDAY (sezione
③·c FORWARD-MONITOR): carica data/paper_statarb/state.json, mostra doppio libro
MODELED/REAL-$600, ret/maxDD/fill-haircut, posizione spread corrente e giorni forward.
Warn aggiornato: LEAD sotto deflated-Sharpe -> forward per confermare l'edge, non deploy.

Smoke-test html() OK (box presente, dati live). Test 146/146.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:20:56 +00:00
Adriano Dal Pastro db738bce3b feat(live): arma il BOOK DERIBIT (TP01+SKH01 nettati in software)
Estende l'esecuzione live da TP01-only al book Deribit-only completo. TP01 e SKH01
tradano lo STESSO strumento (una sola posizione netta per conto su Deribit) -> netting
in software: un solo ordine/asset verso il target netto.

- src/live/book.py: target NETTO per asset = clamp(0.5*E*(0.75*tp_frac + 0.25*skh_sign), ±cap).
  Riusa current_target (TP01, causale) + _skyhook_positions (segno L/S, book 230m) + conto reale.
- src/live/execution.py: rebalance_signed() — reconcile CON SEGNO (long/short, flip via close+open,
  reduce reduce_only). La close resta sempre permessa (si esce da qualunque posizione).
- src/live/livefeed.py: fresh_5m() — feed 5m certificato + coda recente EFFIMERA da Deribit pubblico
  (stesso simbolo inverse, in-memory, NON scrive su disco -> dati certificati intatti; fallback al
  certificato su errore). Solo SKH01 ne ha bisogno (e' a 230m); TP01 e' giornaliero.
- scripts/live/book_execute.py: executor doppio-gate (config + --execute), disaster-SL on-book sulla
  posizione netta, log in data/live/book_executions.jsonl. Feed SKH fresco (live_feed=True).
- scripts/cron_book.sh + crontab ORARIO: book idempotente ogni ora (riconcilia al netto corrente);
  rimossa la riga live_execute.py (TP01-only) dal cron daily per non far collidere i due.
- config/live.json: ARMATO (execution_enabled=true). cap/asset $300 split 75/25, disaster-SL -30%.
  Tutto flat all'arming -> nessun ordine finche' un segnale non arma.
- tests/test_book_live.py: 20 test (sizing 75/25, cap, flip/close/reduce, parita' pesi backtest,
  gate-safety, reconcile con trader fittizio, merge/dedup feed + fallback, loader onorato). 76/76 pass.

CAVEAT: exit SKH SOFTWARE (latenza fino a fine barra 230m; solo disaster-SL on-book); TP01 scende a
peso 0.75 (max $225/asset); SKH01 resta research-grade (equity daily-step, margine DD ETH sottile).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 21:43:27 +00:00
Adriano Dal Pastro 25a22fc7c1 feat(dashboard): riordino LIVE→trades→storico + trade/anno contati
- dashboard riorganizzata in 3 sezioni: ① LIVE (mainnet sola lettura) in
  alto, ② TRADES ESEGUITI (reali) + frequenza operativa al centro,
  ③ STORICO (backtest/forward simulato) in fondo (COMBO/BOOK/FORWARD come ③·a/b/c).
- book_trade_frequency() in sleeves.py: trade/anno CONTATI sui dati certificati
  (cache di modulo, una volta per processo). SKH01 round-trip BTC ~37 / ETH ~43
  -> ~75/anno combinato; TP01 turnover ~7x/anno. Card "trade/anno" + blocco freq.
- fix: collisione var `pos` nel ramo shadow-online (-> shpos) che avrebbe rotto
  la tabella posizioni se il conto fosse leggibile dal container.
- fix: turnover TP01 nan (disallineamento groupby) -> groupby posizionale, 7.2x/anno.
- 56 test pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 21:18:52 +00:00
Adriano Dal Pastro eeac97dde4 feat(dashboard): Deribit-only book panel (TP01+SKH01) + accumulation forecast
New section showing the executable Deribit-only book (TP01 75% + SKH01 25%): combined
FULL/HOLD Sharpe+DD, plus the reinvest-winnings accumulation projection (historical &
conservative CAGR, €5k→5y/10y, conservative €/day run-rate). Reuses the already-computed
sleeve daily series (no extra heavy compute). Honest caveats (bull sample, no leverage,
SKH01 not live, ~€177k for €50/day).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 20:43:47 +00:00
Adriano Dal Pastro 7eb0f67956 feat(dashboard): show SKH01 sleeve in 4-sleeve portfolio view
active_sleeves() already feeds the per-sleeve table & combined metrics, so SKH01
appears automatically. Manual touch-ups: title/docstring -> +SKH01; position label
is now sleeve-aware (the None fallback used to mislabel every pos-fn-less sleeve as
XS01's "book 19 gambe" — now XS01/SKH01/VRP01 get correct labels); footer note adds
SKH01 (quasi-orthogonal @25%, FULL Sharpe 1.68->2.13, DD 14->8%, research/forward-monitor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:41:52 +00:00
Adriano Dal Pastro 010d1f0733 feat(combo): paper combo NUDO vs PROTETTO (guardia-DD -4%) affiancati + dashboard
paper_combo traccia forward entrambe le versioni; dashboard mostra nudo + protetto. Guardia-DD:
de-risk 0.4x a DD>-4%, ri-rischia a -1.6% (backtest MaxDD 8.4->5.8%, 2022 -4.4->-1.8%). Opzioni
escluse (non aiutano il grind). Container ricostruito.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:59:07 +00:00
Adriano Dal Pastro 389573e517 feat(dashboard): pannello COMBO cross-venue (TP01 Deribit + GTAA IB)
Aggiunge alla dashboard la sezione "COMBO DEPLOYABLE — cross-venue (paper)": equity paper forward
del blend 50/50 TP01+GTAA (da data/paper_combo/state.json) + posizioni azionabili IB correnti
(gtaa_weights: peso ETF + cash, asof). Nota onesta: paper rischio-zero, Sharpe ~1.5 ottimistico, il
robusto e' la diversificazione (corr 0.21, DD dimezzato); XS01/VRP01 esclusi (STAT-MODE).
Container ricostruito (codice baked nell'immagine).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 12:32:19 +00:00
Adriano Dal Pastro b5db59bea9 feat(dashboard): mostra il forward-monitor PREVDAY (lead ortogonale a TP01)
Nuova sezione "FORWARD-MONITOR — lead paper (non deploy)" nel dashboard, tra PAPER e LIVE:
legge data/paper_prevday/state.json e mostra i due libri (modeled €2k nominale vs real-$600
con min-order $5), ret/maxDD di entrambi, il fill-haircut, le posizioni correnti BTC/ETH e
i giorni/flip forward. Nota esplicita: LEAD in osservazione, NON deployato.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:27:27 +00:00
Adriano Dal Pastro bf84bc91e2 feat(live): alert Telegram su esecuzione ed errori
src/live/notifier.py (stdlib, no-op se non configurato): legge TELEGRAM_BOT_TOKEN/CHAT_ID da env o
.env(.mainnet) gitignored. live_execute.py invia alert su: ordine eseguito (), ordine non
verificato (⚠️), disaster-SL piazzato/fallito (🛡️/⚠️), conto offline, e qualsiasi eccezione (🛑).
Nessun alert nei giorni flat/HOLD (no rumore). Config gia' presente in .env -> alert attivi.

Test config: uv run python -m src.live.notifier "msg". Test 28/28.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 16:09:09 +00:00
Adriano Dal Pastro 3cba5bb9d0 feat(dashboard): mostra i disaster-SL attivi nella sezione LIVE
Lo shadow espone i bracket disaster-SL aperti (open_orders filtrati per label DISASTER_LABEL,
centralizzata in deribit.py): asset, stop price, size. La sezione LIVE li mostra
("disaster-SL attivi (-30%): ..." o "nessuno (flat)"). Test 28/28.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 16:05:18 +00:00
Adriano Dal Pastro e5e2d3ec9b feat(live): disaster-SL on-book con lifecycle completo (idempotente) nel loop di esecuzione
ensure_disaster_sl(): garantisce UN solo STOP_MARKET reduce_only a ~-30% coerente con la posizione,
ad ogni run del loop, per asset:
- flat  -> cancella i bracket orfani;
- long  -> assicura lo stop (size = posizione, prezzo al tick);
- gia' coerente (1 bracket, amount~=, stop entro 5%) -> lascia com'e' (niente churn ne' gap di
  protezione fra cancel e place).

- deribit.py: open_orders (merge type all+trigger_all), disaster_stop_price.
- execution.py: cancel_order + ensure_disaster_sl.
- live_execute.py: gestione bracket ogni run, gated come l'esecuzione. Validato armato: flat ->
  disaster-SL 'flat' (cleanup), zero ordini. Test 28/28.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:47:30 +00:00
Adriano Dal Pastro bc9e322d0d feat(live): loop di esecuzione GATED di TP01 (execution_enabled + --execute, default OFF)
scripts/live/live_execute.py porta il conto reale al target di TP01 (min(0.5*frazione*equity,
cap/asset)): apre/riduce/chiude via DeribitTrader.rebalance_to(). DOPPIO GATE: config/live.json
execution_enabled=true (master, default false) E flag --execute; senza entrambi e' dry-run.
Reconciliation post-ordine + log in data/live/executions.jsonl. TP01 flat -> 0 azioni.

- execution.py: rebalance_to() (open/reduce/close al target); MAX_AMOUNT alzato a tetto hard
  anti-fat-finger (~$630/$430 su conto ~$600), il sizing operativo lo decide config max_notional.
- config/live.json: master switch + cap/asset $300 + min ordine $5 + disaster_sl_pct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:37:51 +00:00
Adriano Dal Pastro a3d6b97db6 fix(dashboard): sezioni PAPER/LIVE evidenti (barra colorata) + Cache-Control no-cache
Le sezioni erano testo grigio poco visibile e il browser cacheava la pagina ('non vedo differenza').
Ora: header PAPER con barra verde, LIVE con barra rossa + sfondo rosso-tenue (separazione netta);
risposta HTTP con Cache-Control no-cache/no-store -> niente pagina stantia.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:36:21 +00:00
Adriano Dal Pastro cddea50c5a feat(live): conto USDC -> strumenti lineari; entrata/uscita da Old; dashboard LIVE separato da PAPER
Correzione post-micro-test (il conto e' USDC, non BTC/ETH):
- deribit.py: INSTRUMENT -> BTC/ETH_USDC-PERPETUAL (lineari, gli unici eseguibili sul conto USDC);
  notional_to_amount gestisce i lineari (amount in base-coin = notional/price); + quantize_price;
  trade_history (read-only) per i trade reali. build_rebalance_order passa il prezzo.
- shadow.py: sizing col prezzo; espone live_trades (trade reali eseguiti su Deribit).

Entrata/uscita verificate (logica presa da Old/src/live/execution.py):
- execution.py: open() market verificato (state=='filled' + trade, fill/fee reali, filled_amount
  autorevole), close() market reduce_only (le CHIUSURE si tentano SEMPRE, senza cap), disaster-SL
  STOP_MARKET reduce_only. Cap di size SOLO sulle aperture. Fill dataclass.
- microtest.py: usa open()/close(); safe-close se l'apertura non e' verificata.

Dashboard: sezione PAPER (backtest+forward) separata da sezione LIVE (conto reale Deribit: shadow
TP01 + Trades REALI eseguiti). Test 27/27.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:15:45 +00:00
Adriano Dal Pastro c00f6016df feat(live): micro-test esecuzione REALE su Deribit mainnet (USDC linear) — round-trip validato
Primo ordine reale post-reset, a rischio ~0 ($6 notional, leva 0.011x). Scoperto che il conto e'
USDC -> strumento eseguibile = perp LINEARE BTC_USDC-PERPETUAL (l'inverse BTC-PERPETUAL fallisce
'not_enough_funds'). Round-trip BUY/SELL reduce_only verificato: fill reali, fee reali (0.0064 USDC),
posizione tornata a FLAT, costo totale $0.0071.

- src/live/execution.py  : DeribitTrader (estende DeribitRead) con market order + verifica posizione,
  GUARDRAIL hard (solo BTC_USDC-PERPETUAL, amount <= 0.0002 BTC). Niente leva per-ordine (Deribit non
  la accetta: l'esposizione la decide la SIZE).
- scripts/live/microtest.py : runner round-trip, default DRY-RUN, --live per inviare. Pre-flight ABORT
  se posizione preesistente; chiusura reduce_only; verifica ritorno a FLAT.
- src/live/deribit.py    : aggiunti spec contratto LINEARI USDC (BTC/ETH_USDC-PERPETUAL).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 15:06:53 +00:00
Adriano Dal Pastro 715f197cf2 feat(dashboard): lista trades TP01 (entry/exit dal segnale causale)
Nuova sezione "Trades TP01" nella dashboard: eventi ENTRY long / EXIT flat dedotti da
target_series sui dati certificati (data, asset, transizione di posizione, prezzo). In
src/live/shadow.tp01_trades(): account-independent (gira anche offline nel container),
ricalcolata a ogni render -> storico + forward. Empty-state se TP01 non ha mai mosso.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 14:18:46 +00:00
Adriano Dal Pastro 9c48cdd884 feat(live): SHADOW MODE TP01 su Deribit mainnet (sola lettura) + dashboard 3-way
Validazione esecuzione di TP01 a RISCHIO ZERO: gira il loop live contro dati/conto/posizioni REALI
del mainnet, costruisce gli ordini di ribilancio esatti e li STAMPA invece di inviarli. Niente
testnet (e' la causa del reset v2.0.0: feed farlocco) -> shadow su mainnet reale + micro-test a
size minima come unica via per il fill (passo successivo).

- src/live/deribit.py  : client Deribit mainnet SOLA LETTURA (ticker/conto/posizioni via Cerbero MCP)
  + costruttore ordini deterministico (notional->contratti, step BTC $10/ETH $1, quantizzazione,
  delta vs posizione). Nessun metodo di trading, by design.
- src/live/shadow.py   : shadow_report() condiviso CLI+dashboard (niente drift); degrada con grazia
  se il mainnet non risponde.
- scripts/live/live_trend.py : CLI shadow (--no-net offline, --equity override). Verificato su
  mainnet reale: conto $598.07, posizioni flat, TP01 flat -> 0 ordini, parita' col paper OK.
- src/live/dashboard.py : box "Shadow live" + titolo/note al 3-way (TP01+XS01+VRP01).
- tests/test_live_shadow.py : 9 test deterministici (quantizzazione, sizing 50/50, entry/exit/None,
  parita' live==backtest). Suite 26/26.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 14:01:12 +00:00
Adriano Dal Pastro 26e977d338 feat(monitor): dashboard PAPER del portafoglio attivo (TP01+XS01) + paper forward loop
src/live/dashboard.py: web UI stdlib (:8787) che mostra metriche (FULL/HOLD Sharpe, DD, CAGR),
per-sleeve, posizioni correnti, equity (backtest + paper forward), ultimo dato. Solo MONITOR,
esecuzione REALE disabilitata. scripts/live/paper_portfolio.py: forward-only del portafoglio
(StrategyPortfolio su active_sleeves), stato persistente in data/paper_portfolio (gitignored).

Dockerfile + docker-compose.yml minimali (solo servizio dashboard; runner/esecuzione restano in
Old/). Container pythagoras-dashboard ricostruito col codice nuovo (il vecchio mostrava dati
pre-reset). Mount data/ read-only. .dockerignore esclude Old/data/.venv/.git/.env.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 08:57:55 +00:00
Adriano Dal Pastro 14522262e6 chore(reset): v2.0.0 — storico certificato Deribit mainnet, ripartenza pulita
Reset del progetto su fondamenta verificate dopo la scoperta che l'intera
libreria "validata OOS" era artefatto di feed contaminato (print fantasma del
feed Cerbero TESTNET + storico Binance/USDT).

- Storico ricostruito da Deribit MAINNET (ccxt pubblico, tokenless) e
  CERTIFICATO (certify_feed.py): BTC/ETH puliti su TUTTA la storia
  (mediana 2-6 bps vs Coinbase USD), integrita' OHLC + coerenza resample
  (maxΔ 0.00) + cross-venue OK. Alt esclusi (illiquidi/divergenti: LTC/DOGE
  50-82% barre flat; XRP/BNB non certificabili).
- Verdetto sul feed pulito: FADE / PAIRS / XS01 / TSM01 morti (ogni
  portafoglio Sharpe -2.3..-3.0, DD ~40%); solo SH01 e frammenti HONEST
  con segnale residuo, da ri-validare in isolamento.
- Cleanup "restart pulito": strategie, stack live (src/live, src/portfolio,
  runner/executor, yml, docker), ~100 script ricerca/gate, waste/games/
  portfolios, dati non certificati + cache e 60+ diari -> archiviati in Old/
  (preservati, non cancellati). Diario consolidato in un unico documento.
- Skeleton ricerca tenuto: Strategy ABC + indicatori + src/fractal +
  src/backtest/engine + load_data; tool dati certificati (rebuild_history,
  certify_feed, audit_feed, multi_source_check).
- Universo dati ATTIVO: solo BTC/ETH (5m/15m/1h); guardrail fisico
  (load_data su alt -> FileNotFoundError). Esecuzione DISABILITATA, conto flat.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 15:20:59 +00:00
Adriano Dal Pastro 264b9200ea feat(live): Stage 2 — GridWorker (Price Ladder) come PAPER sleeve nel runner
Wire del Price Ladder come sleeve PAPER (sim-only, fuori dal pool €500, NESSUN ordine reale):
- runner: kind="grid" -> GridWorker in build_worker_for; _spec_assets_tf grid; tick branch
  (w.tick(res[asset])); meccanismo PAPER_EXTRA (sleeve paper letti da overrides.paper_extra,
  NON da _defs.py -> NON entrano nel backtest canonico/regression-lock: PORT06 resta 19 sleeve).
  Parsing difensivo (un errore non crasha il runner mainnet). Loop dati estesi a paper_extra.
- GridWorker: bootstrap storia FULL (start fisso, come SH01) + mappatura capitale forward dal
  deploy (capital = initial*eq[-1]/base_norm) -> niente salti da finestra mobile; base_norm
  persistito (resume). grid_mtm robusto al df live (timestamp senza datetime; param df).
- portfolios.yml: GRID_BTC in paper_extra (regime range1.5, rd0.20/ru0.06, L6, sl0.10/tp0.03,
  position_size 0.15 PINNATO). Gira in data/portfolio_paper_stats/GRID_BTC/.
Validazione (validate_grid_worker.py): [A] logica n_trades==backtest, [B] forward-tracking
esatto, [C] resume esatto. Dry-test integrazione runner: import OK, build OK, tick OK, pos 0.15.
SICUREZZA: kind=grid mai eseguito reale (runner avvia ordini solo per single/ml); €500 intatti.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 16:18:53 +00:00
Adriano Dal Pastro b3d4ab7150 feat(live): GridWorker (Price Ladder) SIM/PAPER + validazione replay==backtest — shadow stage 1
Stage 1 dello shadow per il Price Ladder (config finale: BTC 1h range1.5 rd0.20 ru0.06 L6
sl0.10 tp0.03). GridWorker (src/live/grid_worker.py) gira sul feed LIVE e contabilizza
l'equity mark-to-market col motore CANONICO grid_mtm (parita' col backtest per costruzione),
SENZA piazzare ordini reali (sim/paper). Stato persistente + resume. grid_mtm esteso con
param df=None (retro-compatibile: il feed live passa il df; None = _load come prima, gate
invariato — BTC ladder 10.8/5.9, PORT06 base 8.18 identici). Validazione
validate_grid_worker.py: [A] full-tick == grid_mtm esatto, [B] replay incrementale converge
esatto, [C] resume entro la persistenza (4 dec) -> VALIDAZIONE OK.

NB SICUREZZA: nessuna modifica a runner/portfolios.yml/_defs -> il sistema mainnet (€500
reali) e' INTATTO; il worker e' inerte finche' non wirato. L'esecuzione REALE (griglia di
LIMIT resting su Deribit, fill parziali/episodi) e' lo stage 2-3, dietro testnet +
autorizzazione esplicita. Il runner avvia ordini reali solo per kind in (single,ml);
kind=grid resta sim per costruzione.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 14:58:11 +00:00
Adriano Dal Pastro c8b956ab56 fix(dashboard): PnL totale dal ledger, non init hardcoded 2000
La KPI "PnL totale" sottraeva un capitale iniziale fisso di 2000 (retaggio
testnet) -> sul micro-test mainnet da 500 mostrava -1499 (-74.95%) invece di
+0.95 (+0.19%). Nuovo helper _ledger_pnl(): legge pnl_total dall'ultima riga
di equity.jsonl (il ledger lo scrive come equity-initial_capital) e ne deriva
l'iniziale -> la dashboard combacia col ledger per costruzione, qualunque sia
il capitale (500 mainnet / 2000 testnet), niente piu' valori fissi da
aggiornare a mano. Fallback: primo punto equity, poi l'equity stessa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 09:48:33 +00:00
Adriano Dal Pastro b576ee66ac feat(worker): guard TP-invertito — sopprime l'entry quando il TP e' gia' sfondato (wick-print)
Un wick transitorio fa calcolare un tp dal lato sbagliato dell'entry (donchian: segnale
su barra wickata, entry al prezzo recuperato oltre il proprio tp) -> l'exit intrabar
scatta a bars_held=0 in perdita (16-06: 8 giri MR02_BTC 15m, sim -17.9 / reale -2.3).
TP_PHANTOM non lo prende (niente resting oracle, prezzo oltre il livello). Gate
zero-parametri in StrategyWorker._open_position, solo path live. Test + diario + CLAUDE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:16:13 +00:00
Adriano Dal Pastro faf08b3988 docs(spec): piano micro-test mainnet + token Cerbero env-configurabile
Piano operativo per validare l'edge su mainnet con poco denaro reale (il gate per
scalare). Fasi: smoke -> fade-only €1000 2-4 sett -> verdetto ledger-vs-backtest ->
espansione. Sizing motivato (fades €1000 = rumore arrotondamento 2.6% BTC; pairs
esclusi: 30% a quella taglia). Token ora da env CERBERO_TOKEN (default testnet
invariato) -> switch mainnet = solo .env, niente codice. is_mainnet() helper.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:36:26 +00:00
Adriano Dal Pastro 3ac8a46e6a feat(dashboard): trade attivi con data/ora ingresso + tempo in posizione
Nuove colonne 'Ingresso (UTC)' (entry_time) e 'In posizione' (durata dall'ingresso,
formattata m/h/g) con flag stantio. Sostituisce la colonna Eta (staleness) col
tempo di holding effettivo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:24:22 +00:00
Adriano Dal Pastro 7ee5b1767f feat(dashboard): solo dati REALI nei trade attivi + valore mercato reale (anche pairs) + attivi sotto il grafico
- entry/mark/unrealized SEMPRE reali (entry di esecuzione vs mark USDC live); il
  feed sim/decisione (testnet inverse dislocato) non e' piu' mostrato come prezzo
- pairs: valore di mercato reale di ENTRAMBE le gambe + PnL non realizzato reale a
  2 gambe (prima 'pairs (z)' senza valore)
- tabella attivi spostata subito sotto il grafico equity

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:21:22 +00:00
Adriano Dal Pastro d5a83075f8 fix(dashboard): unrealized usa entry REALE (non sim) per coerenza col mark reale
Le posizioni eseguite mostravano l'entry SIM (feed decisione testnet inverse,
dislocato ~1.3% dal lineare USDC) confrontato col mark REALE -> unrealized gonfiato
(SH01_ETH -1.36% invece di ~-0.25%) e due trade ETH con lo stesso entry sim 1661.95.
Ora entry = real_entry_price/real_entry_a se eseguito; unrealized vs mark reale su
base coerente. Indicatore '⚠sim' quando il feed di decisione diverge dal reale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 22:13:48 +00:00
Adriano Dal Pastro 183209dbd4 feat(dashboard): grafico equity per famiglia + tabella strategie raggruppata per famiglia
- nuovo grafico multi-linea 'Equity per famiglia' (PnL cumulato realizzato di ogni
  famiglia su asse-tempo comune, colori per famiglia, legenda col totale)
- tabella strategie reali raggruppata per famiglia con intestazioni colorate +
  PnL di famiglia; attive prima delle ritirate dentro ogni gruppo
- backend: fam_curves (step-wise cumulato per famiglia dai CLOSE reali), tag fam
  sui trade chiusi

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:48:56 +00:00
Adriano Dal Pastro e311d00fe4 fix(dashboard): tooltip equity allineato al mouse (responsive canvas)
Forzare l'altezza del canvas via CSS !important con maintainAspectRatio default
sfalsava la risoluzione interna vs quella mostrata -> hit-test tooltip offset dal
mouse. Fix canonico: canvas in contenitore .chartbox ad altezza fissa + chart
responsive:true/maintainAspectRatio:false + interaction index su tutti e 3 i grafici
(equity, modal, paper).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:35:15 +00:00
Adriano Dal Pastro f6287fcd36 feat(dashboard): area PAPER distinta con equity separata
I 4 multi-asset (TR01/ROT02/TSM01/XS01, solo statistica fuori dal pool reale) ora
in una zona dedicata con la PROPRIA equity (capitale nozionale + PnL cumulato del
book paper) e tabella separata. La tabella/fam_pnl/closed dell'area principale
diventano SOLO reali. Curva paper Chart.js (ocra), cliccabile -> stesso modal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:25:17 +00:00
Adriano Dal Pastro b6b465878a feat(dashboard): scheda per strategia (modal: curva PnL reale vs sim + trade + link grafici) + versione sistema/strategia + equity restyling
- click su una strategia -> modal con descrizione, versione di creazione/modifica,
  curva PnL CUMULATO reale vs sim (mostra il leakage), trade, e link alla scheda
  dettagliata strategie_attive.html (servita, docs/report montato ro)
- versione di sistema (APP_VERSION) nell'header; per ogni strategia la versione/
  origine documentata (mappa VERSIONS da CLAUDE.md)
- equity restyling: gradiente verde/rosso secondo segno, tooltip con EUR e delta,
  valore+delta in testata, assi in EUR, piu' alto. /api/strategy con guard
  path-traversal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 21:20:33 +00:00