15 novembre 2026 · recherche

Comment backtester le volume crypto quand les wash trades gonflent le tape ?

Comment backtester le volume crypto quand les wash trades gonflent le tape ?

Lundi, nous avons fait ce qu'il fallait. L'agent avait une stratégie momentum sur un perpetual USDT-M mid-cap, en clips de 25,000 USDT par trade, et le premier backtest sans filtre de volume a exécuté chaque signal comme si le carnet était celui du BTC. Nous avons donc ajouté le filtre du manuel : vingt barres d'une minute de volume en dollars devaient dépasser vingt fois le clip avant qu'un ordre puisse partir. Vingt minutes, un demi-million de dollars de tape. Le coin imprimait environ $40 million les jours chargés. Le filtre a gardé la plupart des signaux. La courbe d'equity s'est un peu lissée. Nous l'avons envoyé en paper.

Onze heures plus tard, un achat de 25,000 USDT a mangé 8,400 de bid et s'est arrêté. Le volume sur vingt barres à cette minute était de $1.14 million. Le filtre avait dit oui.

34%du tape déclaré n'a jamais fait bouger un niveau du carnet
11 hde paper avant le premier clip coincé
20×règle clip-sur-volume qui a quand même dit oui

Lundi : le filtre qui nous a donné bonne conscience

La note de l'agent sur la pull request était « contrôle de capacité ajouté, notionnel 20×. » Je l'ai approuvée. J'ai déjà approuvé cette phrase. C'est le genre de règle qu'on écrit après qu'on vous a montré un backtest qui tradait un coin à $4,000 d'OI en clips de $50,000, que tout le monde dans la pièce fait la grimace, et qu'on ajoute un multiple de volume pour que ça ne se reproduise plus.

Lundi, la règle a fait ce qu'elle fait toujours en backtest. Elle a écarté les heures mortes. Elle a gardé les heures où le chiffre de volume de l'exchange avait l'air bruyant. Le turnover a chuté d'environ un tiers. La taille moyenne des trades est restée à 25,000 parce que le modèle de fill est un lâche : il prend le clip entier au last plus quelques bps dès que le filtre est ouvert. Personne n'a demandé au carnet si 25,000 était vraiment assis là.

Je tressaille encore quand le volume 24h d'un coin est un chiffre rond à côté d'un open interest maigre. C'est un reste de 2021, quand les bots de « market making » Discord étaient deux sous-comptes qui tradaient entre eux et collaient le screenshot de volume dans #brag. Le tape a l'air d'une fête. Le carnet est en carton. Je me disais qu'un filtre 20× sur des barres d'une minute, c'était comme on dépasse ça. Ce n'est pas ça. C'est comme on moyenne le carton en un chiffre plus lisse.

Mardi : le paper, puis un reliquat

Le paper a commencé gentiment. Les cinq premiers clips se sont exécutés en 2–4 sauts le long de l'ask. Moche, mais fait. Puis 14:07 UTC, un signal long, 25,000 USDT, top of book 1,100, niveau suivant 2,400, puis le vide. Nous avons eu 8,400 exécutés en taker et 16,600 en resting. Quarante secondes plus tard, le reliquat s'est annulé sur notre propre time-in-force. La stratégie se croyait longue d'un clip entier. Le compte était long d'un tiers.

Mais le filtre avait dit oui. J'ai sorti la barre. Le volume en dollars sur les vingt minutes jusqu'à 14:07 était de $1.14 million, largement au-dessus de $500k. Environ $380k de ces $1.14 million étaient des paires de prints : même prix, même taille, flags d'aggressor opposés, à 2–8 millisecondes d'écart, et la taille bid/ask à ce prix n'a pas bougé. Ces trades se payaient les frais entre eux. Ils ne nous offraient pas un trou de 25,000 USDT.

Mercredi : recouper le tape avec le carnet

Mercredi a été le jour lent, celui pour lequel je prévoierais deux fois plus de temps la prochaine fois. Nous avons pris cinq jours de semaine de trades et de snapshots L2 sur le même perp, des photos du carnet à 100ms, et classé chaque print contre le carnet un snapshot avant et un snapshot après.

  1. Si la taille au prix du trade a baissé d'environ la taille du trade, il a touché le carnet. On le compte.
  2. Si un buy et un sell de taille égale se sont imprimés à un même prix sans changement du carnet, appelez-le wash et retirez-le de tout chiffre de capacité.
  3. Si un trade a traversé plusieurs niveaux et que ces niveaux ont disparu, c'est un vrai taker. On le compte, et on ne fait pas semblant de pouvoir aussi prendre cette liquidité ; quelqu'un l'a déjà fait.
  4. Si le trade est tagué liquidation, c'est de la vraie taille, et c'est la dernière taille dont on veut se servir pour prouver que vous pouvez clipper 25,000. L'ordre forcé est en train de vous doubler.

Les snapshots mentent un peu. Tout ce qui s'exécute et se reconstitue en moins de 100ms a l'air d'un fantôme, et certains vrais market-makers font du cancel-replace aussi vite. Nous avons ensuite échantillonné quelques minutes de carnets à 10ms et la part de wash a bougé de quelques points, pas d'un facteur deux. Je peux vivre avec quelques points. Je ne peux pas vivre avec le fait de traiter le ticker de volume de l'exchange comme un recensement de liquidité.

Les AggTrades agrègent déjà un taker qui touche plusieurs makers au même prix. Ils n'agrègent pas deux sous-comptes qui font du wash. Si votre feed « propre » est des trades agrégés, vous avez toujours ce problème. Vous l'avez juste avec moins de lignes.

Et le volume 24h sur l'API ticker est la même somme sale, en différé, c'est pour ça que les agents de research l'adorent. Un champ. Toujours là. On dirait une feature. C'est une statistique marketing qui se trouve être dans le protobuf market-data.

Si un chiffre de volume ne peut pas être rapproché d'un changement dans le carnet, il n'a pas sa place dans un contrôle de capacité, un modèle d'impact ou un filtre d'univers. Le ticker 24h est la pire copie de ce chiffre, parce qu'il a déjà été sommé, arrondi, et vidé de son temps.

Jeudi : la semaine en un tableau

Cinq sessions, même clip, même règle 20×, même modèle de fill dans le backtest. Le ratio de fill paper, c'est le notionnel exécuté sur le notionnel visé pour les ordres que nous avons vraiment envoyés cette session. Le paper du lundi est vide parce que nous étions encore en backtest.

SessionTape exchangeMouvant le carnetType washPrints liq.Filtre a dit goFill paper
Lun$38.4m$22.6m$13.5m$2.3m41 / 48 signauxn/a
Mar$41.1m$24.2m$15.2m$1.7m36 / 400.61
Mer$29.6m$20.1m$8.1m$1.4m22 / 310.77
Jeu$44.8m$25.6m$17.4m$1.8m39 / 440.54
Ven$33.2m$22.3m$9.4m$1.5m28 / 350.71

Les prints type wash représentaient 34% du tape de la semaine. Ils n'étaient pas répartis uniformément. Jeudi, la session que le filtre d'origine préférait le plus, était la plus sale. C'est le mode de défaillance qui m'importe. Le filtre ne se contente pas de surestimer la liquidité en moyenne. Il s'ouvre plus grand les jours où les bots de wash tournent, parce que ce sont les jours où le chiffre brut a l'air le plus sain.

Nous avons relancé le backtest avec uniquement le volume mouvant le carnet, même multiple 20×. Les signaux sont passés de 198 dans la semaine à 121. Beaucoup de ceux écartés se trouvaient dans ces heures façon jeudi où le tape était bruyant et le top of book à 1,100 USDT. Le Sharpe d'origine utilisait 198 fills complets. Je ne vais pas citer le nouveau comme s'il s'agissait d'un résultat sur la stratégie. C'est un résultat sur le modèle de fill : une fois qu'on arrête d'accorder 25,000 USDT à un prix que le carnet n'avait pas, une partie de l'« edge » n'est que des ordres complétés qui auraient été des reliquats.

Vendredi : ce que nous shippons vraiment, et ce que je sauterais

Le filtre que nous avons gardé est ennuyeux. Le notionnel glissant mouvant le carnet, compté uniquement à partir des prints qui ont retiré de la taille d'un niveau, doit dépasser 20× le clip, et nous le mesurons sur les barres avant la barre de décision pour que le wash de la minute en cours ne puisse pas voter. Les prints de liquidation ont un plafond à part : si plus d'un quart du volume récent mouvant le carnet est des liquidations, la stratégie se retire. Le flux forcé, c'est de la vraie taille qui vous double.

L'impact a eu le même régime. L'ancien modèle inférait un lambda de Kyle à partir du volume de l'exchange et de notre clip. Nourrissez-le de wash et le lambda baisse, parce que le marché a l'air profond. Nourrissez-le de volume mouvant le carnet et le même clip représente une part bien plus grande de ce qui a vraiment changé le carnet. Le slippage paper sur les sessions suivantes s'est rapproché de ce chiffre plus laid. Plus proche, pas identique. Nous ne voyons toujours pas la queue, et une photo à 100ms rate encore de la vraie taille.

Ce que je sauterais la prochaine fois, c'est tout le premier lundi. Ne partez pas du ticker, ne partez pas du volume 24h, ne laissez pas l'agent mettre le volume brut en dollars dans le feature store et dans le filtre comme si c'étaient deux idées. C'est une seule série sale, utilisée deux fois. Construisez d'abord le tape cohérent avec le carnet, même si ça veut dire faire de la research pendant deux jours sur un seul mid-cap avant d'avoir un univers. Un univers filtré sur le wash, c'est une liste de coins doués pour avoir l'air occupés.

L'autre chose à sauter : tout modèle de fill qui traite un contrôle de volume validé comme un fill. Le reliquat de mardi, c'était la stratégie. Le filtre ne peut répondre qu'à « est-ce que quelqu'un a tradé. » Il ne peut pas répondre à « est-ce que vos 25,000 vont rester ou disparaître. » Cette deuxième question a besoin du carnet, d'un reliquat et d'un time-in-force, c'est un autre journal, et c'est celui que nous aurions dû écrire avant celui-ci.

wash tradingvolumecryptobacktestingmicrostructure de marché
← Tous les articles