26 Settembre 2026 · ricerca

Abbiamo provato a riprodurre il backtest di una strategia. Ecco dove i numeri hanno iniziato a divergere.

Abbiamo provato a riprodurre il backtest di una strategia. Ecco dove i numeri hanno iniziato a divergere.

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.

ArtefattoCosa registrarePerché è importante
Dati di mercatoID dello snapshot, versione dello schema, rettificheI fornitori correggono lo storico e rivedono le operazioni societarie
EsecuzioneLivello commissionale, serie dei funding, impostazioni di esecuzione e impattoLe impostazioni predefinite e le ipotesi sul conto cambiano i risultati
Ambiente di esecuzioneCommit del codice, versioni del motore e delle dipendenzeLe librerie possono cambiare l’ordinamento, gli arrotondamenti o gli indicatori
RisultatoOrdini, esecuzioni, posizioni e metricheMostra 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.

3fonti di divergenza individuate
1.8%differenza iniziale sul saldo finale
0valore del solo Sharpe corrispondente

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.

riproducibilitàbacktestingingegneria dei datipaper trading
← Tutti gli articoli