Files
PythagorasGoal/docs/diary/2026-07-26-skh-partial-entry.md
T
Adriano Dal Pastro c8d31bc944 research(skh): misura dedicata sugli INGRESSI da barra 230m parziale
Chiude il follow-up dichiarato del 26/07 (misura T1). Il live valuta il segnale
a ogni giro orario del cron su una barra 230m mediamente completa a meta'; il
backtest solo a chiusura di bin. Domanda: di che segno e' il saldo.

Confronto di due path identici in tutto (livelli pct-asimmetrici, uscite
intra-barra, cap max_per_day, fee 0.10% RT) tranne quando si valuta l'ingresso.

  ΔSharpe (live - backtest), 3 offset x 2 asset:
    -0.01 / +0.04 / +0.44 / +0.32 / +0.59 / +0.98  -> 6/6 non negativi, mediana +0.38

Falsi ingressi ~5/anno/asset; cannibalizzano il cap 2-3 volte in 7 anni.
Meccanismo: Donchian breakout — aspettare la chiusura del bin fa pagare il
movimento gia' avvenuto (ingresso 0.25-0.26% peggiore), e su livelli percentuali
quello 0.26% vale il 6-13% della distanza dallo SL contro il 2.6-3.3% da quella
dal TP -> asimmetria a favore della sopravvivenza del trade.

Due attacchi superati:
  - il divario NON e' concentrato: togliendo i 5 giorni migliori si ALLARGA
    (ETH@460 35.6x vs 3.0x); e' il backtest il path concentrato;
  - nessun look-ahead intra-bin: troncando i 5m alle sole barre gia' chiuse la
    risposta e' identica in 289/289 osservazioni (test permanente). Serviva
    perche' il self-check valida solo a CHIUSURA di bin.

Verdetto: non e' un difetto da correggere, il verso e' lasciarlo. Ma live e
backtest girano due strategie diverse e la differenza non e' neutra: sommato
alla misura sulle uscite, il path live di SKH01 e' stato modellato in modo
sistematicamente pessimistico su entrambi i lati.

Book, pesi, cron, config INVARIATI.

Due errori di metodo catturati in sessione e codificati come regole:
  - un self-check su eventi rari si campiona sugli EVENTI (il primo dava
    "80/80 OK" confrontando zeri con zeri, con la ricostruzione rotta);
  - un conteggio su segnale grezzo non e' un conteggio di trade (sovrastima
    ~20x dei falsi ingressi ignorando cap e non-overlap del live).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 22:12:42 +00:00

11 KiB
Raw Blame History

2026-07-26 — SKH01: gli INGRESSI su barra 230m PARZIALE. Misura dedicata.

Richiesta: "fai la misura sugli ingressi con barra parziale". Follow-up dichiarato che chiude (registrato in CLAUDE.md stamattina, misura T1):

la stessa barra parziale tocca anche gli INGRESSI — ent[n-1] puo' venire da un breakout non confermato a fine barra → se evapora, il book apre e richiude. Su 112 bin campionati: disaccordo parziale-vs-completa in 1 (~1%), ma con sole 3 entry nel campione la taglia non e' stimabile … serve una misura dedicata prima di decidere il verso.

Script: scripts/research/r0726_skh_partial_entry.pytest: tests/test_skh_partial_entry.py (8). Book, pesi, cron: INVARIATI. Nessuna decisione di allocazione cambia.


0. Il fatto meccanico da cui parte tutto

resample_5m(..., origin="epoch") non scarta il bin in corso. Il cron gira a ore piene; una barra SKH01 dura 230 minuti. Quindi a ogni giro il live valuta il segnale su una barra 230m che, in media, e' completa a meta'. Il backtest invece valuta solo alle chiusure dei bin.

Stamattina ho misurato il lato uscite di questo fatto (e ho scoperto che il live esce gia' intra-barra, quindi le uscite erano modellate troppo pessimisticamente). Restava il lato ingressi, che e' l'opposto: il live puo' entrare su un breakout che a fine barra non c'e' piu'.

La domanda non e' "succede?" (succede per costruzione). E' di che segno e' il saldo.


1. Come si misura senza misurare la propria aritmetica

Il rischio di questa misura non e' sbagliare un numero: e' costruire una ricostruzione rotta e non accorgersene. signal_at(obs_ms, ...) ricostruisce il segnale che il live avrebbe visto a un istante arbitrario: storia completa fino a li' + barra parziale, passata per i veri htf_features / merge_htf_to_ltf / atr su una finestra di 200 barre HTF.

Due errori catturati in sessione, entrambi del tipo che passa i test se i test sono pigri:

(a) Self-check vacuo + bug di confine. La prima versione stampava "BTC 80/80 OK". Era falso su due livelli insieme. obs_ms // MS_LTF a un'osservazione alla chiusura del bin cadeva nel bin successivo, ancora vuoto → aggregato vuoto → signal_at ritornava None → segnale 0. E il check campionava bin a caso: gli ingressi sono ~2% dei bin, quindi confrontava zeri con zeri e passava comunque. Le uniche 2 divergenze su ETH erano gli unici 2 bin con un segnale vero — cioe' il campione stava gia' dicendo che era rotto al 100%, non al 2.5%.

Fix: ((obs_ms - 1) // MS_LTF) * MS_LTF, e selfcheck riscritta per testare esplicitamente i bin CON ingresso. Esito corretto: 120/120 su BTC, 120/120 su ETH. I "falsi allarmi" sui bin flat (17 BTC / 22 ETH su 400) sono bin dove il segnale c'e' ma il backtest lo sopprime col cap max_per_day=1 — atteso, non un difetto.

Regola: un self-check su eventi rari va campionato sugli eventi, non sulla popolazione. Un check che confronta zeri con zeri ha potenza zero e sembra un successo.

(b) Sovrastima ~20× dei falsi ingressi. La prima scansione contava 1361 falsi ingressi (204% in piu' dei trade veri, costo stimato 3.03%/anno di sleeve). Numero sbagliato: signal_at riporta il compositore grezzo, mentre il live applica anche il cap max_per_day=1 e il non-overlap. La spia era nella sezione D della stessa stampa — 305 giorni con un falso ingresso a fronte di 663 "eventi": con cap 1/giorno non possono essere eventi indipendenti. Riscritta come macchina a stati sequenziale fedele al live: i falsi ingressi veri sono ~5/anno/asset.

Regola: un conteggio di eventi su un segnale grezzo non e' un conteggio di trade. Prima di monetizzare un evento, farlo passare per gli stessi filtri che ha il live.


2. Il risultato

Due path identici in tutto (stessi livelli SKH01_V2_DD pct-asimmetrici, stesse uscite intra-barra, stesso cap, stesse fee 0.10% RT) tranne quando si valuta l'ingresso:

  • LIVE — segnale valutato a ogni confine orario interno al bin (= cio' che fa il cron oggi);
  • BACKTEST — segnale valutato solo alle chiusure dei bin (= cio' che il backtest assume).
asset offset path equity× trade falsi Sharpe
BTC 0 LIVE 6.58 249 29 1.07
BTC 0 BACKTEST 6.28 211 0 1.08
ETH 0 LIVE 6.09 285 39 0.95
ETH 0 BACKTEST 5.44 236 0 0.91
BTC 230 LIVE 27.10 254 20 1.63
BTC 230 BACKTEST 8.32 226 0 1.19
ETH 230 LIVE 11.47 283 34 1.20
ETH 230 BACKTEST 5.08 241 0 0.88
BTC 460 LIVE 17.53 258 18 1.44
BTC 460 BACKTEST 4.29 236 0 0.85
ETH 460 LIVE 72.87 281 17 1.93
ETH 460 BACKTEST 6.12 253 0 0.95

ΔSharpe (live backtest): 0.01, +0.04, +0.44, +0.32, +0.59, +0.98 → 6/6 non negativi, mediana +0.38.

⚠️ I multipli d'equity NON sono ritorni dello sleeve. Questo simulatore compone per-trade senza vol-target, senza pesi di book, a nozionale unitario. Servono solo a confrontare due path che differiscono per una cosa sola. La lente onesta qui e' lo Sharpe (che non compone), e i multipli sono la sua integrazione su 7 anni.

Split in-sample / hold-out (offset 0, dove ho le serie):

asset path FULL IS HOLD
BTC LIVE 1.07 1.07 1.12
BTC BACKTEST 1.08 1.15 0.71
ETH LIVE 0.95 0.93 1.03
ETH BACKTEST 0.91 0.88 1.03

All'offset 0 il FULL e' un pareggio ma l'hold-out favorisce il live su BTC (+0.41) e pareggia su ETH. Coerente col fatto noto che offset 0 e' l'ancora fortunata del backtest (93-98° pctl sui 23 offset a priori): e' esattamente l'ancora dove il path canonico ha meno da guadagnare.


2-bis. I due controlli che il risultato doveva superare

Un +0.98 di Sharpe e un 72.87× di equity sono il tipo di numero che va attaccato prima di crederci.

(a) E' concentrato in pochi giorni? No — e il controllo va nella direzione opposta al sospetto:

offset 460 ret/trade win rate top-5 gg = % del log-equity equity senza i top-5
ETH LIVE +1.878% 48.6% 16.7% 35.64×
ETH BACKTEST +0.946% 40.6% 39.5% 2.99×
BTC LIVE +1.307% 46.1% 22.5% 9.20×
BTC BACKTEST +0.801% 44.0% 38.3% 2.46×

Togliendo i 5 giorni migliori il divario si allarga (ETH 35.6× vs 3.0×). E' il backtest il path concentrato (~39% del log-equity in 5 giorni). La differenza vive nella distribuzione: ret/trade circa doppio e win rate +8pp (ETH) / +2pp (BTC).

(b) C'e' look-ahead intra-bin? E' il rischio serio, perche' il self-check valida la ricostruzione solo a chiusura di bin — un leak che esistesse solo intra-bin gli sarebbe invisibile per costruzione. Test decisivo: ricalcolare ogni osservazione intra-bin con la serie 5m troncata alle sole barre gia' chiuse a obs_ms. Se il futuro contasse, la risposta cambierebbe.

BTC 145/145 e ETH 144/144 osservazioni intra-bin: risposta identica dopo il troncamento, e il prezzo d'ingresso coincide sempre con l'ultimo close 5m gia' chiuso (241/241).

Cablato come test permanente (test_nessun_lookahead_intra_bin).


3. Il meccanismo (perche' vince, e perche' non e' una sorpresa)

Sezione B della scansione: quando il segnale c'e' anche a fine bin, il live entra in anticipo di 180 minuti mediani a un prezzo 0.25-0.26% migliore in media (0.11-0.12% mediano).

SKH01 e' un Donchian breakout. Aspettare fino a 230 minuti la chiusura del bin significa, sui casi che confermano, pagare il pezzo di movimento gia' avvenuto. Il costo di quell'attesa e' sistematico; il beneficio (evitare i breakout che evaporano) e' reale ma raro — ~5 eventi/anno/asset dopo i filtri del live, perche' il cap max_per_day=1 e il non-overlap assorbono quasi tutto.

E l'effetto si amplifica sui livelli, che sono percentuali sull'ingresso (long sl4%/tp10%, short sl2%/tp8%). Entrare 0.26% piu' avanti nella direzione del breakout sposta TP e SL dello stesso 0.26% — ma il TP e' a 4-10% e lo SL a 2-4%: la stessa quantita' assoluta vale il 6-13% della distanza dallo SL contro il 2.6-3.3% della distanza dal TP. Il vantaggio d'ingresso e' quindi asimmetrico a favore della sopravvivenza del trade: e' il canale che spiega il win rate piu' alto, non un giorno fortunato.

La cannibalizzazione del cap non morde: ingressi veri bloccati da un falso ingresso = 2 su BTC (0.6%) e 3 su ETH (0.9%).


4. Verdetto

L'ingresso su barra parziale NON e' un difetto da correggere. Il verso del follow-up e': lasciarlo.

Ma la lettura che conta e' la seconda:

Il live e il backtest stanno girando due strategie diverse, e la differenza non e' neutra.

Tutti i numeri di SKH01 nel progetto — Sharpe standalone, il peso 25% del book Deribit, l'audit d'ancora del 02/07, la conferma di peso/cadenza del 24/07 — sono calcolati sul path a chiusura di bin, che non e' quello che gira. La misura dice che il path reale e' in 6/6 coppie asset×offset. Insieme alla misura di stamattina sulle uscite (il live esce gia' intra-barra, +0.081 Sharpe FULL di book sottostimato), il path live di SKH01 e' stato modellato in modo sistematicamente pessimistico su entrambi i lati.

Cosa NON concludo. Che "l'ingresso intra-bin e' un miglioramento validato". Non ha passato nessuno dei gate del progetto: e' stato misurato sugli stessi 7 anni su cui SKH01 e' stato selezionato e affinato, non e' passato per study_family_honest ne' per un deflated-Sharpe, e la taglia varia molto fra ancore (da 0.01 a +0.98). Promuoverlo a meccanismo canonico sarebbe esattamente la selezione-sull'hold-out che il progetto ha gia' codificato come gate.

E non serve promuoverlo: e' gia' cio' che il live fa. L'azione richiesta e' l'opposta — smettere di trattare il numero del backtest come l'aspettativa del live, e non "riparare" il live per farlo somigliare a un backtest peggiore.

Nessun cambio a book, pesi, cron, config.


5. Regole nuove

  1. Un self-check su eventi rari si campiona sugli EVENTI. Confrontare zeri con zeri ha potenza zero e passa. (Costo: un "80/80 OK" completamente falso.)
  2. Un conteggio di eventi su segnale grezzo non e' un conteggio di trade. I filtri del live (cap giornaliero, non-overlap) vanno applicati prima di monetizzare qualsiasi evento. (Costo: sovrastima 20× e un costo inventato di 3%/anno di sleeve.)
  3. Quando live e backtest differiscono, misurare il DELTA con machinery identica — un solo grado di liberta' cambiato — e quotarlo sulla banda d'ancora, non su un'ancora sola. All'ancora canonica questo effetto vale ~0; sulla banda vale +0.38 mediano. Su un'ancora sola avrei concluso "irrilevante".