Backtest di una Strategia: Overfitting, Look-Ahead Bias e Altri Modi per Ingannarsi
Chiunque abbia provato a costruire una strategia di trading, un modello di previsione o anche solo una regola di business basata su dati storici si è trovato davanti allo stesso momento: il backtest dice che funziona. Numeri belli, curva in salita, poche perdite. Poi si prova in produzione e non funziona.
La domanda interessante non è "perché non funziona", ma "perché non me ne sono accorto prima". Il backtest non è una simulazione della realtà: è una simulazione della realtà vista attraverso i dati che ho scelto io, con le decisioni che ho preso io, guardando quei dati. È uno strumento potentissimo e contemporaneamente un generatore automatico di illusioni.
In questo articolo provo a mettere in fila i modi più comuni in cui un backtest mente, e qualche pratica concreta per renderlo meno bugiardo. Gli esempi numerici sono inventati: servono a fissare le idee, non a rappresentare un caso reale.
Cos'è davvero un backtest
Un backtest prende una regola del tipo "compra quando succede X, vendi quando succede Y", la applica a una serie storica di prezzi (o di vendite, o di click, o di qualsiasi altra variabile) e calcola cosa sarebbe successo. Sembra lineare.
Il problema è che tra la regola e il risultato c'è una catena di decisioni umane:
- quali dati ho usato;
- da quando a quando;
- quali parametri ho scelto (soglie, finestre, indicatori);
- come ho trattato costi, commissioni, timing;
- come ho deciso quando il test era "abbastanza buono".
Ognuno di questi punti è un'opportunità per introdurre un bias. E il bias più insidioso è quello che non si vede: il fatto stesso di aver guardato i dati prima di decidere la regola.
Look-ahead bias: usare il futuro senza accorgersene
Il look-ahead bias è l'errore più semplice da descrivere e il più difficile da evitare davvero. Consiste nell'usare, in un certo istante della simulazione, un'informazione che in quell'istante non sarebbe stata disponibile.
Esempi tipici:
- usare il prezzo di chiusura di oggi per decidere se comprare all'apertura di oggi (il prezzo di chiusura lo conosci solo dopo la chiusura);
- usare un dato di bilancio trimestrale nel giorno in cui si riferisce, invece del giorno in cui è stato pubblicato (che può essere settimane dopo);
- riempire i valori mancanti con la media dell'intero periodo, che include il futuro;
- normalizzare le feature di un dataset prima di splittarlo in train e test: la media e la deviazione standard calcolate su tutto il dataset contengono informazione dal test set.
L'ultimo punto è il più subdolo perché è innocente: sembra solo una fase di pulizia dati. Ma se la scala delle feature è stata calcolata includendo il futuro, il modello ha già assaggiato il futuro.
Un esempio concreto. Supponiamo di voler normalizzare una feature con lo z-score:
# SBAGLIATO: media e std calcolate su tutto il dataset
mu = df['feature'].mean()
sigma = df['feature'].std()
df['feature_norm'] = (df['feature'] - mu) / sigma
# poi split train/test
train = df[df.index < split_date]
test = df[df.index >= split_date]
Anche se il modello vede solo train, la colonna feature_norm è stata costruita usando statistiche che includono test. La correzione è calcolare le statistiche solo sul train e applicarle al test:
mu = train['feature'].mean()
sigma = train['feature'].std()
train['feature_norm'] = (train['feature'] - mu) / sigma
test['feature_norm'] = (test['feature'] - mu) / sigma
Piccola modifica, differenza enorme nella credibilità del risultato.
Overfitting: il backtest come specchio del progettista
L'overfitting è quando una strategia si adatta al rumore specifico del periodo storico che ho guardato, invece che a un pattern che si ripete. In finanza quantitativa è il peccato originale, ma vale anche per previsioni di domanda, pricing, churn.
Il meccanismo è semplice: ogni volta che aggiungo un parametro libero, aggiungo gradi di libertà per far combaciare la curva storica. Con abbastanza parametri si può fittare quasi qualsiasi serie.
Un esempio numerico. Immagino una serie di rendimenti giornalieri plausibile. Se testo 100 regole diverse (medie mobili, breakout, mean reversion, combinazioni) e prendo quella con lo Sharpe migliore sul periodo storico, il risultato sarà ottimo anche se tutte le 100 regole fossero rumore puro. Con abbastanza tentativi, il massimo di una collezione di numeri casuali è grande. È statistica di base, non finanza.
Questo si chiama selection bias o data snooping. È difficile da quantificare, ma è il motivo per cui "ho trovato una strategia con Sharpe 3" va tradotto in "ho testato N cose e ho scelto la migliore".
Alcune pratiche per ridurlo:
- Fissare le regole prima di guardare i risultati: definire parametri e criteri di valutazione su un periodo di sviluppo, poi validare altrove.
- Contare i tentativi: se ho testato 50 varianti, il mio riferimento statistico non è più lo Sharpe medio, ma il massimo di 50 prove casuali.
- Preferire modelli semplici: una regola con 3 parametri è più difficile da fittare rumorosamente di una con 30.
- Sospettare le prestazioni troppo belle: drawdown bassi e win rate altissimi sono quasi sempre il segnale di qualcosa che non va nei dati o nella simulazione.
Costi, slippage e la realtà che non entra nel backtest
Un backtest che ignora i costi è un backtest che mostra rendimenti lordi. Nella pratica:
- ogni operazione ha una commissione;
- il prezzo a cui si entra non è quello visto sul grafico, è quello che il mercato ti dà (slippage);
- c'è una differenza tra bid e ask;
- se la strategia opera su strumenti poco liquidi, l'impatto di mercato può essere rilevante;
- su scala piccola questi costi sembrano dettagli, su molte operazioni diventano il fattore principale.
Un esempio inventato: una strategia che opera 250 volte l'anno, con un rendimento lordo annuo del 12% e un costo per operazione dello 0,05%, paga circa il 12,5% annuo di costi (250 × 0,05%). Il rendimento netto diventa negativo. Oppure, in versione più realistica: una strategia che opera 50 volte l'anno con rendimento lordo dell'8% e costo per operazione dello 0,1% paga il 5% di costi, lasciando il 3% netto. Le differenze tra un backtest senza costi e uno con costi ragionevoli possono trasformare una strategia da "ottima" a "non pervenuta".
Aggiungere i costi al backtest non è un dettaglio tecnico: è la differenza tra una stima e una fantasia.
Out-of-sample e walk-forward: validare su dati mai visti
La pratica più sana è dividere il passato in tre porzioni, non due:
| Blocco | Uso | Cosa ci si aspetta |
|---|---|---|
| Train / sviluppo | Progettare regole e stimare parametri | Prestazioni gonfiate, non fidarsi |
| Validation | Scegliere tra poche alternative | Prestazioni realistiche ma ottimistiche |
| Test / hold-out | Verifica finale, toccata una volta sola | Prestazioni oneste, se non si è sbirciato |
Il pezzo critico è il hold-out. Se lo si guarda più volte per decidere se una variante è meglio dell'altra, smette di essere out-of-sample e diventa validation. Il modo per non barare è usarlo una volta sola, alla fine, e accettare il risultato.
Il walk-forward è una versione più raffinata: si allena su una finestra iniziale, si testa sulla finestra successiva, si sposta tutto avanti di un passo, si ripete. In codice, l'idea è:
for i in range(n_finestre):
train = dati[i*window : i*window + window]
test = dati[i*window + window : i*window + 2*window]
modello = allena(train)
risultati.append(valuta(modello, test))
Ogni blocco di test è out-of-sample rispetto al proprio train. È più vicino a come si userebbe la strategia nella realtà, ed è molto più severo di un singolo split.
Un limite importante: il walk-forward assume che il passato sia in una certa misura rappresentativo del futuro. In finanza questa assunzione è debole. Un regime di tassi a zero e un regime di tassi al 5% sono mondi diversi, e un backtest che li mescola può raccontare una storia che non esiste più.
Le metriche che contano davvero
Il rendimento medio non basta. Un backtest serio guarda almeno a:
- rendimento netto, non lordo;
- volatilità e quindi Sharpe ratio, per capire quanto rendimento si paga con quanto rischio;
- massimo drawdown, perché è quello che si sente emotivamente e che spesso fa abbandonare la strategia;
- numero di operazioni, perché con 12 operazioni in 3 anni le statistiche valgono poco;
- distribuzione dei rendimenti, non solo la media;
- stabilità nel tempo: la strategia funziona in tutti gli anni o solo in uno?
Uno Sharpe ratio di 1 su un periodo di 20 anni e 500 operazioni è una cosa. Uno Sharpe di 2 su 6 mesi e 15 operazioni è rumore raccontato bene. La regola pratica è che le metriche vanno lette insieme alla quantità di dati e al numero di tentativi fatti.
In pratica: una checklist minima
Quando costruisco un backtest personale (per curiosità, per studio, per capire un fenomeno), provo a passare da qui:
- Ho scritto la regola prima di guardare i risultati?
- Sto usando solo dati disponibili in quel momento?
- Ho normalizzato e pulito i dati usando statistiche solo dal train?
- Ho incluso costi e slippage plausibili?
- Ho separato train, validation e un hold-out che tocco una volta sola?
- So quante varianti ho provato in totale, o ho perso il conto?
- Le metriche che guardo hanno senso con il numero di osservazioni che ho?
- Il comportamento cambia drasticamente tra periodi diversi?
Se la risposta a più di una di queste domande è "non saprei", il backtest probabilmente è un racconto, non una misura.
Conclusione
Un backtest è uno strumento di falsificazione, non di conferma. Serve a cercare motivi per cui un'idea è sbagliata, non a trovare una scusa per fidarsi. I punti chiave:
- Il look-ahead bias è spesso invisibile e nasce da scelte apparentemente innocue, come normalizzare prima dello split.
- L'overfitting e il data snooping gonfiano i risultati ogni volta che si aggiungono parametri o tentativi.
- I costi di transazione trasformano strategie apparentemente buone in strategie mediocri o peggiori.
- La validazione out-of-sample con un hold-out toccato una volta sola è più utile di mille ottimizzazioni.
- Le metriche vanno lette insieme alla quantità di dati e al numero di tentativi fatti.
La finanza quantitativa non è l'arte di trovare strategie che funzionano nel passato, è l'arte di capire quali strategie hanno una chance di funzionare anche quando il passato non si ripete. Ed è per questo che i backtest più utili sono quelli che ci fanno cambiare idea, non quelli che ci danno ragione.
Foto di copertina di Anne Nygård su Unsplash.