Un backtest Python richiede una catena controllabile: dati, informazione disponibile in quell’istante, richieste, eseguiti e registro riconciliato. Conserva identificativi oltre ai timestamp. Un grafico veloce dell’equity non dimostra che il segnale ignorasse pubblicazioni successive o che il prezzo fosse eseguibile nel modello.

Scegli l’ambiente per la domanda di ricerca

Il tester MT5 supporta EA multivaluta, test e ottimizzazione: Python non è necessariamente la fuga da un limite di un solo cambio. Offre un altro modo di organizzare dati, calcoli personalizzati e ricerca. Confronta prodotto, contratto e modello di Esecuzione di un ordine; per indagare differenze fra implementazioni congela stessi dati e regole.

Conserva i dati e il loro significato

Registra strumento e prodotto, fornitore, lato della quotazione, fuso, campionamento e intervallo scaricato. Controlla duplicati, ordine e periodi mancanti. Una chiusura di mercato non è automaticamente un file corrotto; riempire un vuoto può inventare osservazioni. Salva originale e trasformazioni separati. Vedi Backtest: controllare lacune, duplicati e conflitti CSV.

copy_rates_range di MetaTrader5 restituisce time, OHLC, tick_volume, spread e real_volume, non una tariffa completa storica di commissioni e swap. Le barre dipendono da storia disponibile nel terminale e impostazioni; richiedere un intervallo non prova completezza. Argomenti temporali e dati restituiti usano UTC. Converti sessioni con fusi espliciti, senza assumere che Europe/Rome coincida sempre con un offset costante.

pandas e NumPy consentono calcoli; Backtrader offre un flusso a eventi. Anche vectorbt aggiorna stato monetario e delle attività, con modalità ordini, segnali e funzioni personalizzate. «Vettoriale» non significa esecuzioni indipendenti dallo stato precedente. Nessuna etichetta garantisce realismo o un tempo fisso. Scegli dipendenze necessarie, annota versioni, licenze, diritti sui dati e ambiente supportato: dati e distribuzione possono avere costi separati.

Togliere l’indice può spostare il segnale

Tre record fittizi completati, ordinati A = 100, B = 102, C = 104. Una Series di flag ha invece ordine C: 1, A: 0, B: 0. Uno indica soltanto un candidato da modellare, non un ordine o un prezzo eseguito.

Identificativo e posizione non sono la stessa chiave

Identificativo e posizione non sono la stessa chiavePrezzi A100 B102 C104; flag C1 A0 B0. La linea marcata C collega C al suo flag uno:104. Accoppiare invece le prime posizioni senza ID assegna uno ad A100. È un modello di assegnazione, non un profitto.Lunghezza uguale non bastaPrezzi per IDFlag riordinatiA · 100B · 102C · 104C · 1A · 0B · 0Con ID: C → 104Senza ID: prima riga A → 100Verifica anche quando il flag era disponibile.
La connessione C conserva l’identificativo. Le prime posizioni degli array non hanno lo stesso significato.

Scorri orizzontalmente o ingrandisci il diagramma per leggere i dettagli.

pandas allinea Series per etichetta: prices * flags dà A: 0, B: 0, C: 104. Convertire entrambe in array e moltiplicare per posizione produce 100, 0, 0. Riassegnarlo ad A, B, C rende A il candidato. Verifica ID prima di to_numpy(), non soltanto le lunghezze. Il corretto allineamento non risolve ancora la disponibilità temporale del segnale.

Quando il record diventa utilizzabile?

Una barra H1 etichettata con apertura 10:00 non ha OHLC definitivo alle 10:00: serve la fine del periodo. Nel resampling pandas closed decide appartenenza ai bordi e label il bordo visualizzato. Cambiare etichetta non anticipa la disponibilità dell’aggregato.

Unisci osservazioni macro per pubblicazione della versione allora disponibile, non solo per mese di riferimento. merge_asof richiede chiavi ordinate: backward cerca prima o allo stesso istante, nearest può trovare un record successivo. Nessuno conosce da solo le revisioni. Definisci tolleranza e ordine per eventi con lo stesso timestamp.

Test inventato: decisione 10:04 UTC; record 10:00 valore 50 e 10:05 valore 60. Senza tolleranza, backward seleziona 50, quattro minuti prima; nearest 60, uno dopo ma futuro. Tolleranza backward inclusiva di due minuti: nessuna corrispondenza. Non sostituire il dato assente col futuro soltanto perché più vicino.

Ricetta separata: prime venti barre con High da 100 a 119, Open = High −0.5, Low = High −2, Close = High −1. Barra 21 O120/H121/L118/C120.5; barra 22 O120.6/H122/L119/C121. Prezzi arbitrari, non serie forex reale.

previous_high = bars["high"].shift(1).rolling(20).max()
signal = bars["close"] > previous_high
next_bar_signal = signal.shift(1, fill_value=False)

Alla 21 il massimo delle venti barre precedenti è 119: 120.5> 119 vero. Includere High corrente rende soglia 121 e confronto falso. L’ultima riga colloca il segnale osservato nella 22: non determina fill, accettazione, uscita o quantità. Usa input completati e specifica eventi ed esecuzione separatamente. Il codice mantiene sintassi e punti decimali Python, anche nel testo italiano.

Segnale, fill e oneri separati

Nel modello standard documentato Backtrader, un Market richiesto dopo elaborazione della barra usa l’Open della prossima disponibile. Impostazioni o modelli diversi possono cambiare tempi. Se stop e target ricadono nello stesso intervallo OHLC, non conosci necessariamente quale sia stato osservato prima.

Modello originale: acquisto 10000 EUR su EUR/USD all’Ask 1.1002 con Bid 1.1000. Vendita successiva di tutto al Bid 1.1012 con Ask 1.1014. Pip 0.0001 USD per EUR: differenza dieci pip = 10 USD. Commissione 1 USD per lato → netto 8 USD; finanziamento e ulteriore slippage zero per ipotesi. Sottrarre altri due pip d’ingresso darebbe 6 USD, contando due volte uno scarto già presente nei fill.

Nuovo modello separato in EUR: quattro unità di un prodotto ipotetico quotato in EUR, acquisto eseguito 250 EUR ciascuna e vendita 252, senza cambio o finanziamento. Lordo 4 × 2 = 8 EUR, commissione 1,50 EUR per lato, netto 5 EUR. Gli eseguiti includono già i prezzi effettivi: sottrarre un altro spread fittizio di 1 EUR produce 4 EUR errati. Non è un preventivo o una specifica di un broker.

Per il prodotto reale definisci finanziamento, conversioni, contratto, margine e rifiuti. Con più strumenti modellizza cassa condivisa, margine e ordine di richieste simultanee: sommare curve indipendenti può includere ordini non finanziabili insieme. Uno slippage casuale richiede distribuzione, seed e versione.

Il registro rende verificabili le metriche

Altro modello con R monetario identico: quaranta +2 R e sessanta −1 R danno guadagni 80 R, perdite 60 R, netto 20 R, PF 80/60≈1,33, media 0,2 R. Costo 0,1 R su ogni trade: quaranta +1,9 R e sessanta −1,1 R → guadagni 76 R, perdite 66 R, netto 10 R, PF 76/66≈1,15, media 0,1 R. Non è un risultato osservato di backtest.

Controesempio di stato: su cinque barre condizioni vero, vero, vero, falso, vero. Entrambi i protocolli entrano nella 1; uno stop chiude nella 2 prima di valutare l’ingresso. Nessuna uscita successiva. Entrare ogni volta che sei flat e vero dà ingressi 1 e 2. Richiedere prima un nuovo falso per riarmare aspetta 2 e 3, si riarma nella 4 ed entra nella 5. Due ingressi ciascuno, tempi diversi. È un nostro protocollo, non una pretesa sui default delle librerie.

Conserva equity delle posizioni aperte e risultati chiusi. Per il Drawdown includi capitale iniziale e separa flussi. Non aggiungere rendimento o Sharpe non ricostruibili da registro e serie datati.

Nuovo registro EUR: fill e costi una volta solaQuattro unità inventate: 250→252 EUR; commissione 1,50 EUR per lato.ESEMPIO DI CALCOLOPrezzi eseguiti4 × (252−250) = 8 EURCommissioni1,50 + 1,50 = 3 EURRisultato netto5 EUR
Nuovo registro EUR: fill e costi una volta sola. Quattro unità inventate: 250→252 EUR; commissione 1,50 EUR per lato.

Netto 5 EUR: non sottrarre un altro spread già contenuto nei fill.

Prezzi eseguiti
4 × (252−250) = 8 EUR – Nessun cambio o finanziamento per ipotesi.
Commissioni
1,50 + 1,50 = 3 EUR – Esplicite e separate.
Risultato netto
5 EUR – Sottrarre ancora 1 EUR darebbe 4, doppio conteggio.

Selezione e dati intatti

Fissa finestre cronologiche di sviluppo e test prima di scegliere regole. Registra ogni strumento, filtro, combinazione e split tentati, anche scartati. Pochi parametri non significano poche ipotesi esplorate. La ricerca di Bailey e coautori studia sovraottimizzazione da selezione ripetuta; qui non stimiamo una probabilità PBO dai modelli fittizi.

Altro campione inventato: 75 vincite +0,2 R e 25 perdite −1 R danno 15 R contro 25 R, netto −10 R prima dei costi e PF 0,6, pur con 75% di successi. Una percentuale alta non diagnostica da sola bias; verifica causalità, contabilità, dipendenza, esecuzione e sensibilità dei parametri.

Prima prova offline

  1. Crea progetto isolato e conserva dati originali, identificativi, UTC, lato quotazione e versioni. Non servono credenziali live né ordini.
  2. Riproduci pochi record specificati: disponibilità del segnale, evento eseguibile, dato assente e revisione.
  3. Definisci stato: aggiunte, inversioni, rientro dopo stop o riarmo. Confronta gli identificativi attesi d’ingresso.
  4. Riconcilia fill e oneri, deriva risultati dal registro e ripeti con alternative d’esecuzione dichiarate.
  5. Salva tentativi, finestre intatte, limiti e versioni. Un calo fisso di performance non identifica da solo la causa. Prosegui con Walk-forward: finestre, gap e limiti della valutazione.