1 novembre 2026 · recherche

Comment faire le warmup d'un backtest sans compter le lookback comme de la performance ?

Comment faire le warmup d'un backtest sans compter le lookback comme de la performance ?

Un Donchian 20 jours a l'air inoffensif dans une spec. L'agent écrit un max glissant sur 20 barres, le backtest démarre à la première ligne du fichier parquet, et pendant les deux premières semaines le « plus haut 20 jours » n'est que le max courant des barres disponibles. Au jour quatre, c'est un plus haut de quatre jours. La stratégie que vous pensiez tester n'est pas celle qui a produit la première douzaine de fills.

J'ai un notebook sur les barres daily ETHUSDT où le Sharpe full-sample est de 1.4. On coupe les 20 premières séances et il tombe à 0.6. On garde ces 20 et on jette le reste de la première année, et ça affiche 3.1. Personne n'a leaké demain. La stratégie a utilisé le passé, simplement pas assez, et le rapport a traité ces trades à moitié formés comme des preuves.

1.4Sharpe full-sample, fenêtre inachevée incluse
0.6même code après 20 séances terminées
3.1Sharpe si on ne garde que les trades de burn-in

Laisser la fenêtre trader pendant qu'elle se remplit encore

Le carnage habituel, c'est min_periods=1. Pandas calculera une moyenne glissante sur une seule barre si on le laisse faire. Les agents le font en permanence, parce qu'un NaN en haut du frame a l'air d'un bug, et le remplir fait passer le test unitaire au vert.

Un target de vol réalisée 20 jours avec deux observations de rendement, c'est une explosion de taille. La variance de deux nombres, c'est un pile ou face, on l'inverse, et la première position fait plusieurs fois le risque visé. Un z-score contre un écart-type quasi nul fait le même tour avec un signe : la stratégie a l'air d'avoir une entrée au rasoir qui ne réapparaît plus une fois la fenêtre honnête.

Les breakouts sont pires, parce qu'ils ressemblent à la vraie règle. Un canal 20 barres à la barre six est un canal six barres. On obtient un cluster de trades dès le départ, souvent dans une phase calme qui n'aurait pas déclenché l'indicateur terminé. Les marchés calmes dérivent un peu. Un canal serré se déclenche. La courbe d'equity prend une avance qu'aucune année suivante ne répète.

Le zero-fill et le forward-fill inventent un autre mensonge. Un RSI à 0 se lit comme survendu. Un ATR manquant à 0 fait exploser la taille unitaire, et le backtest achète docilement un entrepôt. Je préfère qu'un NaN tue l'ordre plutôt qu'un 0 en invente un.

Je me surprends encore à tracer depuis la ligne 0 parce qu'un mois vide à gauche du graphique a l'air inachevé. Le mois vide, c'est la partie honnête.

Rogner la courbe d'equity, garder la position

Celle-ci survit à la revue de code. On calcule correctement les features 20 jours, on retire les 20 premières lignes de la courbe tracée, et on publie à partir du 21 janvier. La position du 21 janvier a été ouverte le 14 janvier. Le plus-haut du trailing stop, le compteur de pyramide, le cash après ces burns : tout ça s'est glissé dans l'échantillon « propre ».

Le carnage, c'est une stratégie paper qu'on ne peut pas démarrer à la date de l'article. Redémarrez à plat à la date de début déclarée et les ordres de la première semaine ne concordent pas. Parfois le backtest est déjà en trade alors que le système paper n'a aucune raison d'entrer. Parfois le système paper entre parce que son lookback est froid, et le backtest reste à l'écart parce que son mois caché a déjà pris le breakout. Deux carnets d'ouverture, une seule date de début publiée.

Les folds walk-forward font ça discrètement. Chaque fenêtre de test a une queue de lookback qu'on ne trace pas. Si on ne simule pas cette queue, les premiers trades de test sont à nouveau des trades de fenêtre inachevée. Si on la simule et qu'on ne présente que les jours de test, la position du jour de test est conditionnelle à des fills qu'on ne montre pas. Cette deuxième version peut être un choix de recherche légitime. Appeler le premier matin du fold un cold start, alors qu'un trailing stop est déjà live depuis la queue, voilà comment deux chercheurs tirent deux Sharpe d'une même config.

Si redémarrer à plat à la date de début publiée change le P&L, le warmup est dans le track record. Les données de lookback peuvent être présentes. Les trades de lookback, non.

Faire le warmup en jours calendaires quand la feature n'est pas un jour

« Donnez-lui 30 jours » laisse la feature sous-spécifiée. Trente jours calendaires sur un Donchian 5 minutes, c'est des milliers de barres au-delà d'un lookback de 20 périodes. Trente jours sur une feature daily qui a besoin de 20 séances, c'est trop gras ou trop maigre, selon les week-ends et les trous.

Un z-score de funding rate sur l'une de nos venues perp a reçu un warmup de 30 jours parce que la spec disait 30 périodes et que quelqu'un a traduit périodes en calendaire. Le funding s'y imprime toutes les huit heures. Trente jours, c'est environ 90 règlements. Trente périodes, c'est dix jours. Les deux mois de burn-in en trop incluaient par hasard une semaine de depeg. Les retirer a rendu la fenêtre live plus calme que la vraie histoire de la stratégie. On a mis ça sur le compte de la sensibilité à la date de début. Le warmup avait mangé le régime.

Et crypto versus actions, le même nombre change de sens sans que personne ne modifie un paramètre. Vingt « jours » d'ETH incluent les samedis. Vingt séances actions, c'est presque un mois calendaire. Copiez un lookback 20 jours d'un notebook actions sur des bougies perpetual horaires et vous avez un canal 20 heures avec un nom 20 jours. La première barre valide arrive alors soit 20 heures plus tard, soit 20 jours plus tard si une fonction plus loin resample, et j'ai vu les deux dans le même diff d'agent.

Figer le premier timestamp négociable

Le warmup est une exigence de données, pas un échantillon bonus. Chaque feature indique le nombre d'observations terminées dont elle a besoin, dans les unités où on la calcule. Le premier timestamp négociable est la première barre où tout cela est vrai et où un compte à plat aurait eu le droit d'envoyer un ordre.

FeatureCe que la spec dit d'habitudeCe qui doit réellement existerSubstitut silencieux
Donchian 20 jours20 plus-hauts daily20 séances terminéesMax courant avec min_periods=1
Vol réalisée 30 joursFenêtre 30 jours30 rendements close-to-closeVariance deux jours, inversée en taille
Z-score de funding 20 prints20 jours20 règlements de funding20 jours calendaires (~90 prints), ou 20 barres du mauvais timeframe
RSI 14 périodes en 5m14 périodes14 barres de cinq minutes clôturées14 jours, ou 14 barres avec trous en forward-fill

Le P&L avant ce timestamp reste hors du track record. L'état avant ce timestamp peut encore devoir être simulé, pour qu'un trailing stop ou un cooldown soit réel quand l'horloge atteint la première barre négociable, mais ces fills n'entrent ni dans le Sharpe, ni dans le nombre de trades, ni dans le calcul de capacité. Puis lancez le test moche : redémarrer à plat à ce timestamp, avec le lookback disponible uniquement comme données. Si les ordres changent, vous livriez des trades cachés.

Le paper trading démarre sur le même contrat. Chaque fenêtre de test walk-forward aussi. Si le graphique a l'air de manquer un mois, laissez-le manquer.

backtestingingénierie des donnéeswalk-forwardagents IApaper trading
← Tous les articles