Market Data Timestamps: SIP विरुद्ध Exchange Clocks
Market data timestamps चार clocksमधून येतात. एकाच tradesना प्रत्येक clockनुसार sort केल्यावर tape कसा बदलतो आणि कोणता clock कधी वापरायचा ते जाणून घ्या.
Market data timestamps म्हणजे matching engineकडून निष्पादित केलेला एक trade print तो दाखवणाऱ्या स्क्रीनपर्यंत पोहोचताना त्यावर नोंदवले जाणारे वेळेचे ठसे. US equity tradeच्या सार्वजनिक नोंदीत असे तीन timestamps असतात. प्रत्येक timestamp वेगळ्या प्रश्नाचे उत्तर देतो. त्याच दिवसातील prints आधी एका clockनुसार आणि नंतर दुसऱ्या clockनुसार sort करा. तुम्हाला दोन खरोखर वेगळे tapes मिळतील.
एक print ज्या चार clocksमधून जातो
तुमच्यापर्यंत पोहोचेपर्यंत एका printवर अनेक वेळा timestamp लावला जातो. क्रमाने:
- Matching engine time. एखाद्या venueच्या matching engineने दोन orders एकमेकांशी जुळवलेला क्षण. Venueबाहेरील कोणीही ही value थेट वाचू शकत नाही. Trade कधी झाला याचे हे वास्तविक ground truth आहे. त्यानंतरचे प्रत्येक clock त्याचे approximation असते.
- Participant time, ज्याला venue किंवा exchange time असेही म्हणतात. Venueने आपल्या feedवर print प्रकाशित करताना लिहिलेला timestamp. तो
participant_timestampfieldमध्ये असतो. प्रत्यक्षात तुम्ही वाचू शकत असलेल्या सर्व valuesपैकी हा matching engineच्या सर्वात जवळचा असतो. - SIP time. Print consolidated tapeपर्यंत पोहोचल्यावर securities information processorने लिहिलेला timestamp. Consolidated tape हा US equity venuesना एकत्र करणारा एकमेव अधिकृत feed आहे. ही
sip_timestampfield आहे आणि अधिकृत tape sequence तिचे अनुसरण करते. त्या feed आणि venueच्या स्वतःच्या feedमधील फरक SIP विरुद्ध direct exchange feeds येथे दिला आहे. - Capture time. Packet तुमच्या network cardवर पोहोचल्यावर तुमच्या स्वतःच्या network cardने लिहिलेला timestamp. तो vendorच्या recordमध्ये कधीही दिसत नाही, कारण तो marketऐवजी तुमचा data path दर्शवतो. Packet capture आणि replayचे काम पूर्णपणे या clockवर चालते.
Exchangeबाहेरील printsवर trf_timestamp हा पाचवा timestamp असतो. Trade reporting facilityने report स्वीकारल्याची वेळ तो दर्शवतो.
Venuesनुसार market data timestamps का वेगळे असतात
Venueच्या timestamp आणि consolidated timestampमधील फरक म्हणजे printने transitमध्ये आणि processorच्या queueमध्ये घालवलेला वेळ. ही एकच संख्या नसते. प्रत्येक venue processorपासून वेगळ्या अंतरावर असते. Hardware आणि queueदेखील वेगवेगळे असतात. खालील panelमध्ये 10 June 2026 रोजीच्या ठरावीक अर्ध्या तासात AAPLचे prints करणाऱ्या प्रत्येक venueसाठी हा फरक मोजला आहे.
प्रत्येक आकड्यामागील अचूक SQL
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 15त्या venuesमध्ये venue timestamp आणि consolidated timestampमधील सर्वात मोठा median gap 346.2 microseconds होता. तो NYSE Arca, Inc. येथे दिसला. त्याच windowमध्ये सर्वात कमी gap असलेल्या venueचा gap 13.7 microseconds होता. p99 columnकडे विशेष लक्ष द्या. त्या सर्वात धीम्या venueसाठी तो 420.8 microsecondsपर्यंत पोहोचला. Median लपवतो तो tail हा column दाखवतो.
कोणता timestamp वापरावा
जवळजवळ प्रत्येक परिस्थितीसाठी चार नियम पुरेसे आहेत.
- Microstructure work आणि event studiesसाठी participant time. एखाद्या venueवर काय घडले आणि कोणत्या क्रमाने घडले हे मोजायचे असल्यास venue clock वापरा. MBO विरुद्ध MBP order book dataचा विषय असलेली order book reconstruction इतर कोणत्याही clockवर वापरता येत नाही.
- अधिकृत tapeशी जुळवणी आवश्यक असलेल्या प्रत्येक कामासाठी SIP time. Regulatory reporting, best execution review, अधिकृत open आणि close, तसेच counterparty consolidated recordशी तपासणार असलेली कोणतीही figure यासाठी SIP time वापरा.
- तुमच्या स्वतःच्या pathचे मोजमाप करण्यासाठीच capture time. Data तुमच्या machineपर्यंत पोहोचायला किती वेळ लागला हे ते सांगते. Trade कधी झाला हे ते सांगत नाही. दोन machinesवरील capture time कधीही समान नसतो.
- एकाच datasetमध्ये clocks मिसळू नका. एका clockवरील quotes आणि दुसऱ्या clockवरील trades यांचा join केल्यास आकडे वरवर योग्य दिसतात. परंतु महत्त्वाच्या क्षणी ते अपयशी ठरतात.
तेच prints, दोन पद्धतीने sorted
Sorting करताना हा फरक स्पष्ट दिसतो. खालील panelमध्ये त्या अर्ध्या तासातील सर्वाधिक गजबजलेले ten milliseconds घेतले आहेत. Venue orderमधील पहिले twelve on-exchange prints ठेवले आहेत. त्यानंतर तेच twelve consolidated tape orderमध्ये पुन्हा क्रमवारीत लावले आहेत. दोन rankingsमध्ये प्रत्येक print किती स्थानांनी हलला यानुसार table sort केले आहे.
प्रत्येक आकड्यामागील अचूक SQL
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 ASCएखाद्या printच्या दोन ranksमधील सर्वात मोठा फरक 6 आहे. तो print 10:44:17.160712 वाजता आपल्या venueमधून निघाला आणि 10:44:17.161018 वाजता tapeवर पोहोचला. त्याला 305.7 microseconds लागले. Venue clockवरील 6व्या स्थानावरून तो tapeवरील 12व्या स्थानावर गेला. यापैकी कोणताही क्रम चुकीचा नाही. ते वेगवेगळ्या प्रश्नांची उत्तरे देतात. Tape clockवर केलेल्या trade sequence studyमध्ये हा burst कोणत्याही venueने प्रत्यक्षात निर्माण न केलेल्या क्रमाने दिसतो. Venue clockवर केलेले best execution review अधिकृत recordशी जुळत नाही.
Exchangeबाहेरील prints eventनंतर बराच उशिरा पोहोचतात
Exchangeपासून दूर, wholesalerकडे किंवा dark poolमध्ये निष्पादित झालेला trade सार्वजनिक order bookवर match होत नाही. तो trade reporting facilityला report केला जातो. Reportमध्ये execution time असते. मात्र ती report नंतर tapeवर पोहोचते. हा कालावधी travel time नसून reporting delay असतो. तो अनेक पटींनी मोठा असतो.
प्रत्येक आकड्यामागील अचूक SQL
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) ASCत्या windowमधील off-exchange AAPL printsपैकी 24.8% prints under 1 ms bucketमध्ये येतात. Tail 1 s to 10 s bucketपर्यंत जातो आणि त्यात 74 prints आहेत. दहा seconds उशिरा पोहोचलेल्या printवर तो प्रत्यक्षात निष्पादित झाल्याची venue clock timeच असते. मात्र tape streamमध्ये तो त्या executionनंतर दहा secondsनी दिसतो. Tape timeनुसार sort केल्यास तो चुकीच्या minuteमध्ये दिसतो. सामान्य sequenceच्या बाहेर report केलेल्या printsवर sale condition codes असतात. ते तसे असल्याचे हे codes दर्शवतात. trade condition codesचा एक उद्देश हाच आहे.
त्याच tradesपासून दोन व्यक्ती वेगवेगळे bars का तयार करतात
जवळजवळ प्रत्येक “data चुकीचा आहे” असा ticket याच कारणामुळे निर्माण होतो. Bar म्हणजे printsचा एक bucket. Print कोणत्या stampनुसार bucketमध्ये ठेवला आहे, यावर त्याचा bucket ठरतो. खालील panelमध्ये venue clockवरून tape clockवर बदलल्यावर bucket बदलणाऱ्या printsची संख्या चार सामान्य bar lengthsसाठी मोजली आहे.
प्रत्येक आकड्यामागील अचूक SQL
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 ASC1 second gridवर त्या windowमधील 8.966% prints दोन clocksनुसार वेगळ्या barमध्ये येतात. एकूण 8944 prints असे आहेत. Bar 5 minutesपर्यंत मोठा केल्यावर ही संख्या 0.024%पर्यंत कमी होते. ही रचना यांत्रिक आहे. Printचा clock gap एखादी boundary ओलांडला की तो bucket बदलतो. Shorter barsमध्ये boundaries अधिक असतात. त्यामुळे दोन vendors बरोबर असूनही त्याच minuteसाठी वेगळे volume प्रकाशित करू शकतात. OHLCV bars कसे तयार केले जातात येथे ही पद्धत सविस्तर दिली आहे.
Nanosecond field म्हणजे nanosecond accuracy नव्हे
दोन्ही timestamps nanosecond resolution असलेल्या integersच्या रूपात येतात. Resolution म्हणजे field कोणती value व्यक्त करू शकते. Accuracy म्हणजे ती value वास्तविक वेळेच्या किती जवळ आहे. या दोन्ही गोष्टी पूर्णपणे वेगवेगळ्या घटकांवर ठरतात.
Industryमधील clock alignment हे physicsऐवजी regulatory toleranceने नियंत्रित केले जाते. FINRAच्या clock synchronization ruleनुसार member firmsचे business clocks NIST referenceपासून 50 millisecondsच्या मर्यादेत असणे आवश्यक आहे. Exchanges आणि processors यापेक्षा अधिक अचूक alignment ठेवतात. ते Precision Time Protocol (PTP, IEEE 1588 म्हणून standardised) वापरतात. हा protocol data वाहून नेणाऱ्या त्याच networkवर reference clock वितरित करतो आणि machinesना sub microsecond alignmentमध्ये ठेवतो.
यातून दोन निष्कर्ष निघतात. एका organisationच्या stampsमध्ये microsecond resolutionवरील ordering अर्थपूर्ण असते. वेगवेगळ्या organisationsमधील दोन stampsमधील काही hundred nanosecondsचा फरक error barच्या आत असतो. त्याला वास्तविक ordering मानणे म्हणजे noiseचे वाचन करणे होय.
वारंवार विचारले जाणारे प्रश्न
SIP timestamp आणि participant timestampमध्ये काय फरक आहे?
Venueने आपल्या feedवर trade प्रकाशित करताना participant timestamp लिहिला जातो. Trade अधिकृत combined feedवर पोहोचल्यावर consolidated tape processor SIP timestamp लिहितो. दोन्हीमधील gap म्हणजे transit आणि queueing time. On-exchange printsसाठी तो microsecondsमध्ये मोजला जातो. Trade reporting facilityमार्फत report केलेल्या printsसाठी तो अनेकदा milliseconds किंवा त्याहून अधिक असतो.
Backtestingसाठी कोणता market data timestamp वापरावा?
एखाद्या venueवर participantला काय दिसू शकले किंवा त्याने काय केले असते याचे model तयार करत असल्यास participant timestamp वापरा. अधिकृत consolidated recordशी जुळवणी आवश्यक असल्यास SIP timestamp वापरा. कोणताही timestamp निवडला तरी quotesसह studyमधील प्रत्येक tableवर तोच लागू करा.
माझे one-minute bars data providerच्या barsशी का जुळत नाहीत?
सामान्यतः clock mismatch हे कारण असते. Venue stamp minute boundaryच्या अगदी आधी असलेल्या printचा tape stamp boundaryनंतरचा असू शकतो. त्यामुळे दोन conventionsनुसार तोच trade वेगवेगळ्या barsमध्ये जातो. उशिरा report केलेले off-exchange prints हा फरक आणखी वाढवतात.
Nanosecond timestamps nanosecondपर्यंत अचूक असतात का?
नाही. Fieldमध्ये nanosecond resolution असते. Accuracy ही timestamp लिहिणाऱ्या machineचे clock किती अचूकपणे synchronise केले आहे यावर ठरते. PTP वापरणाऱ्या exchange आणि processor systemsमध्ये sub microsecond alignment असते. Brokerचे business clocks 50 millisecondsच्या regulatory toleranceमध्ये ठेवले जातात. अधिक सैल clockच्या toleranceपेक्षा सूक्ष्म comparisons अर्थपूर्ण नसतात.
वरील प्रत्येक panelसोबत तो तयार करणारी SQL query दिली आहे. त्यामुळे प्रत्येक figure कोणत्या clockवरून आली हे तुम्ही अचूकपणे पाहू शकता. Printsच्या स्वतःच्या windowला वेगळ्या clockनुसार पुन्हा sort करून tape कसा बदलतो हे पाहण्यासाठी Strasmore terminalवर plain Englishमध्ये प्रश्न विचारा.