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>
8.5 KiB
2026-07-26 — T1 nel live: il fix richiesto NON va fatto, e il perché è una correzione di modello
Richiesta: implementare nel live il fix T1 (TP di SKH01 come limit resting on-book). Esito: NON implementato, con i numeri sotto. Implementato invece ciò che le misure sostengono: la sorveglianza della freschezza del feed 5m di SKH01, e la correzione dei docstring che hanno causato tre settimane di misure sbagliate.
File toccati (produzione): src/live/livefeed.py, src/live/book.py, src/portfolio/sleeves.py
(solo docstring), scripts/live/book_execute.py, config/live.json.
Test: tests/test_skh_feed_freshness.py (11 casi) · suite 266 verdi.
Strategia, pesi, cadenza del cron: INVARIATI. Nessun ordine inviato.
1. Cosa ho trovato leggendo il codice di produzione
Il fix T1 nasceva da una simulazione in cui SKH01 esce per conto suo. Il live non funziona così, e il vincolo era scritto nel codice:
book.py: «gli exit sono SOFTWARE (no bracket on-book per SKH, sennò chiuderebbero anche la quota TP01)»
TP01 e SKH01 tradano lo stesso strumento e Deribit tiene una sola posizione netta. Un ordine on-book al livello di TP di SKH chiuderebbe una fetta della posizione netta, che è per il 75% di TP01. Ho quindi misurato i due ostacoli invece di assumerli:
(A) Compatibilità di segno — risolvibile. Un ordine reduce-only può muovere la posizione solo verso lo zero. Se SKH è short mentre il netto è long (perché TP01 pesa di più), chiudere lo short significa aumentare il netto: non esprimibile. Frequenza sui trade che escono in TP — gli unici che il fix tocca: 97% compatibili (SKH long 100%, SKH short 94%). Il 3% si sarebbe potuto saltare con fallback all'uscita software.
(B) Divergenza modello/live — sembrava bloccante. Se il limit riempie a metà barra ma il modello non "vede" l'uscita, il cron successivo ricalcola il target includendo ancora la quota SKH e ricompra ciò che il TP ha appena chiuso. Misurato assumendo la rilevazione a fine barra 230m: ritardo mediano 115 min, p90 210, e nel 70% dei TP almeno un cron gira nella finestra (mediana 1.9 cron, p90 3.5).
2. …e poi ho scoperto che il problema (B) non esiste
Il problema (B) presuppone che il modello veda le uscite solo a barra 230m chiusa. È ciò che dicono i docstring:
sleeves._skyhook_positions: «fino all'ultima barra 230m chiusa. Causale: usa solo barre chiuse»book.py: «latenza fino alla chiusura della barra 230m corrente»
Sono falsi. resample_5m non scarta il bin in corso — aggrega le barre 5m che ci sono
finora — e il ciclo di _skyhook_positions itera fino a n-1, quindi valuta gli hit di SL/TP
anche sul bin parziale, col suo high/low corrente. Verificato sul feed reale: l'ultimo bin 230m
conteneva 21 barre 5m su 46 (105 minuti su 230).
Quindi il live rileva il tocco entro il primo cron dopo il tocco (~1h), non a fine barra. E non è look-ahead: il livello è fissato all'ingresso da barre chiuse, e osservare che il prezzo l'ha già toccato è esattamente ciò che fa qualunque stop reale.
La conseguenza: il path live era modellato male da tre settimane
La lente hourly — usata dall'audit del 02/07, dal follow-up del 24/07 e dal mio stesso T1 di
stamattina — assume la rilevazione a fine barra. Il modello fedele è un altro (fastdetect:
rilevazione intra-barra a 5m, uscita a mercato al primo cron successivo). Sulla banda appaiata dei
23 offset, relativo al path live come veniva modellato:
| modalità | ΔFULL mediana [min,max] | ΔHOLD mediana | offset migliorati (FULL) |
|---|---|---|---|
fastdetect = il live VERO |
+0.081 [+0.00,+0.14] | +0.039 | 23/23 |
canonical (tetto teorico del backtest) |
+0.054 [−0.05,+0.12] | +0.099 | — |
onbook_tp (il fix richiesto) |
+0.054 [−0.03,+0.07] | +0.061 | 19/23 |
onbook (TP+SL on-book) |
+0.024 [−0.07,+0.11] | +0.031 | 17/23 |
Due letture, entrambe importanti:
- Il "−0.35 di degrado del path live" è in gran parte un artefatto di modello, sopra l'artefatto di ancora già trovato stamattina. Sul FULL il live vero sta sopra il canonical.
- Il fix richiesto sarebbe un declassamento: +0.054 contro i +0.081 che il live già fa — e in cambio si porterebbero in un percorso con soldi veri ordini parziali sul netto, un 3% di casi non esprimibili, e la riconciliazione fra fill del broker e stato del modello.
Per questo non l'ho implementato. Non è una difficoltà tecnica: è che la misura, fatta sulla lente giusta, dice che peggiorerebbe.
3. Il problema vero, trovato per strada
fresh_5m è il pezzo che tiene bassa la latenza d'uscita. E fallisce in silenzio:
try:
tail = _fetch_recent_5m(sym, lookback_days)
except Exception:
return base # ← nessun log, nessun errore, nessuna traccia
_fetch_recent_5m inghiotte a sua volta le eccezioni (except Exception: break). Se il fetch
pubblico Deribit non risponde, il segnale SKH gira sul feed certificato, che il cron ricostruisce
una volta al giorno. La latenza d'uscita passa da ~1 ora a ~1 giorno, e niente lo segnala:
il conto è online, la posizione è leggibile, il gate di staleness guarda il feed di TP01 — nessuno
dei controlli esistenti scatta. È lo stesso schema del feed-freeze del 2026-07-14, su un altro feed.
E conta esattamente quanto il resto di questo lavoro: la latenza d'uscita è dove vive la qualità del path live.
Cosa ho cablato
livefeed.feed_age_minutes(df5)— pura, testabile senza rete: età in minuti dell'ultima barra 5m, misurata dalla sua chiusura, conNoneper input non interpretabili (None= "non misurata", da trattare come sospetta: se tornasse0.0sembrerebbe fresca) e clamp a zero sugli skew d'orologio.book.book_report(live_feed=True)avvolge il loader per misurare la freschezza del feed effettivamente usato, e la espone comeskh_feed_age_min(massimo fra gli asset: se anche uno solo è stantio, il netto è sospetto).book_executestampa lo stato e allerta su Telegram sopraskh_feed_max_age_min(30 min, inconfig/live.json).
Scelta dichiarata: allerta, NON blocca. Bloccare fermerebbe anche il ribilancio di TP01 — sono nettati sullo stesso strumento — per un guasto di rete; e forzare SKH a flat chiuderebbe posizioni buone su un glitch. Non ho evidenza su quale politica di blocco sia giusta, quindi la decisione resta all'operatore, informato.
Docstring corretti
I due docstring falsi sono stati corretti sul posto, con la misura e il perché. Erano loro a sostenere la catena di ragionamenti sbagliata, ed erano la cosa più economica da riparare.
4. Follow-up dichiarato, non risolto
La stessa barra parziale che migliora le uscite tocca anche gli ingressi: ent[n-1] può
venire da un bin parziale, cioè da un breakout non ancora confermato a fine barra. Se il segnale
evapora, il book apre e richiude — churn puro.
Misurato su 112 bin campionati: entry sulla barra completa in 3, sulla parziale in 2, disaccordo in 1 (~1% dei bin). Ma con sole 3 entry nel campione la taglia dell'effetto non è stimabile: so che esiste, non so quanto pesa. Non l'ho toccato — a differenza delle uscite, qui il comportamento del live diverge dal backtest in modo sostanziale (entra su un segnale che il backtest non avrebbe visto), e sistemarlo è un cambio di strategia, non di strumentazione. Serve una misura dedicata prima di decidere in che verso.
5. Lezioni
- Prima di implementare una raccomandazione, leggere il codice che dovrà ospitarla. T1 era corretto sul suo modello e inapplicabile sull'architettura reale — e leggendo quel codice è saltato fuori che il modello stesso era sbagliato. La ricerca del mattino non lo poteva sapere: simulava lo sleeve, non il book nettato.
- Un docstring falso costa più di un bug, perché nessun test lo cattura e tutti ci ragionano sopra. Questi due hanno guidato tre analisi (02/07, 24/07, T1) verso una latenza che il codice non aveva.
- Un fallback silenzioso è un guasto silenzioso.
fresh_5mfa la cosa giusta (mai operare a cieco) ma non dice di averla fatta: la scelta giusta è tenere il fallback e misurarlo. - Terzo caso in due giorni in cui il numero di partenza era peggio di com'era stato scritto:
la fortuna d'ancora sul degrado (stamattina), la lente
hourly(qui), il wick indipendente (ieri). Ogni volta il difetto stava nella lente, non nella strategia.