Comment les données sont enregistrées
∞structurelTransactions, cotations et mises à jour du carnet, chacune horodatée d'un numéro de séquence et d'une heure d'horloge. Bien gérer les horodatages et l'ordonnancement, c'est la différence entre un vrai backtest et une fiction.
L'idée
Ce que montre ce schéma. Un flux n'est que le moteur d'appariement qui se raconte : des messages typés (ADD, TRADE, DELETE), chacun portant un numéro de séquence et jusqu'à trois horodatages. Un achat marketable émet deux messages qu'il faut appliquer atomiquement, et la transaction ne porte aucun sens d'agresseur. Manquez un seul numéro de séquence et un ordre fantôme n'est jamais annulé, corrompant en silence tout état ultérieur – c'est pourquoi une capture sans trou est le contrôle d'intégrité.
Quels sont les trois types de messages sur une bande ?
Une bande (tape) transporte trois sortes de messages. Une transaction enregistre une exécution : prix, taille, et parfois le sens de l'agresseur. Une cotation enregistre un changement du meilleur bid ou ask. Une mise à jour du carnet enregistre un ajout, une modification ou une annulation à n'importe quel niveau de prix. Les transactions vous disent ce qui s'est passé ; les cotations et mises à jour du carnet vous disent ce qui était disponible.
L'intuition d'abord, car la structure est plus simple que le jargon. Le moteur d'appariement (le carnet d'ordres) ne fait que deux choses toute la journée : il pose et annule des ordres au repos, et il croise des ordres en transactions. La bande, c'est juste le moteur qui raconte les deux, message par message, dans l'ordre exact où ils se sont produits. Tout le reste de cette page est de la comptabilité posée par-dessus ce flux unique.
Une transaction (un « print ») indique qu'une exécution a eu lieu : instrument, prix, taille, horodatage, un identifiant de transaction, et souvent un jeu de codes de condition (print d'enchère, lot atypique, hors carnet, déclaration tardive). Crucial : la plupart des flux de transactions publics n'indiquent pas le sens de l'agresseur (si l'acheteur ou le vendeur a franchi le spread), ce qui est tout le problème de l'inférence du sens des transactions. Une cotation (une mise à jour du BBO) indique que le meilleur bid ou le meilleur ask a changé, un nouveau prix ou une nouvelle taille en haut du carnet ; c'est le flux L1. Une mise à jour du carnet (message de profondeur) indique qu'un ordre a été ajouté, modifié à la baisse ou annulé à un niveau de prix : le flux L2/L3, la vérité granulaire d'où l'on peut dériver les cotations et même les transactions.
Quelle est la différence entre données L1, L2 et L3 ?
Les trois niveaux décrivent quelle part du carnet un flux expose. L1, c'est juste le haut du carnet : meilleur bid et ask plus la dernière transaction. L2, c'est la profondeur agrégée par niveau de prix (market-by-price). L3, c'est ordre par ordre (market-by-order) : chaque ordre individuel avec son propre identifiant et sa position de file. Les flux plus profonds sont plus volumineux, mais ils permettent de reconstruire davantage de la microstructure.
L1 (haut du carnet / BBO) donne le meilleur bid, le meilleur ask, leurs tailles et la dernière transaction : assez pour voir le prix, inutile pour modéliser la profondeur, la file ou la probabilité d'exécution. L2 (market-by-price, MBP) donne, pour chaque côté, la taille totale au repos agrégée à chaque niveau de prix (souvent les 5 à 10 niveaux du haut) : l'entrée standard de la plupart des travaux de microstructure, où vous pouvez voir la profondeur et modéliser le fait de balayer le carnet mais ne pouvez pas retrouver où un ordre précis se situe dans la file. L3 (market-by-order, MBO) donne chaque ordre individuel, avec son propre identifiant, prix, taille et arrivée, si bien que vous pouvez voir la position de file et reconstruire le carnet de façon déterministe, ce qu'exige l'étude de la valeur de file et de la probabilité d'exécution.
Le point honnête, répété dans tout cet atlas : la granularité que vous pouvez obtenir plafonne les questions que vous pouvez poser. Nasdaq TotalView-ITCH et la plupart des flux de places sérieux sont MBO ; la plupart des « L2 » du particulier sont du MBP agrégé et ne peuvent pas retrouver la file. Une bande L3/MBO propre est la ressource que les pages de stratégie supposent en silence, et la chose que presque personne n'a proprement.
Quels sont les trois horodatages, et pourquoi diffèrent-ils ?
Un seul message peut porter jusqu'à trois horodatages : l'horodatage de place (moteur d'appariement) quand l'événement a eu lieu à l'intérieur de la place, l'horodatage de passerelle quand il a quitté la bordure de la place, et votre propre horodatage de capture quand votre gestionnaire l'a reçu. Ils diffèrent par la latence de transmission et de file, et seul l'horodatage de place ordonne correctement les événements entre instruments.
L'intuition est un relais d'horloges. L'événement se produit dans un domaine d'horloge (le moteur), traverse fils et passerelles (un autre), et est enregistré dans le vôtre (un troisième). Chaque saut ajoute du délai et de la gigue ; les trois marques bornent où le temps a été passé. La marque de place / moteur est l'horloge causale : appliquée à l'instant de l'événement, c'est la seule qui ordonne correctement deux événements sur des instruments différents, c'est donc la marque que vous utilisez pour toute analyse inter-instruments (lead-lag, ou les règles de sens de transaction qui comparent une transaction à une cotation contemporaine). La marque de passerelle est appliquée quand le message sort de la passerelle de données de marché de la place ; son écart à la marque du moteur mesure la latence interne de la place. La marque de capture est appliquée par votre gestionnaire de flux ou votre carte de capture à la réception ; son écart à la marque de passerelle est votre latence de transport.
Les captures sérieuses marquent au niveau de la carte réseau (disciplinées par PTP, souvent à la nanoseconde) plutôt que dans le logiciel, parce que la gigue d'ordonnancement de l'OS écrase les différences qui vous intéressent. Un time.time() logiciel dans un gestionnaire Python est sans valeur pour la microstructure : la gigue qu'il ajoute est plus grande que les écarts de latence qu'il mesurerait. L'horodatage de capture est exactement la quantité que la pile à faible latence et la colocation existent pour réduire.
Pourquoi la synchronisation d'horloge (PTP) compte-t-elle ?
Pour comparer des événements entre machines, places ou instruments, chaque horloge doit s'accorder à la microseconde près, sinon vous ne pouvez pas dire lequel de deux événements quasi simultanés est arrivé en premier. PTP (IEEE 1588) discipline les horloges sur une référence commune (souvent GPS) à une précision sous la microseconde ; la précision milliseconde de NTP est bien trop grossière, et MiFID II RTS 25 en fait une exigence légale du plancher.
Le danger est une causalité fabriquée. Si deux horloges dérivent d'une milliseconde, un « lead-lag » que vous mesurez à l'échelle de la milliseconde est un artefact des horloges, pas du marché : aux échelles de temps du HFT, des horloges non synchronisées inventent des relations qui n'existent pas. PTP (Precision Time Protocol, IEEE 1588) distribue une horloge maîtresse disciplinée par GPS sur un réseau avec horodatage matériel à chaque saut, atteignant une synchronisation sous la microseconde (souvent des dizaines de nanosecondes). NTP est de classe milliseconde et adéquat seulement pour le travail en barres journalières.
Il y a aussi un plancher réglementaire. MiFID II RTS 25 exige que les horloges des participants HFT soient synchronisées sur l'UTC à 100 microsecondes près (1 ms pour le non-HFT), et le Consolidated Audit Trail (CAT) américain fixe ses propres règles de granularité ; les deux sont des minimums de 2026, et les boutiques compétitives tournent bien plus serré. À retenir pour un lecteur qui achète ou construit une bande : la qualité des horodatages est aussi importante que les prix. Un flux à horodatages logiciels et horloge non disciplinée ne peut pas soutenir la recherche en microstructure, aussi bon marché soit-il.
Que sont les numéros de séquence, et pourquoi doivent-ils être sans trou ?
Chaque message d'un flux porte un numéro de séquence croissant de façon monotone. Il permet au récepteur de détecter un paquet perdu ou désordonné : si vous voyez la séquence 1004 après 1002, vous avez manqué 1003 et votre carnet est désormais faux. La détection de trous plus un mécanisme de récupération sont ce qui rend un carnet reconstruit digne de confiance.
L'intuition, c'est que l'état local du carnet est un total cumulé. Le carnet que vous tenez est la somme cumulée de chaque incrément ; manquez un incrément et tout état ultérieur est silencieusement corrompu : un ordre fantôme qui ne s'annule jamais, un niveau qui ne se vide jamais. Le numéro de séquence est le contrôle d'intégrité qui détecte le manque. Les flux de données de marché multicast (binaires, par ex. ITCH sur UDP) numérotent chaque message par canal, et un trou () signifie une perte de paquet, fréquente en multicast UDP, qui déclenche une récupération.
La récupération prend deux formes. Un flux A/B redondant publie deux flux multicast identiques ; vous arbitrez, prenant le message qui arrive le premier et comblant les trous de A par B. Ou un canal snapshot/refresh vous laisse demander un carnet frais, puis rejouer les incréments depuis. Dans les deux cas, un backtest fidèle en dépend : pour simuler les exécutions, vous devez rejouer la séquence exacte de messages que le moteur a produite, dans l'ordre, ce qui n'est possible que si votre capture est sans trou et contrôlée par séquence. Une bande à trous silencieux produit un backtest qui diverge de la réalité de façons que vous ne pouvez pas voir (backtesting & simulation).
Snapshots vs incréments : comment reconstruit-on le carnet ?
Un flux vous donne un snapshot périodique (le carnet complet à un instant) plus un flux d'incréments (chaque ajout, modification ou annulation). Vous construisez le carnet en chargeant le dernier snapshot, puis en appliquant chaque incrément en séquence. Les snapshots bornent le temps de récupération ; les incréments portent les changements en direct. Inversez l'ordre d'application et votre carnet se désynchronise.
Voyez le snapshot comme un point de sauvegarde et les incréments comme les coups depuis. Vous pouvez toujours reconstruire l'état courant à partir de la dernière sauvegarde plus les coups, à condition de les appliquer dans la séquence exacte sans trou. Les flux incrémentaux (delta) sont le réglage efficace par défaut : seuls les changements sont envoyés, si bien que la bande passante suit l'activité, pas la taille du carnet. Le snapshot/refresh est envoyé périodiquement ou sur demande, si bien qu'un arrivant tardif (ou un gestionnaire qui a pris un trou) peut se resynchroniser sans rejouer toute la journée.
C'est le bug crypto classique. Beaucoup de places crypto diffusent un snapshot REST/WS plus un canal de diffs WebSocket, et vous devez mettre en tampon les diffs, récupérer le snapshot, puis n'appliquer que les diffs dont la séquence dépasse celle du snapshot. Sauter cette poignée de main (appliquer des diffs antérieurs au snapshot, ou l'inverse) corrompt silencieusement le carnet, l'erreur la plus courante quand on enregistre sa propre place. Le modèle professionnel est de style ITCH/OUCH : l'ITCH de Nasdaq est un flux MBO purement incrémental (messages add / execute / cancel / delete order) ; OUCH est le protocole de saisie d'ordres associé. Le modèle (incréments complets add/modify/cancel avec un snapshot de récupération) est repris par CME MDP 3.0, Eurex EOBI et d'autres. Renvoi croisé vers IX-FIX pour décoder les octets de message réels ; citez la spécification de flux de la place pour le jeu de messages exact (en 2026).
Exemple travaillé
Un fragment de bande MBO synthétique pour l'instrument XYZ, en 2026 : un canal, horodatages en nanosecondes depuis minuit de cette place, monotone. La séquence 1001 ajoute 300 lots au bid à 50,00 (ordre A, le meilleur bid) ; 1002 ajoute 100 à l'ask à 50,01 (ordre B, le meilleur ask, donc le spread est d'un tick) ; 1003 ajoute 400 au bid à 49,99 (ordre C, bid de niveau 2). Puis un achat exécutable arrive : 1004 est une TRANSACTION de 100 à 50,01, et 1005 est un DELETE de l'ordre B à 50,01. Lisez ce que cette bande vous dit.
L'achat exécutable franchissant le spread a produit deux messages : le print de transaction (1004) et la mise à jour du carnet retirant l'ask au repos (1005). Ils partagent un horodatage à la nanoseconde près parce qu'ils sont un seul événement de moteur, votre gestionnaire doit donc appliquer les deux de façon atomique ; traitez-les séparément et vous afficherez un instant une transaction contre une offre encore au repos. La transaction en 1004 ne porte aucun drapeau d'agresseur ; vous inféreriez qu'elle était initiée à l'achat parce qu'elle a printé à l'ask, la règle de la cotation ; voir inférence du sens des transactions.
Maintenant, perdez un paquet. Supposons que votre capture ait sauté de la séquence 1003 à 1005, manquant la transaction en 1004. Vous porteriez un ask au repos fantôme B qui ne s'annule jamais : votre carnet montre une liquidité qui n'existe plus, et tout état ultérieur hérite de l'erreur. La détection de trou sur le 1004 manquant () est précisément ce qui vous sauve : elle force une récupération au lieu d'une corruption silencieuse. Les chiffres ici sont illustratifs et synthétiques ; la granularité d'horodatage réelle, les jeux de messages et les codes de condition sont propres à la place, lisez donc toujours la spécification de flux de la place (en 2026). La structure (événements, trois horodatages, numéros de séquence, snapshot plus incréments) est invariante ; les largeurs de champ et les codes sont ce que vous devez chercher.