Un test di backtesting utile non serve a trovare un parametro migliore: arresta il processo a metà, ripristinalo e completa lo stesso replay. A parità di input e con un simulatore di esecuzione controllato, decisioni, ordini ed equity dovrebbero coincidere con quelli di un'esecuzione senza interruzioni.
Se non coincidono, hai trovato un problema di gestione dello stato. La strategia dipende da qualcosa che non hai salvato o che non sei riuscito a ricostruire. Questa dipendenza conta quando si riprendono le esecuzioni di ricerca, si sostituiscono i worker o si distribuisce nuovo codice su un servizio di paper trading.
Mi piace questo test perché la risposta attesa è insolitamente chiara. Non c'è da discutere se il mercato sia cambiato: entrambe le esecuzioni ricevono lo stesso mercato.
Ecco tre modi sbagliati di riavviare. I numeri sono esemplificativi; ciascun problema può verificarsi anche in un sistema altrimenti deterministico.
1. Ricaricare poche barre e considerare gli indicatori pronti
Supponiamo che una strategia usi una media mobile esponenziale a 100 periodi. Il suo aggiornamento è:
alpha = 2 / 101
ema_next = alpha * close + (1 - alpha) * ema_previous
Il processo senza interruzioni porta avanti il valore accumulato dell'EMA. Il processo riavviato recupera 100 barre, inizializza l'EMA usando la prima chiusura e presume che un indicatore a 100 periodi richieda 100 osservazioni.
Questa ipotesi confonde il parametro di smoothing dell'indicatore con una finestra di memoria finita. Un'EMA conserva un contributo via via minore del suo stato iniziale. Se due versioni partono con una differenza di 10 unità di prezzo nell'EMA, prezzi successivi identici riducono tale differenza come segue:
| Aggiornamenti dall'inizializzazione | Differenza residua | Frazione dell'errore iniziale |
|---|---|---|
| 100 | 1.353 | 13.53% |
| 250 | 0.0674 | 0.674% |
| 500 | 0.000454 | 0.00454% |
Il calcolo è 10 * (99 / 101)^k. Recuperare 100 barre fornisce solo 99 aggiornamenti se la prima osservazione viene usata come valore iniziale.
Il problema di solito emerge in prossimità di una soglia decisionale. Un'esecuzione rileva un prezzo sopra l'EMA, l'altra sotto. Una piccola differenza numerica genera un'operazione in più. Da quel momento possono divergere anche i periodi di attesa, il capitale disponibile e le decisioni successive.
Salva lo stato ricorsivo dell'indicatore, il suo stato di inizializzazione e l'ultimo evento elaborato. In alternativa, ripeti il replay da uno stato iniziale noto. Un warm-up più lungo può fornire un'approssimazione accettabile, ma scegli la durata in base a una tolleranza d'errore esplicita e verifica se tale tolleranza può cambiare le decisioni. “Cinque volte il periodo” è una convenzione, non una dimostrazione.
E poi gli indicatori non sono tutto lo storico. Un percentile mobile richiede la sua finestra. Un modello online può richiedere lo stato dell'ottimizzatore. Una regola che attende 3 barre dopo una perdita deve ricordarsi la perdita e il contatore.
2. Salvare le posizioni e dimenticare gli ordini in corso
La posizione obiettivo è di 10 unità. Un ordine d'acquisto per 10 ne ha eseguite 4 e ne lascia 6 in sospeso. Salvi nel checkpoint la posizione come 4, riavvii e invii un altro ordine d'acquisto per le 6 mancanti.
Se vengono eseguiti sia il quantitativo residuo dell'ordine originale sia quello del nuovo ordine, ti ritrovi con 16 unità.
Nel backtesting questo bug spesso resta nascosto perché il riavvio del motore di esecuzione cancella silenziosamente gli ordini attivi. Nel paper trading, il simulatore o il servizio esterno potrebbe conservarli. Lo stesso codice di recupero produce quindi un'esposizione diversa a seconda di quale componente è sopravvissuto.
| Al riavvio | Stato effettivo | Cosa rileva il recupero basato solo sulla posizione |
|---|---|---|
| Posizione obiettivo | 10 | 10 |
| Posizione eseguita | 4 | 4 |
| Quantità d'acquisto in sospeso | 6 | 0 |
| Quantità aggiuntiva necessaria | 0 | 6 |
Il problema si manifesta con un'ondata inspiegabile di ordini subito dopo il recupero. A volte l'esposizione raddoppia. Altre volte si chiude una posizione mentre il suo ordine di protezione è ancora attivo, con il rischio che quell'ordine apra in seguito una nuova posizione.
Un checkpoint deve includere l'identità e lo stato del ciclo di vita degli ordini, oltre alle posizioni. Prima di generare nuove azioni, il recupero deve riconciliare quei dati con il sistema di esecuzione. Un ordine dall'esito sconosciuto va verificato: trattare “nessuna conferma salvata” come “mai inviato” è il modo in cui nascono gli ordini duplicati.
Gli identificativi cliente stabili degli ordini aiutano a verificare cosa è successo. Impediscono i duplicati solo se il sistema che li riceve applica davvero le regole di unicità o idempotenza richieste. Salva anche gli identificativi delle esecuzioni già elaborate, così un fill riprodotto nel replay non incrementa la posizione due volte.
Ho un debole per la noiosa schermata con lo stato degli ordini. Il giorno del riavvio, le sue piccole righe diventano all'improvviso l'interfaccia più interessante dell'edificio.
3. Ripristinare la posizione e azzerare il registro P&L
Consideriamo un esempio spot senza leva e senza commissioni. Parti con $10,000 di liquidità, acquisti 10 unità a $100 e crei un checkpoint quando il prezzo di riferimento raggiunge $110.
Lo stato corretto è $9,000 di liquidità più una posizione del valore di $1,100: equity pari a $10,100. Se il recupero ripristina le 10 unità ma azzera la liquidità riportandola ai $10,000 iniziali, registra $11,100. Hai creato $1,000 riavviando un processo.
Altre varianti sono meno eclatanti. Il recupero mantiene intatta l'equity ma reimposta il prezzo di ingresso a $110. L'equity totale può restare corretta mentre cambia l'attribuzione tra profitti realizzati e non realizzati. Se uno stop o una condizione di uscita dipende dal prezzo di ingresso, questa scorciatoia contabile modifica il comportamento di trading.
Oppure il sistema dimentica il precedente massimo dell'equity. Supponiamo che l'equity abbia raggiunto un picco di $10,600 prima di scendere a $10,100. Il drawdown è circa del 4.72%. Se al recupero si azzera il massimo storico, la strategia crede improvvisamente che il drawdown sia zero. Qualsiasi controllo del rischio basato sul drawdown è stato appena azzerato senza autorizzazione.
Il problema può quindi manifestarsi come un salto nell'equity, un drawdown migliorato in modo sospetto o una regola di rischio che smette di attivarsi dopo i rilasci. Conserva il registro contabile e lo stato della strategia che ne dipende: movimenti di liquidità, posizioni, costo di carico applicabile, oneri maturati e memoria dei controlli di rischio. Riconcilia l'equity ripristinata con il registro usando lo stesso timestamp di valutazione.
Un checkpoint richiede un punto di consistenza. Salvare la liquidità dopo un fill e la quantità della posizione prima di quel fill produce uno stato che non è mai esistito. Registra insieme gli stati correlati oppure conserva una sequenza durevole di eventi da cui ricostruirli. Salva con quello stato anche il cursore degli eventi, così il recupero non salta il fill e non lo applica due volte.
Nel sistema di ricerca terrei un test che esegue un replay di riferimento senza interruzioni e poi riavvia una seconda esecuzione in momenti volutamente scomodi: durante l'inizializzazione degli indicatori, dopo un fill parziale e mentre è attivo un limite di rischio. Usa lo stesso ordine degli eventi e conserva lo stato casuale del simulatore. Confronta la prima decisione dopo il recupero, i registri degli ordini e dei fill e il percorso dell'equity. Un saldo finale uguale può nascondere errori che si compensano.
Per un arresto anomalo dopo l'invio ma prima della conferma, il test deve anche preservare separatamente lo stato del servizio di esecuzione da quello del processo della strategia. Altrimenti cancella proprio l'incertezza che stai cercando di testare.
La specifica di una strategia comprende ciò che ricorda. Rendi esplicita quella memoria a sufficienza da poter terminare il processo a metà di un replay e mostrare esattamente come riprende il lavoro.
← Tutti gli articoli


