Un Donchian a 20 giorni sembra innocuo in una spec. L'agente scrive un massimo mobile a 20 barre, il backtest parte dalla prima riga del file parquet, e per le prime due settimane il "massimo a 20 giorni" è solo il massimo corrente delle barre che esistono. Al giorno quattro è un massimo a quattro giorni. La strategia che pensavi di testare non è quella che ha prodotto la prima dozzina di fill.
Ho un notebook su barre daily di ETHUSDT in cui lo Sharpe sull'intero campione è 1.4. Taglio le prime 20 sessioni e scende a 0.6. Tengo quelle 20 e scarto il resto del primo anno, e stampa 3.1. Nessuno ha leakato il domani. La strategia ha usato il passato, solo non abbastanza, e il report ha trattato quei trade a metà come evidenza.
Far operare la finestra mentre si sta ancora riempiendo
Il disastro abituale è min_periods=1. Pandas calcola una media mobile su una singola barra se glielo permetti. Gli agenti lo fanno in continuazione, perché un NaN in cima al frame sembra un bug, e riempirlo fa diventare verde lo unit test.
Un target di realized-vol a 20 giorni con due osservazioni di rendimento è un'esplosione di size. La varianza di due numeri è un lancio di moneta, la inverti, e la prima posizione è diverse volte il rischio previsto. Uno z-score contro una deviazione standard vicina a zero fa lo stesso trucco con un segno: la strategia sembra avere un ingresso da rasoio che non si rivede più una volta che la finestra è onesta.
I breakout sono peggiori, perché sembrano la regola vera. Un canale a 20 barre sulla barra sei è un canale a sei barre. Ottieni un cluster di trade proprio all'inizio, spesso in un tratto quieto che non avrebbe innescato l'indicatore completo. I mercati quieti driftano un po'. Un canale stretto scatta. La curva di equity si prende un vantaggio di partenza che nessun anno successivo ripete.
Zero-fill e forward-fill inventano una bugia diversa. Un RSI a 0 si legge come ipervenduto. Un ATR mancante a 0 fa esplodere la size unitaria, e il backtest compra obbediente un magazzino. Preferisco che un NaN uccida l'ordine piuttosto che uno 0 ne inventi uno.
Mi scopro ancora a plottare dalla riga 0 perché un mese vuoto a sinistra del grafico sembra incompiuto. Il mese vuoto è la parte onesta.
Ritagliare la curva di equity, tenere la posizione
Questo sopravvive alla code review. Calcoli correttamente le feature a 20 giorni, togli le prime 20 righe dalla curva plottata e pubblichi dal 21 gennaio. La posizione del 21 gennaio era stata aperta il 14 gennaio. L'high-water del trailing stop, il conteggio della piramide, il cash dopo quei burn: tutto è finito nel campione "pulito".
Il disastro è una strategia paper che non si può avviare nella data del write-up. Riavvia da flat all'inizio dichiarato e gli ordini della prima settimana non coincidono. A volte il backtest è già in un trade che il sistema paper non ha motivo di aprire. A volte il sistema paper entra perché il suo lookback è freddo, e il backtest sta fuori perché il suo mese nascosto ha già preso il breakout. Due book di apertura, una sola data di inizio pubblicata.
I fold walk-forward lo fanno in silenzio. Ogni finestra di test ha una coda di lookback che non plotti. Se salti la simulazione di quella coda, i primi trade di test sono di nuovo trade con finestra incompiuta. Se la simuli e riporti solo i giorni di test, la posizione del giorno di test è condizionata a fill che non stai mostrando. Quella seconda versione può essere una scelta di ricerca legittima. Chiamare cold start la prima mattina del fold, mentre un trailing stop è già live dalla coda, è il modo in cui due ricercatori ottengono due Sharpe da una sola config.
Fare il warmup in giorni di calendario quando la feature non è un giorno
"Dagli 30 giorni" lascia la feature sotto-specificata. Trenta giorni di calendario su un Donchian a 5 minuti sono migliaia di barre oltre un lookback a 20 periodi. Trenta giorni su una feature daily che ha bisogno di 20 sessioni è o grasso o magro, a seconda di weekend e buchi.
Uno z-score sul funding rate di una delle nostre venue sui perp ha ricevuto un warmup di 30 giorni perché la spec diceva 30 periodi e qualcuno ha tradotto i periodi in calendario. Lì il funding stampa ogni otto ore. Trenta giorni sono circa 90 settlement. Trenta periodi sono dieci giorni. I due mesi extra di burn-in includevano per caso una settimana di depeg. Toglierla ha fatto sembrare la finestra live più calma della storia reale della strategia. La gente ha incolpato la sensibilità alla data di inizio. Il warmup si era mangiato il regime.
E crypto contro equity fa cambiare significato allo stesso numero senza che nessuno modifichi un parametro. Venti "giorni" di ETH includono i sabati. Venti sessioni equity sono quasi un mese di calendario. Copi un lookback a 20 giorni da un notebook su azioni sulle candele perpetual orarie e hai un canale a 20 ore con un nome da 20 giorni. La prima barra valida è allora o 20 ore dopo, o 20 giorni dopo se qualche funzione successiva fa il resample, e ho visto entrambi nello stesso diff dell'agente.
Fissare il primo timestamp negoziabile
Il warmup è un requisito sui dati, non un campione bonus. Ogni feature indica il numero di osservazioni complete di cui ha bisogno, nelle unità in cui viene calcolata. Il primo timestamp negoziabile è la prima barra in cui tutte queste condizioni sono vere e un conto flat sarebbe stato autorizzato a inviare un ordine.
| Feature | Cosa dice di solito la spec | Cosa deve esistere davvero | Sostituto silenzioso |
|---|---|---|---|
| Donchian a 20 giorni | 20 massimi daily | 20 sessioni complete | Massimo corrente con min_periods=1 |
| realized vol a 30 giorni | finestra a 30 giorni | 30 rendimenti close-to-close | Varianza a due giorni, invertita in size |
| z-score sul funding a 20 print | 20 giorni | 20 settlement di funding | 20 giorni di calendario (~90 print), o 20 barre del timeframe sbagliato |
| RSI a 14 periodi su 5m | 14 periodi | 14 barre da cinque minuti chiuse | 14 giorni, o 14 barre con gap in forward-fill |
Il P&L prima di quel timestamp resta fuori dal track record. Lo stato precedente a quel timestamp potrebbe comunque dover essere simulato, così un trailing stop o un cooldown è reale quando l'orologio arriva alla prima barra negoziabile, ma quei fill non finiscono nello Sharpe, nel conteggio dei trade o nella matematica della capacity. Poi fai il controllo brutto: riavvia da flat a quel timestamp, con il lookback disponibile solo come dati. Se gli ordini cambiano, stavi spedendo trade nascosti.
Il paper trading parte sullo stesso contratto. Così anche ogni finestra di test walk-forward. Se il grafico sembra mancare un mese, lascialo mancare.
← Tutti gli articoli


