Horodatages des market data : SIP ou bourse ?
Les market data utilisent quatre horloges. Découvrez comment chacune réordonne les mêmes trades sur le tape et quelle horloge choisir selon votre analyse.
Les horodatages des market data sont les heures inscrites sur un même print lorsqu’il circule du matching engine qui l’a exécuté jusqu’à l’écran qui l’affiche. Une transaction sur actions américaines en comporte trois dans les données publiques, et chacune répond à une question différente. Triez les prints d’une même séance selon une horloge, puis selon une autre : vous obtenez deux tapes réellement différents.
Les quatre horloges que traverse un même print
Un print reçoit plusieurs horodatages avant de vous parvenir. Dans l’ordre :
- Heure du matching engine. C’est l’instant où le matching engine d’une place fait se croiser deux ordres. Personne en dehors de la place ne lit directement cette valeur. Elle constitue la référence pour déterminer quand la transaction a eu lieu ; toutes les horloges suivantes n’en sont qu’une approximation.
- Heure du participant, également appelée heure de la place ou de l’exchange. C’est l’horodatage inscrit par la place lorsqu’elle publie le print sur son propre feed, dans le champ
participant_timestamp. Parmi les valeurs effectivement accessibles, c’est celle qui est la plus proche du matching engine. - Heure du SIP. C’est l’horodatage inscrit par le securities information processor lorsque le print atteint le consolidated tape, le feed officiel unique qui regroupe toutes les places américaines d’actions. Il s’agit du champ
sip_timestamp, et la séquence du tape officiel suit cette valeur. La différence entre ce feed et le feed direct d’une place est expliquée dans SIP et feeds directs des exchanges. - Heure de capture. C’est l’horodatage inscrit par votre propre carte réseau lorsque le paquet arrive. Il n’apparaît jamais dans les données d’un vendor, puisqu’il décrit votre trajet et non le marché. Les travaux de capture et replay de paquets reposent entièrement sur cette horloge.
Les prints off exchange portent un cinquième horodatage, trf_timestamp, qui indique le moment où une trade reporting facility a reçu la déclaration.
Pourquoi les horodatages des market data diffèrent selon les places
L’écart entre l’horodatage d’une place et celui du consolidated tape correspond au temps passé par un print en transit et dans la file d’attente du processeur. Ce n’est pas une valeur unique. Chaque place se trouve à une distance différente du processeur, utilise un matériel différent et passe par une file d’attente différente. Le tableau ci-dessous mesure cet écart pour chaque place ayant imprimé AAPL pendant une demi-heure fixe le 10 juin 2026.
Le SQL exact derrière chaque chiffre
WITH venues AS
(
SELECT
toUInt32(id) AS exchange_id,
any(coalesce(nullIf(acronym, ''), name)) AS venue_name
FROM global_markets.stocks_exchanges
WHERE asset_class = 'stocks'
GROUP BY exchange_id
)
SELECT
if(v.venue_name = '', concat('Venue ', toString(t.exchange)), v.venue_name) AS venue,
count() AS print_count,
round(quantileDeterministic(0.5)(
toFloat64(toUnixTimestamp64Nano(t.sip_timestamp)
- toUnixTimestamp64Nano(t.participant_timestamp)) / 1000,
toUInt64(t.sequence_number)), 1) AS median_lag_us,
round(quantileDeterministic(0.99)(
toFloat64(toUnixTimestamp64Nano(t.sip_timestamp)
- toUnixTimestamp64Nano(t.participant_timestamp)) / 1000,
toUInt64(t.sequence_number)), 1) AS p99_lag_us
FROM global_markets.stocks_trades AS t
LEFT JOIN venues AS v ON v.exchange_id = toUInt32(t.exchange)
WHERE t.ticker = 'AAPL'
AND t.sip_timestamp >= '2026-06-10 14:30:00'
AND t.sip_timestamp < '2026-06-10 15:00:00'
AND ifNull(toUnixTimestamp64Nano(t.trf_timestamp), 0) = 0
GROUP BY venue
HAVING count() >= 200
ORDER BY median_lag_us DESC
LIMIT 15Sur ces places, l’écart médian le plus important entre l’horodatage de la place et celui du consolidated tape était de 346.2 microsecondes, pour NYSE Arca, Inc.. La place la plus rapide sur la même fenêtre affichait 13.7 microsecondes. La colonne p99 est la plus instructive : pour cette même place la plus lente, elle atteignait 420.8 microsecondes. Elle montre la latence extrême que la médiane masque.
Quel horodatage utiliser
Quatre règles couvrent presque tous les cas.
- L’heure du participant pour les travaux de microstructure et les event studies. Toute analyse qui mesure ce qui s’est passé sur une place et dans quel ordre doit utiliser l’horloge de la place. La reconstitution du carnet d’ordres, traitée dans données de carnet d’ordres MBO et MBP, est inutilisable avec une autre horloge.
- L’heure du SIP pour toute analyse devant être rapprochée du tape officiel. Cela concerne le reporting réglementaire, l’analyse de best execution, l’ouverture et la clôture officielles, ainsi que tout chiffre qu’une contrepartie vérifiera par rapport au registre consolidé.
- L’heure de capture uniquement pour mesurer votre propre trajet. Elle indique le temps nécessaire aux données pour atteindre votre machine. Elle ne dit rien du moment où la transaction a eu lieu, et deux machines ne l’enregistrent jamais de la même manière.
- Ne mélangez jamais les horloges dans un même dataset. Une jointure qui rapproche des quotes horodatées selon une horloge de trades horodatés selon une autre produit des chiffres plausibles, mais devient fausse précisément dans les moments importants.
Les mêmes prints, triés de deux façons
C’est au moment du tri que la distinction devient concrète. Le tableau ci-dessous prend les dix millisecondes les plus actives de cette demi-heure, conserve les douze premiers prints on exchange dans l’ordre de la place, puis classe de nouveau ces mêmes douze prints selon l’ordre du consolidated tape. Le tableau est trié selon l’écart entre les deux rangs de chaque print.
Le SQL exact derrière chaque chiffre
WITH
burst AS
(
SELECT intDiv(toUnixTimestamp64Nano(participant_timestamp), 10000000) AS slice_10ms
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-06-10 14:30:00'
AND sip_timestamp < '2026-06-10 15:00:00'
AND ifNull(toUnixTimestamp64Nano(trf_timestamp), 0) = 0
GROUP BY slice_10ms
ORDER BY count() DESC, slice_10ms ASC
LIMIT 1
),
sample AS
(
SELECT
participant_timestamp,
sip_timestamp,
toUInt64(sequence_number) AS seq,
toUnixTimestamp64Nano(sip_timestamp)
- toUnixTimestamp64Nano(participant_timestamp) AS lag_ns
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-06-10 14:30:00'
AND sip_timestamp < '2026-06-10 15:00:00'
AND ifNull(toUnixTimestamp64Nano(trf_timestamp), 0) = 0
AND intDiv(toUnixTimestamp64Nano(participant_timestamp), 10000000)
IN (SELECT slice_10ms FROM burst)
ORDER BY participant_timestamp ASC, seq ASC
LIMIT 12
),
ranked AS
(
SELECT
participant_timestamp,
sip_timestamp,
lag_ns,
row_number() OVER (ORDER BY participant_timestamp ASC, seq ASC) AS participant_rank,
row_number() OVER (ORDER BY sip_timestamp ASC, seq ASC) AS sip_rank
FROM sample
)
SELECT
concat('P', leftPad(toString(participant_rank), 2, '0')) AS print_label,
concat(formatDateTime(toTimeZone(participant_timestamp, 'America/New_York'), '%H:%i:%S'), '.',
leftPad(toString(intDiv(toUnixTimestamp64Nano(participant_timestamp) % 1000000000, 1000)), 6, '0')) AS venue_clock_et,
concat(formatDateTime(toTimeZone(sip_timestamp, 'America/New_York'), '%H:%i:%S'), '.',
leftPad(toString(intDiv(toUnixTimestamp64Nano(sip_timestamp) % 1000000000, 1000)), 6, '0')) AS tape_clock_et,
participant_rank,
sip_rank,
abs(toInt32(sip_rank) - toInt32(participant_rank)) AS places_moved,
round(lag_ns / 1000, 1) AS sip_lag_delta_us
FROM ranked
ORDER BY places_moved DESC, participant_rank ASCL’écart maximal entre les deux rangs d’un print est de 6. Ce print a quitté sa place à 10:44:17.160712 et atteint le tape 305.7 microsecondes plus tard, à 10:44:17.161018. Il passe ainsi de la position 6 selon l’horloge de la place à la position 12 selon le tape. Aucun des deux ordres n’est faux. Ils répondent à des questions différentes. Une étude de la séquence des transactions fondée sur l’horloge du tape lit cette séquence dans un ordre qu’aucune place n’a jamais produit. Une analyse de best execution fondée sur l’horloge de la place ne concorde pas avec le registre officiel.
Les prints off exchange arrivent longtemps après l’événement
Une transaction exécutée en dehors d’un exchange, chez un wholesaler ou dans un dark pool, est déclarée à une trade reporting facility au lieu d’être exécutée sur un carnet public. La déclaration porte l’heure d’exécution, mais elle atteint le tape plus tard. Cet intervalle correspond à un délai de déclaration, et non à un temps de transport. Il est d’un tout autre ordre de grandeur.
Le SQL exact derrière chaque chiffre
WITH off_exchange AS
(
SELECT
(toUnixTimestamp64Nano(sip_timestamp)
- toUnixTimestamp64Nano(participant_timestamp)) / 1000000.0 AS delay_ms
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-06-10 14:30:00'
AND sip_timestamp < '2026-06-10 15:00:00'
AND ifNull(toUnixTimestamp64Nano(trf_timestamp), 0) > 0
)
SELECT
multiIf(delay_ms < 1, 'under 1 ms',
delay_ms < 10, '1 to 10 ms',
delay_ms < 100, '10 to 100 ms',
delay_ms < 1000, '100 ms to 1 s',
delay_ms < 10000, '1 s to 10 s',
'over 10 s') AS reporting_delay,
count() AS print_count,
round(100 * count() / (SELECT count() FROM off_exchange), 2) AS share_pct
FROM off_exchange
GROUP BY reporting_delay
ORDER BY min(delay_ms) ASCParmi les prints AAPL off exchange de cette fenêtre, 24.8% se trouvent dans la tranche under 1 ms. La queue s’étend jusqu’à la tranche 1 s to 10 s, qui contient 74 prints. Un print arrivé avec dix secondes de retard conserve l’heure de la place à laquelle il a effectivement été exécuté, tout en apparaissant dix secondes plus loin dans le flux du tape. Si vous le triez selon l’heure du tape, il semble appartenir à la mauvaise minute. Les prints déclarés en dehors de la séquence normale portent des sale condition codes qui le signalent. C’est l’une des fonctions des codes de condition de transaction.
Pourquoi deux personnes construisent des bars différents à partir des mêmes trades
Presque tous les tickets signalant que « les données sont erronées » trouvent leur origine ici. Un bar est un ensemble de prints, et la tranche dans laquelle tombe un print dépend de l’horodatage utilisé. Le tableau ci-dessous compte les prints qui changent de tranche lorsque l’on passe de l’horloge de la place à celle du tape, pour quatre durées de bar courantes.
Le SQL exact derrière chaque chiffre
WITH
prints AS
(
SELECT
toUnixTimestamp64Nano(participant_timestamp) AS venue_ns,
toUnixTimestamp64Nano(sip_timestamp) AS tape_ns
FROM global_markets.stocks_trades
WHERE ticker = 'AAPL'
AND sip_timestamp >= '2026-06-10 14:30:00'
AND sip_timestamp < '2026-06-10 15:00:00'
),
grids AS
(
SELECT arrayJoin([1, 10, 60, 300]) AS bar_seconds
)
SELECT
multiIf(bar_seconds = 1, '1 second',
bar_seconds = 10, '10 seconds',
bar_seconds = 60, '1 minute',
'5 minutes') AS bar_length,
countIf(intDiv(venue_ns, toInt64(bar_seconds) * 1000000000)
!= intDiv(tape_ns, toInt64(bar_seconds) * 1000000000)) AS moved_print_count,
round(100 * countIf(intDiv(venue_ns, toInt64(bar_seconds) * 1000000000)
!= intDiv(tape_ns, toInt64(bar_seconds) * 1000000000)) / count(), 3) AS moved_pct
FROM prints
CROSS JOIN grids
GROUP BY bar_seconds
ORDER BY bar_seconds ASCSur une grille de 1 second, 8.966% des prints de cette fenêtre changent de bar avec les deux horloges, soit 8944 prints au total. Lorsque la durée du bar passe à 5 minutes, cette proportion tombe à 0.024%. Le mécanisme est simple : un print change de tranche lorsque l’écart entre ses deux horodatages franchit une limite. Les bars courts comportent davantage de limites. Deux vendors peuvent donc être tous les deux corrects tout en publiant des volumes différents pour la même minute. La méthode de construction est détaillée dans la construction des bars OHLCV.
Un champ en nanosecondes n’offre pas une précision à la nanoseconde
Les deux horodatages sont des entiers avec une résolution à la nanoseconde. La résolution correspond à ce que le champ peut exprimer. La précision indique à quel point la valeur est proche de l’heure réelle. Ces deux caractéristiques dépendent de facteurs complètement différents.
La synchronisation des horloges dans le secteur est encadrée par une tolérance réglementaire, et non par les limites de la physique. La règle de synchronisation des horloges de la FINRA impose aux entreprises membres de maintenir leurs horloges opérationnelles dans une limite de 50 millisecondes par rapport à la référence du NIST. Les exchanges et les processeurs utilisent une synchronisation beaucoup plus précise, fondée sur le Precision Time Protocol (PTP, standardisé par l’IEEE 1588). Ce protocole distribue une horloge de référence sur le même réseau que celui qui transporte les données et maintient les machines à moins d’une microseconde les unes des autres.
Deux conséquences en découlent. Au sein des horodatages d’une même organisation, l’ordre à la résolution de la microseconde est significatif. Entre organisations, un écart de quelques centaines de nanosecondes entre deux horodatages se situe dans la marge d’erreur. Le traiter comme un véritable ordre chronologique revient à interpréter du bruit.
FAQ
Quelle est la différence entre l’horodatage du SIP et celui du participant ?
L’horodatage du participant est inscrit par la place lorsqu’elle publie une transaction sur son propre feed. L’horodatage du SIP est inscrit par le processeur du consolidated tape lorsque cette transaction atteint le feed officiel combiné. L’écart entre les deux correspond au temps de transport et de mise en file. Il se mesure en microsecondes pour les prints on exchange, et souvent en millisecondes ou davantage pour les prints déclarés par l’intermédiaire d’une trade reporting facility.
Quel horodatage des market data utiliser pour un backtesting ?
Utilisez l’horodatage du participant pour toute modélisation de ce qu’un participant aurait pu voir ou faire sur une place. Utilisez l’horodatage du SIP pour toute analyse devant être rapprochée du registre consolidé officiel. Quel que soit votre choix, appliquez-le à toutes les tables de l’étude, y compris aux quotes.
Pourquoi mes bars d’une minute ne correspondent-ils pas à ceux de mon fournisseur de données ?
Un décalage d’horloge est généralement en cause. Un print dont l’horodatage de la place se situe juste avant la limite d’une minute peut avoir un horodatage du tape juste après cette limite. La même transaction se retrouve alors dans deux bars différents selon la convention retenue. Les prints off exchange déclarés tardivement amplifient l’écart.
Les horodatages en nanosecondes sont-ils précis à la nanoseconde ?
Non. Le champ offre une résolution à la nanoseconde, mais la précision dépend de la qualité de synchronisation de l’horloge de la machine qui l’inscrit. Les systèmes des exchanges et des processeurs utilisant le PTP restent alignés à moins d’une microseconde, tandis que les horloges opérationnelles des brokers sont soumises à une tolérance réglementaire de 50 millisecondes. Les comparaisons plus fines que la tolérance de l’horloge la moins précise ne sont pas significatives.
Chaque tableau ci-dessus est accompagné du SQL qui l’a produit. Vous pouvez ainsi vérifier exactement de quelle horloge provient chaque chiffre. Pour trier de nouveau votre propre fenêtre de prints selon une autre horloge et observer la modification du tape, formulez votre question en anglais courant sur le terminal Strasmore.