Market Data Timestamps: SIP vs Exchange Clocks
Market data timestamps come from four different clocks. See how sorting the same trades by each one changes the tape, and which clock to use for what.
Market data timestamps are the clocks stamped onto a single trade print as it travels from the matching engine that executed it to the screen that shows it. A US equity trade carries three of them in the public record, and each one answers a different question. Sort the same day's prints by one clock and then by another, and you hold two genuinely different tapes.
The four clocks a single print passes
A print gets stamped repeatedly on its way to you. In order:
- Matching engine time. The instant a venue's matching engine crossed two orders. Nobody outside the venue reads this value directly. It is the ground truth for when a trade happened, and every clock after it is an approximation of it.
- Participant time, also called venue or exchange time. The stamp the venue writes when it publishes the print on its own feed, carried in the
participant_timestampfield. Of everything you can actually read, this sits closest to the matching engine. - SIP time. The stamp the securities information processor writes when the print reaches the consolidated tape, the single official feed that merges every US equity venue. This is the
sip_timestampfield, and the official tape sequence follows it. The split between that feed and a venue's own is covered in SIP versus direct exchange feeds. - Capture time. The stamp your own network card writes when the packet lands. It never appears in a vendor's record, since it describes your path rather than the market. Packet capture and replay work runs entirely on this clock.
Off exchange prints carry a fifth stamp, trf_timestamp, marking when a trade reporting facility took the report in.
Why market data timestamps disagree across venues
The gap between a venue's stamp and the consolidated stamp is the time a print spent in transit and in the processor's queue. It is not one number. Each venue sits a different distance from the processor, on different hardware, behind a different queue. The panel below measures that gap for every venue that printed AAPL during a fixed half hour on 10 June 2026.
The exact SQL behind every number
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 15Across those venues, the widest median gap between the venue stamp and the consolidated stamp was 346.2 microseconds, at NYSE Arca, Inc.. The tightest venue in the same window ran 13.7 microseconds. The p99 column is the one worth staring at: for that same slowest venue it reached 420.8 microseconds, the tail a median hides.
Which timestamp should you use
Four rules cover almost every case.
- Participant time for microstructure work and event studies. Anything measuring what happened at a venue and in what order belongs on the venue clock. Order book reconstruction, the subject of MBO versus MBP order book data, is unusable on any other.
- SIP time for anything that must reconcile with the official tape. Regulatory reporting, best execution review, the official open and close, and any figure a counterparty will check against the consolidated record.
- Capture time only for measuring your own path. It tells you how long data took to reach your machine. It tells you nothing about when the trade happened, and two machines never agree on it.
- Never mix clocks inside one dataset. A join that matches quotes on one clock against trades on another returns numbers that look plausible and fail at exactly the moments that matter.
The same prints, sorted two ways
Sorting is where the abstraction breaks. The panel below takes the busiest ten milliseconds of that half hour, keeps the first twelve on exchange prints in venue order, then ranks the same twelve again in consolidated tape order. The table is sorted by how far each print moved between the two rankings.
The exact SQL behind every number
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 ASCThe largest gap between a print's two ranks is 6. That print left its venue at 10:44:17.160712 and reached the tape 305.7 microseconds later, at 10:44:17.161018, moving from position 6 on the venue clock to position 12 on the tape. Neither ordering is wrong. They answer different questions. A trade sequence study run on the tape clock reads this burst in an order no venue ever produced, and a best execution review run on the venue clock disagrees with the official record.
Off exchange prints land far behind the event
A trade executed away from an exchange, at a wholesaler or in a dark pool, is reported to a trade reporting facility rather than matched on a public book. The report carries the execution time, and it arrives at the tape afterwards. That interval is a reporting delay rather than travel time, and it is orders of magnitude larger.
The exact SQL behind every number
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) ASCOf the off exchange AAPL prints in that window, 24.8% land in the under 1 ms bucket. The tail runs out to the 1 s to 10 s bucket, holding 74 prints. A print that arrives ten seconds late still carries the venue clock time it actually executed, while sitting in the tape's stream ten seconds downstream of it. Sort by tape time and it appears in the wrong minute. Prints reported outside the normal sequence carry sale condition codes that say so, which is one of the things trade condition codes exist to flag.
Why two people build different bars from the same trades
Almost every "the data is wrong" ticket lands here. A bar is a bucket of prints, and the bucket a print falls into depends on which stamp you bucket by. The panel below counts the prints that change bucket when you switch from the venue clock to the tape clock, across four common bar lengths.
The exact SQL behind every number
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 ASCOn a 1 second grid, 8.966% of the prints in that window fall into a different bar under the two clocks, 8944 prints in all. Stretch the bar to 5 minutes and the figure drops to 0.024%. The pattern is mechanical: a print changes bucket whenever its clock gap straddles a boundary, and shorter bars carry more boundaries. Two vendors can both be correct and still publish different volume for the same minute. The construction itself is walked through in how OHLCV bars are built.
A nanosecond field is not nanosecond accuracy
Both stamps arrive as integers with nanosecond resolution. Resolution is what a field can express. Accuracy is how close the value sits to true time, and the two are set by completely different things.
Clock alignment across the industry is governed by regulatory tolerance rather than by physics. FINRA's clock synchronization rule holds member firms' business clocks to within 50 milliseconds of the NIST reference. Exchanges and processors run far tighter, using the Precision Time Protocol (PTP, standardised as IEEE 1588), which distributes a reference clock over the same network that carries the data and holds machines in sub microsecond alignment.
Two things follow. Within one organisation's stamps, ordering at microsecond resolution is meaningful. Across organisations, a difference of a few hundred nanoseconds between two stamps sits inside the error bar, and treating it as a real ordering is reading noise.
FAQ
What is the difference between the SIP timestamp and the participant timestamp?
The participant timestamp is written by the venue when it publishes a trade on its own feed. The SIP timestamp is written by the consolidated tape processor when that trade reaches the official combined feed. The gap between them is transit and queueing time, measured in microseconds for on exchange prints and often in milliseconds or longer for prints reported through a trade reporting facility.
Which market data timestamp should I use for backtesting?
Use the participant timestamp for anything that models what a participant could have seen or done at a venue, and the SIP timestamp for anything that must reconcile with the official consolidated record. Whichever you pick, apply it to every table in the study, quotes included.
Why do my one minute bars not match my data provider's?
A clock mismatch is the usual answer. A print whose venue stamp falls just before a minute boundary can carry a tape stamp just after it, which places the same trade in different bars under the two conventions. Late reported off exchange prints widen the effect.
Are nanosecond timestamps accurate to the nanosecond?
No. The field holds nanosecond resolution, and the accuracy is set by how well the writing machine's clock is synchronised. Exchange and processor systems using PTP hold sub microsecond alignment, while broker business clocks are held to a 50 millisecond regulatory tolerance. Comparisons finer than the tolerance of the looser clock are not meaningful.
Every panel above ships with the SQL that produced it, so you can see exactly which clock each number came from. To re-sort your own window of prints under a different clock and watch the tape change, ask the question in plain English on the Strasmore terminal.