Un backtest Python est une simulation de décisions avec les informations disponibles à leur instant, des règles de remplissage et un compte. Une courbe issue de signaux multipliés par des rendements ne suffit pas à prouver que ces opérations auraient été possibles. Commencez par quelques lignes dont vous pouvez expliquer chaque montant.

Séparer calcul, moteur et environnement

Conservez version de Python, dépendances, paramètres, calendrier et empreinte des données. pandas et NumPy servent au calcul ; Backtrader organise des événements et des ordres. vectorbt possède aussi une simulation de portefeuille, des règles d’état et des fonctions personnalisables : « vectorisé » ne signifie pas nécessairement opérations indépendantes. Les défauts de chaque moteur restent à lire et tester, sans classement universel de vitesse ou fidélité.

Travaillez d’abord hors connexion au compte. Un environnement reproductible ne rend pas une hypothèse profitable ; il permet de retrouver pourquoi deux résultats diffèrent. Un notebook interactif peut conserver des variables d’une exécution précédente : redémarrez et exécutez la séquence complète avant de figer un résultat.

Contrôler les données et leur identité

MetaTrader5 fournit via copy_rates_range les colonnes time, open, high, low, close, tick_volume, spread et real_volume. Les heures sont en UTC et l’histoire accessible dépend du terminal, notamment de sa limite de barres. Ces champs ne constituent pas un historique complet de commissions et financement. Une série Yahoo Finance ou d’une bourse via CCXT a son propre marché ; elle ne devient pas automatiquement un flux CFD de votre courtier.

Documentez unités, doublons, trous, révisions et fuseau. L’étiquette d’une barre H1 commençant à 10 h ne rend pas sa clôture disponible à 10 h : elle se termine à 11 h dans ce modèle. Lors d’un resampling, closed définit l’appartenance à l’intervalle et label son étiquette ; aucun des deux ne remplace une règle de disponibilité.

Même longueur, mauvais événement

Modèle source : prix indexés A 100, B 102, C 104 ; drapeaux indexés dans l’ordre C 1, A 0, B 0. Le produit par étiquette choisit C et donne A 0, B 0, C 104. En retirant les index puis multipliant les tableaux dans leur ordre physique, on obtient 100, 0, 0 ; réattribuer A/B/C désigne faussement A. Le drapeau n’est encore qu’un candidat, pas un ordre exécuté.

L’identité précède la position dans le tableau

L’identité précède la position dans le tableauPrix A100 B102 C104, drapeaux C1 A0 B0. Association par étiquette : C104. Association physique : A100 à tort.Prix : A 100 · B 102 · C 104Drapeaux : C 1 · A 0 · B 0Étiquettes → C 104Positions → A 100 : événement erronéNi signal ni produit ne prouvent un fill.
Jeu fictif de trois lignes, sans opération de marché. Retirer les index peut changer le sens du calcul.

Faites défiler horizontalement ou agrandissez le schéma pour lire les détails.

Passé autorisé ou futur procheDécision 10:04 UTC, observations reçues à 10:00 et 10:05.EXEMPLE DE CALCULBackward50Nearest60Backward, tolérance 2 minAbsent
Passé autorisé ou futur proche. Décision 10:04 UTC, observations reçues à 10:00 et 10:05.

Nearest peut choisir une information future.

Backward
50 – Quatre minutes avant.
Nearest
60 – Une minute après : interdit à cet instant.
Backward, tolérance 2 min
Absent – Ne pas combler avec le futur.

Empêcher le futur d’entrer par une jointure

À 10:04 UTC, une observation reçue à 10:00 vaut 50, celle de 10:05 vaut 60. Une jointure backward retient 50, âgé de quatre minutes ; nearest choisit 60 car une minute est plus proche, mais cette information est future. Avec tolérance de deux minutes et backward, il n’y a pas de correspondance. Ne remplacez pas l’absence par la prochaine valeur. Triez les clés comme demandé par pandas et distinguez publication initiale et valeur révisée : une direction correcte ne répare pas une mauvaise version historique.

Ajout de contrôle pour un export francophone : conservez séparément identifiant texte, heure UTC de disponibilité et séquence de réception. Deux événements reçus à la même seconde ne sont pas nécessairement interchangeables. Une virgule décimale destinée à l’affichage doit être interprétée selon un schéma explicite, sans transformation aveugle des séparateurs CSV.

Décaler le signal ne définit pas son exécution

Sur les vingt premières barres fictives, les plus hauts vont de 100 à 119, avec ouverture H−0,5, bas H−2 et clôture H−1. Barre 21 : O 120, H 121, L 118, C 120,5. Barre 22 : O 120,6, H 122, L 119, C 121. Le maximum des vingt barres précédentes vaut 119 à la barre 21 : 120,5 est supérieur. Inclure son propre plus haut 121 annulerait ce signal.

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

Le décalage place le candidat sur la barre 22, sans fixer prix, acceptation, quantité ou sortie. Dans le modèle standard documenté de Backtrader, un ordre marché décidé à la clôture peut être exécuté à l’ouverture suivante ; d’autres réglages changent le protocole. Si une barre OHLC touche stop et objectif, les quatre nombres seuls ne donnent pas leur ordre temporel.

Réconcilier un journal avant les statistiques

Modèle source en USD, quantité 10 000 EUR : achat Ask 1,1002 quand Bid vaut 1,1000, puis vente Bid 1,1012 quand Ask vaut 1,1014. Profit 10 USD ; commission 1 USD par côté, net 8 USD, financement et slippage supposés nuls. Retrancher encore les deux pips du spread d’entrée donnerait 6 USD et compterait deux fois ce coût. Plusieurs symboles partagent cash et marge : leurs courbes isolées ne s’additionnent pas nécessairement.

À risque monétaire R constant, 40 gains de 2 R et 60 pertes de 1 R donnent 20 R, moyenne 0,2 R et profit factor 80/60. Avec 0,1 R de coût par opération : gains nets 76 R, pertes 66 R, total 10 R, moyenne 0,1 R et facteur 76/66. Un taux de réussite de 75 % avec gains 0,2 R et pertes 1 R produit au contraire −10 R sur cent opérations, facteur 0,6.

Définir réentrée et sélection avant de regarder le score

Condition vraie, vraie, vraie, fausse, vraie : entrée barre 1, stop barre 2 avant évaluation de l’entrée, puis aucune sortie. « À plat et vrai » réentre barre 2. « Nouveau signal après réarmement par faux » attend la barre 4 et entre barre 5. Deux entrées dans chaque cas, mais pas aux mêmes instants. Il faut décrire cet état, pas le déduire d’un nom de bibliothèque.

Gardez capital initial, equity ouverte, transferts et période dans le journal. Enregistrez tous les essais de paramètres ; le meilleur parmi de nombreux essais n’est pas une validation indépendante. Réservez une période non utilisée pour sélectionner les règles, puis testez stabilité et coûts, sans seuil magique de Sharpe ni probabilité de surajustement inventée.

Livrable minimal vérifiable

  1. Figez données et règle de disponibilité, puis reproduisez les trois lignes indexées.
  2. Vérifiez une opération complète et les états de réentrée à la main.
  3. Exportez demandes, remplissages, coûts et equity, avec essais rejetés conservés.
  4. Passez à Walk-forward : fenêtres, labels disponibles et égalités pour séparer ajustement et évaluation ultérieure.