Deux backtests d’un même script Pine concordent rarement au centime près : dire qu’un moteur « colle à TradingView » ne veut rien dire tant qu’on n’a pas précisé ce qui est comparé et quel écart reste acceptable. Ce qu’est un backtest noté, comment ses trades sont appariés à ceux de TradingView, ce qu’exige chacun des cinq niveaux, et comment on juge une modification du code.
Beaucoup de backtesters affirment coller à TradingView. Mais deux backtests d’un même script Pine ne concordent presque jamais au centime près : tant qu’on ne sait pas ce qui a été comparé, ni quel écart on juge acceptable, l’affirmation ne veut pas dire grand-chose. Notre tableau de résultats attribue un mot, parmi cinq, à chacun des 7 989 backtests, et 7 905 d’entre eux portent la mention « excellent ». Ce billet explique ce que veulent dire ce mot et les quatre autres.
Un backtest, une liste de trades
L’unité, c’est la sonde : « une stratégie exportée de TradingView avec sa liste de trades, puis rejouée trade pour trade sur les mêmes barres » (README du codegen). Le script garde ses propres inputs et valeurs par défaut, et la notation compare deux listes de trades : celle de TradingView, et celle que PineForge produit sur les mêmes barres.
Un même script peut servir de sonde sur plusieurs marchés. Les 7 989 se répartissent entre 309 des 312 stratégies du corpus ouvert et 7 680 sondes tirées de 741 scripts TradingView, sur neuf marchés (crypto, futures et actions américaines, un indice indien, une paire de devises et l’or), chacun en barres de 15 minutes et en barres journalières (tableau de résultats).
Apparier les trades
Toute la notation tient dans un seul script public, verify_corpus.py. Il apparie chaque trade de TradingView au trade PineForge le plus proche qui n’a pas encore été apparié, dans la même direction, dont l’entrée tombe à une heure près de celle de TradingView et dont le prix d’entrée s’en écarte de 3,00 au plus, dans les unités de prix propres au marché (appariement, limites). On mesure ensuite deux choses : quelle part de la liste de TradingView a été reproduite, et à quel point les trades reproduits sont proches.
La première s’appelle la couverture, et elle se calcule sur l’ensemble des trades clôturés de TradingView, pas seulement sur la portion où les deux listes se chevauchent. Le code explique pourquoi : les autres métriques sont calculées dans une fenêtre que les appariements eux-mêmes définissent, « si bien que, sans ce garde-fou, une exécution qui ne reproduit presque rien peut décrocher la meilleure note sur le mince échantillon qu’elle a reproduit par hasard (observé en production : “excellent” avec 0,9 % de couverture réelle) » (script de notation). Quand la couverture est devenue éliminatoire, deux stratégies du corpus sont descendues en « moderate » : elles reproduisaient 209 trades de TradingView sur 224 et 228 sur 241, des écarts que l’ancienne fenêtre masquait.
Cinq mots
| Niveau | Trades de TradingView reproduits | Nombre de trades | Prix d’entrée, de sortie (p90) | P&L (p90) |
|---|---|---|---|---|
| excellent | ≥ 99 % | identique et, lorsque TradingView affiche deux ou plusieurs Signals d’entrée distincts au même instant exact, au même prix et dans la même direction, le moteur affiche autant d’entrées distinctes à cet endroit (identité des entrées distinctes) | à 0,01 % près | à 1 % près |
| strong | ≥ 95 % | à 6 % près | 0,1 %, 0,5 % | à 100 % près |
| moderate | ≥ 75 %, et ≥ 90 % dans la zone de chevauchement | |||
| weak | au moins un | |||
| minimal | aucun |
« p90 » signifie que neuf trades sur dix sont au moins aussi proches (seuils, échelle). Une liste qui laisse au plus un trade de TradingView sans appariement passe les seuils de couverture d’« excellent » et de « strong » : un trade au bord d’un export court ne peut donc pas coûter le niveau. Le niveau « excellent », lui, ne tolère aucune différence dans le nombre de trades. La raison qu’en donne le code : « des seuils en pourcentage peuvent masquer des dizaines de trades manquants ou en trop dans les grosses stratégies » (script de notation). Les stratégies dont les sorties utilisent un trailing stop sont notées avec des seuils plus souples, sorties à 0,05 % près et P&L à 100 % près, parce que l’endroit où un trailing stop s’exécute à l’intérieur d’une barre dépend du chemin intra-barre de TradingView (script de notation).
Le pire trade est affiché, pas noté
Les niveaux se lisent au 90e centile, pas sur le pire trade. Une stratégie publique montre pourquoi ; voici la sortie du script de notation sur order-harbor-stop-limit-01, abrégée :
Matched: 471 (100.0% of TV)
Count delta: 0.0000% (OK; abs=0)
PnL p90 delta: 0.0381% (OK)
-- report-only (not gated; MAE/MFE are intrabar-path-limited) --
Entry/Exit/PnL p100: 0.0011% / 0.0084% / 4.9658%
-> excellent
Regardez le dernier chiffre avant le niveau : le P&L d’un trade s’écarte de près de 5 %. Si on lui demande ses pires trades (--show-diffs 3), le script de notation montre que, sur ce trade, TradingView est entré à 1 970,36 et PineForge à 1 970,35, pour une perte d’environ 51 cents. Un cent sur environ 2,5 unités, cela fait 2,5 cents, et 2,5 cents, c’est 5 % d’une perte de 51 cents. Une note fondée sur le pire trade refuserait « excellent » à cette stratégie pour un cent sur une seule entrée ; le centile la laisse passer, et le rapport affiche malgré tout la valeur aberrante.
Juger une modification
Un niveau décrit le code tel qu’il est. Une modification, elle, se juge à ce qu’elle fait bouger : les mêmes sondes sont notées avant et après. La règle n’admet aucune régression sur le périmètre critique. Sur tous les autres marchés et unités de temps, elle calcule un score sur deux tranches, « excellent » et « excellent+strong » : avec un score supérieur à zéro, la modification passe tant qu’aucune sonde qui sort d’une tranche ne recule de plus d’un niveau ; avec un score nul, elle passe si rien ne s’est dégradé (README).
Deux tranches, parce que chacune voit des mouvements qui échappent à l’autre. Une stratégie qui passe de « strong » à « excellent » ne change que le premier décompte ; une stratégie qui passe de « moderate » à « strong » ne change que le second. En septembre, une modification a fait passer 32 sondes en « excellent » ; deux d’entre elles étaient auparavant sous « strong » et ont donc compté dans les deux tranches : la modification a obtenu un score de +34, sans qu’aucune sonde ne recule. Le périmètre critique, c’est le volet ETH en 15 minutes : 1 009 sondes, dont les 309 stratégies du corpus ouvert. Aucune sonde ne peut y reculer, quoi que la modification gagne ailleurs.
Quand rien ne bouge
Beaucoup de bonnes modifications ne font rien bouger : un refactoring, une nouvelle API, le correctif d’un cas qu’aucune stratégie de l’ensemble n’atteint. Une modification qui ne touche que la documentation ne demande aucune campagne de notation (exemple). Quand aucune sonde n’entre dans une tranche ni n’en sort, une modification du code obtient un score nul. Selon la règle du README, elle passe tant que rien ne s’est dégradé : avec la mention « no-improve-no-regression » si aucune sonde n’a changé de niveau, ou « improved » si une amélioration échappe aux deux tranches, par exemple une stratégie qui monte de « weak » à « moderate ». Un score nul peut aussi masquer une perte, et la modification échoue alors : une sonde qui tombe de « moderate » à « minimal », sous les deux tranches, ou une sonde dont le recul annule le gain d’une autre.
Pour ce genre de modification, un mouvement nul est le résultat attendu ; il ne prouve pas pour autant que rien d’autre n’a changé, car cinq mots restent une mesure grossière. C’est pourquoi la CI du moteur fige aussi un hash de chaque liste de trades que le moteur produit sur le corpus ouvert : modifier le slippage d’un tick sur une seule stratégie « déplace ses trades et son hash de référence, alors que verify_corpus.py affiche toujours excellent=311, strong=0, anomaly=1 » (documentation de la CI).
Ce que cela change pour vous
- Sur une page de la galerie, « excellent » signifie le même nombre de trades que TradingView, au moins 99 % des trades de TradingView reproduits, et des prix et un P&L dans les limites du tableau ci-dessus pour neuf trades sur dix. Pour « excellent », lorsque TradingView affiche deux ou plusieurs Signals d’entrée distincts au même instant exact, au même prix et dans la même direction, le moteur affiche autant d’entrées distinctes à cet endroit (identité des entrées distinctes). Toutes les stratégies de la galerie sont en « excellent », sauf une, déclarée comme anomalie côté TradingView ; « strong » n’apparaît que dans le test privé.
- Si vous comparez votre propre backtester à TradingView, faites-le de la même façon : appariez les trades par leur entrée, calculez la couverture sur l’ensemble des trades de TradingView, et lisez des centiles, pas le pire trade.
- La partie publique peut être relancée : les commandes du README compilent, exécutent et notent les 312 stratégies du corpus. Le test privé, c’est notre propre mesure sur des scripts qui ne sont pas publics, pour la plupart des scripts communautaires gardés privés conformément aux conditions d’utilisation de TradingView.
Niveaux mesurés le 2026-09-29 sur du code du moteur et du codegen inclus dans les versions 1.0.0. Le code du moteur et du codegen 1.0.1, sortis le 2026-10-02, a été noté sur les mêmes 7 989 sondes, sans qu’aucune sonde ne change de niveau.
Pour aller plus loin
- Comment nous mesurons la parité : les résultats actuels et leurs sources.
- Parcourir la galerie : le niveau de chaque stratégie du corpus, avec les deux listes de trades.
- Une histoire de parité sur la marge : à quoi ressemble la sortie du script de notation quand une stratégie n’est pas en « excellent », et comment l’une d’elles a été remontée jusqu’à sa cause.