Abbiamo rieseguito un backtest salvato e ottenuto una curva azionaria diversa. Stesso codice della strategia, stesso intervallo di date, stesso simbolo. Il saldo finale differiva dell’1.8% e 3 operazioni si erano spostate di una barra.
Basta questo per rendere difficile fidarsi di un risultato di ricerca. Se un collega, una versione futura di te o un servizio di paper trading non riesce a riprodurre l’esecuzione, non puoi capire se una modifica ha migliorato la strategia o ha semplicemente cambiato l’esperimento. Ecco i passaggi che abbiamo seguito per individuare la divergenza.
Giorno 1: abbiamo definito cosa intendessimo per «la stessa esecuzione»
Il nostro primo errore è stato considerare il file della strategia come l’esperimento. Non era così. L’esecuzione dipendeva anche dai dati in ingresso, dalla versione del motore, dal calendario, dai metadati degli strumenti e dalle impostazioni di esecuzione. Il codice descriveva solo una parte del calcolo.
Prima di cambiare qualsiasi cosa, abbiamo creato un manifesto dell’esecuzione. Vi abbiamo registrato il commit della strategia, gli identificativi degli snapshot dei dati, l’intervallo di date, la venue, il piano commissionale, la fonte dei funding, il modello di esecuzione degli ordini e le versioni del software. Abbiamo salvato anche gli ordini e le esecuzioni risultanti, perché una curva azionaria da sola non mostra dove due esecuzioni hanno iniziato a divergere.
| Artefatto | Cosa registrare | Perché è importante |
|---|---|---|
| Dati di mercato | ID dello snapshot, versione dello schema, rettifiche | I fornitori correggono lo storico e rivedono le operazioni societarie |
| Esecuzione | Livello commissionale, serie dei funding, impostazioni di esecuzione e impatto | Le impostazioni predefinite e le ipotesi sul conto cambiano i risultati |
| Ambiente di esecuzione | Commit del codice, versioni del motore e delle dipendenze | Le librerie possono cambiare l’ordinamento, gli arrotondamenti o gli indicatori |
| Risultato | Ordini, esecuzioni, posizioni e metriche | Mostra dove le esecuzioni cominciano a divergere |
Giorno 2: abbiamo confrontato le operazioni, non lo Sharpe
Le metriche riepilogative erano una distrazione. Le due esecuzioni avevano uno Sharpe quasi identico, ma i log delle esecuzioni mostravano la prima discrepanza al regolamento dei funding. Un’esecuzione applicava il tasso alla posizione aperta al momento del regolamento; l’altra usava la posizione successiva al ribilanciamento di quel timestamp.
Il codice della strategia non era cambiato. Era cambiato l’ordinamento degli eventi nel motore. Un piccolo aggiornamento di versione aveva reso esplicita la sequenza, che prima dipendeva da come venivano ordinati casualmente 2 eventi.
Abbiamo aggiornato il contratto dell’esecuzione per specificare l’ordine: applicare il funding alla posizione mantenuta fino al regolamento, poi elaborare le decisioni della strategia per quel timestamp. La convenzione esatta può variare in base alla venue e al motore. Lasciarla implicita è l’errore.
Giorno 3: un file di dati «uguale» si è rivelato diverso
Dopo aver fissato l’ordine degli eventi, le discrepanze rimanenti si concentravano in alcune operazioni azionarie. Il fornitore aveva corretto una rettifica storica per uno split. Il nostro file aveva lo stesso nome e lo stesso numero di righe di prima, perciò sembrava invariato.
Ora calcoliamo l’impronta digitale di ogni snapshot immutabile dei dati e conserviamo insieme la relativa policy di rettifica. Un hash ci dice se i byte sono cambiati, ma non spiega il perché. Per questo il manifesto include anche la fonte, l’ora di acquisizione e la versione della trasformazione. Per i dati soggetti a revisione, questi dettagli fanno parte del risultato.
Un backtest riproducibile deve rispondere alla domanda: «quale versione del passato ha visto?»
Giorno 4: abbiamo trovato un’impostazione predefinita passata inosservata
L’ultima differenza era una commissione maker impostata a zero, perché la configurazione della strategia non specificava il campo. Un motore più recente aveva applicato la commissione predefinita del conto. Quella singola impostazione predefinita aveva cambiato le operazioni al margine quanto bastava per spiegare gran parte dello scarto nel saldo finale.
Abbiamo reso esplicite le impostazioni con rilevanza economica e configurato il motore affinché stampasse la configurazione risolta nel record dell’esecuzione. Le impostazioni predefinite sono comode durante l’esplorazione. Sono prove poco solide quando si confrontano risultati ottenuti in momenti diversi.
Cosa eviteremmo la prossima volta
Abbiamo passato mezza giornata a confrontare le metriche aggregate prima di guardare la prima esecuzione diversa. Non partire da lì. Ordina entrambi i log degli eventi per timestamp e confronta la prima divergenza: spesso le differenze successive derivano tutte da quella causa iniziale.
Eviteremmo anche di pensare che un’immagine container, da sola, renda riproducibile un’esecuzione. Fissa gran parte dell’ambiente software, ma non un file di dati esterno, un piano commissionale recuperato al momento dell’esecuzione o lo storico rivisto da un fornitore.
Quando cambia un backtest, conserva entrambi i manifesti e i log delle esecuzioni, poi correggi una fonte di divergenza alla volta. Il risultato utile non è solo una curva che puoi rieseguire. È un record che spiega quali dati e ipotesi l’hanno prodotta e perché l’esecuzione successiva potrebbe essere diversa.
← Tutti gli articoli


