Strasmore Research
徹底分析 Matt Connor著者: Matt Connor

マーケットデータの時刻:SIPと取引所時計の違い

マーケットデータには四つの時計があります。同じ約定を時計ごとに並べ替えるとテープがどう変わるか、用途別にどの時計を使うべきかを解説します。

マーケットデータのタイムスタンプとは、約定を実行したマッチングエンジンから表示画面まで、単一の約定記録に付与される時刻である。米国株の約定記録には公開データ上、三つの時刻があり、それぞれ異なる問いに答える。同じ日の約定記録を一つの時刻で並べ、その後に別の時刻で並べると、実質的に異なる二つのテープが得られる。

単一の約定記録が通過する四つの時刻

約定記録には、投資家に届くまでの過程で繰り返し時刻が付与される。順序は以下のとおりである。

  1. マッチングエンジン時刻。 取引所のマッチングエンジンが二つの注文を約定させた瞬間の時刻である。取引所の外部にいる者がこの値を直接読むことはできない。約定が成立した時刻の基準であり、その後のすべての時刻はこの時刻の近似値である。
  2. 参加者時刻(取引所時刻とも呼ばれる)。 取引所が自らのフィードで約定記録を配信する際に書き込む時刻で、participant_timestampフィールドに記録される。実際に読み取れる時刻の中では、マッチングエンジン時刻に最も近い。
  3. SIP時刻。 約定記録が統合テープに到達した際に、証券情報処理業者(SIP)が書き込む時刻である。統合テープは、米国株のすべての取引所を統合する単一の公式フィードである。これはsip_timestampフィールドであり、公式テープの順序もこの時刻に従う。統合フィードと取引所独自のフィードの違いについては、SIPと取引所の直接フィードで説明する。
  4. キャプチャ時刻。 パケットが到着した際に、利用者自身のネットワークカードが書き込む時刻である。市場ではなく自分の通信経路を示すため、ベンダーの記録には現れない。パケットキャプチャとリプレイの処理は、すべてこの時刻を基準に行う。

取引所外の約定記録には、取引報告機関が報告を受け付けた時刻を示す第五の時刻、trf_timestampも付く。

市場データのタイムスタンプが取引所ごとに一致しない理由

取引所時刻と統合時刻の差は、約定記録が移動中および処理業者のキュー内で費やした時間である。これは単一の数値ではない。取引所ごとに処理業者までの距離、ハードウェア、キューが異なるためである。以下のパネルは、2026年6月10日の固定した30分間にAAPLの約定記録を配信したすべての取引所について、この差を測定したものである。

クエリ会場別SIP受信遅延、AAPL、2026年6月10日(マイクロ秒)
各数値の背後にある正確な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
Run this yourself

これらの取引所の中で、取引所時刻と統合時刻の中央値の差が最も大きかったのは346.2マイクロ秒で、NYSE Arca, Inc.だった。同じ時間帯で最も差が小さかった取引所は13.7マイクロ秒だった。注目すべきはp99列である。同じ最も遅い取引所では420.8マイクロ秒に達しており、中央値では見えない裾の遅延を示している。

どのタイムスタンプを使うべきか

ほとんどの場合、以下の四つの原則で判断できる。

  • マイクロストラクチャー分析とイベントスタディには参加者時刻を使う。 取引所で何が起き、どの順序だったかを測定する処理は、取引所時刻を基準にする。MBOとMBPの板情報で扱う注文板の再構築は、別の時刻では利用できない。
  • 公式テープとの照合が必要な処理にはSIP時刻を使う。 規制報告、最良執行の検証、公式の寄り付きと引け、そして取引相手が統合記録と照合する数値が該当する。
  • キャプチャ時刻は自分の通信経路の測定にだけ使う。 データが自分のコンピューターに届くまでの時間は分かるが、約定が成立した時刻は分からない。また、二台のコンピューターが同じ値を示すこともない。
  • 一つのデータセット内で時刻を混在させない。 一方の時刻で気配値を結合し、別の時刻で約定記録を結合すると、もっとも重要な局面で破綻する、もっともらしい数値が返される。

同じ約定記録を二通りに並べる

この違いが明確になるのが並べ替えである。以下のパネルでは、その30分間で最も取引が集中した10ミリ秒を取り上げ、取引所外約定を除く最初の12件を取引所時刻順に残した。その後、同じ12件を統合テープの順序で再び順位付けした。表は、二つの順位の移動幅が大きい順に並べている。

クエリ同じ十二件の約定を会場時計順・テープ時計順で表示します
各数値の背後にある正確な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
Run this yourself

一つの約定記録における二つの順位の最大差は6である。この約定記録は10:44:17.160712に取引所を離れ、305.7マイクロ秒後の10:44:17.161018にテープへ到達した。取引所時刻では6位だったが、テープでは12位になった。どちらの順序も誤りではない。答えている問いが異なるだけである。テープ時刻で行った約定順序の分析では、どの取引所も生成していない順序でこの集中局面を読むことになる。一方、取引所時刻で行った最良執行の検証は、公式記録と一致しない。

取引所外約定はイベントから大きく遅れて到着する

取引所外で、ホールセラーやダークプールを通じて成立した取引は、公開板で約定するのではなく、取引報告機関へ報告される。報告には約定時刻が記録され、その後にテープへ到着する。この間隔は移動時間ではなく報告遅延であり、桁違いに長い。

クエリ取引所外AAPL約定の報告遅延別、2026年6月10日
各数値の背後にある正確な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
Run this yourself

この時間帯の取引所外のAAPL約定記録のうち、24.8%がunder 1 msの区分に入った。遅延の裾は1 s to 10 sの区分まで伸び、そこには74件の約定記録が含まれる。10秒遅れて到着した約定記録にも、実際に成立した時点の取引所時刻は残っている。しかし、テープ上ではその10秒後に位置する。テープ時刻で並べると、別の分に入る。通常の順序以外で報告された約定記録には、そのことを示す売買条件コードが付く。取引条件コードは、そのような状態を示すために存在する。

同じ取引から二人の利用者が異なるバーを作る理由

「データが間違っている」という問い合わせのほとんどは、ここに行き着く。バーは約定記録をまとめた区間であり、どの時刻を基準に区切るかによって、約定記録が入る区間が変わる。以下のパネルは、四つの一般的なバー期間について、取引所時刻からテープ時刻へ切り替えた際に区間が変わる約定記録を数えたものである。

クエリ時計を切り替えるとバーが変わる約定、バー長別
各数値の背後にある正確な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 ASC
Run this yourself

1 secondの区切りでは、この時間帯の約定記録のうち8.966%が二つの時刻で異なるバーに入り、合計8944件だった。バーを5 minutesまで長くすると、その割合は0.024%に低下する。仕組みは単純である。時刻の差が区切り線をまたぐと、約定記録の入る区間が変わる。短いバーほど区切り線が多い。同じ1分間の出来高について、二つのベンダーがともに正しくても、異なる数値を公表することがある。作成方法はOHLCVバーの構築方法で詳しく説明している。

ナノ秒フィールドはナノ秒精度を意味しない

二つの時刻は、いずれもナノ秒単位を表現できる整数として届く。分解能とは、フィールドが表現できる細かさである。精度とは、値が真の時刻にどれだけ近いかであり、この二つを決める要因はまったく異なる。

業界全体の時計の同期は、物理法則ではなく規制上の許容範囲によって管理されている。FINRAの時計同期規則では、会員企業の業務用時計をNISTの基準時刻から50ミリ秒以内に保つことが求められる。取引所や処理業者は、Precision Time Protocol(PTP、IEEE 1588として標準化)を使い、より厳格に同期している。PTPはデータ伝送と同じネットワークを通じて基準時刻を配信し、機器間のずれを1マイクロ秒未満に抑える。

ここから二つの点が分かる。一つの組織内の時刻では、マイクロ秒単位の順序に意味がある。組織をまたぐ場合、二つの時刻の数百ナノ秒の差は誤差の範囲内にある。その差を実際の順序として扱うのは、ノイズを読み取ることになる。

よくある質問

SIPタイムスタンプと参加者タイムスタンプの違いは何ですか?

参加者タイムスタンプは、取引所が自らのフィードで取引を配信する際に書き込む。SIPタイムスタンプは、その取引が公式の統合フィードに到達した際に、統合テープの処理業者が書き込む。両者の差は移動時間とキューイング時間であり、取引所で成立した約定記録ではマイクロ秒単位、取引報告機関を通じて報告された約定記録ではミリ秒以上になることが多い。

バックテストにはどのマーケットデータのタイムスタンプを使うべきですか?

取引所で参加者が見たり取引したりできた状況をモデル化する場合は参加者タイムスタンプを使う。公式の統合記録との照合が必要な場合はSIPタイムスタンプを使う。どちらを選ぶ場合でも、気配値を含め、分析対象のすべてのテーブルに同じ時刻を適用する。

1分足がデータプロバイダーと一致しないのはなぜですか?

通常の原因は時刻の不一致である。取引所時刻が分の境界直前だった約定記録が、テープ時刻では境界直後になることがある。この場合、同じ取引が二つの基準で異なるバーに入る。取引所外約定の報告遅延が影響をさらに広げる。

ナノ秒タイムスタンプはナノ秒単位で正確ですか?

いいえ。フィールドはナノ秒単位の分解能を持つが、精度は記録する機器の時計がどれだけ同期しているかで決まる。PTPを使う取引所や処理業者のシステムは1マイクロ秒未満の同期を維持する一方、ブローカーの業務用時計には50ミリ秒の規制上の許容範囲がある。同期精度の低い時計の許容範囲より細かい比較には意味がない。


上記の各パネルには、作成に使ったSQLが付属している。そのため、各数値がどの時刻を基に算出されたかを正確に確認できる。自分の約定記録の時間帯を別の時刻で並べ替え、テープがどのように変わるか確認したい場合は、Strasmore terminalで平易な英語による質問を入力すればよい。