はじめに|定量開発でよく遭遇する悩み
金の日内高頻度トレード向けプログラムを開発している方なら、一度は経験するトラブルがあります。ローカルの相場表示画面は価格がスムーズに更新されているのに、Tick データからローソク足を作成してバックテストを回すと、実際の取引ツールと数値や波形がずれてしまう現象です。
私自身、金相場収集ツールを自作した際にこの問題に苦しみました。最初はローソク足の始値・高値・安値・終値を計算するロジックを何度も見直しましたが、どこに不具合があるのか見つけられませんでした。すべての生配信メッセージを出力して検証したところ、相場データに付属する増加型のシーケンス番号が不連続に飛び、複数の Tick 情報が通信途中で失われていることが判明したのです。
ここで大切なポイントをお伝えします。画面上の価格更新が正常に見えても、全ての約定記録が漏れなく保存できているとは限りません。金は取引が活発な商品なので、短時間に少しの Tick が欠けてもすぐに気づきにくいです。だけど長期間戦略の検証や流動性指標の算出に使うと、無視できない計算誤差が生まれてしまいます。今回はシーケンス番号を活用した連続性チェック、非同期で動く自動補完処理の実装手順を、実際に動かせる Python コードと共に紹介します。
1. シーケンス番号とは?データの欠損を見抜く目印
現在普及している金のリアルタイム相場 API は WebSocket の長時間接続を利用し、次々と Tick メッセージを配信しています。各データには価格、約定量、タイムスタンプといった基礎情報のほか、1 ずつ増え続けるシーケンス番号が紐付けられています。
この番号は各 Tick に割り振られた通し番号のようなもので、受信したデータが連続しているか判断する基準になります。例えば前回の番号が 10103、今回が 10107 だった場合、その間の 3 件の相場データが届いていないと分かる仕組みです。
2 つの番号の差が 1 より大きい時点で通信経路にデータ損失が発生したと判断できます。補完処理を用意していないと、後から作るローソク足や定量指標の数値が歪み、バックテストの結果が実運用の参考にならなくなってしまいます。
2. データ受信の一番最初に検証ロジックを入れる
長年定量システムを開発した経験から、シーケンス番号のチェックはデータを受け取る処理の最前段階に配置することをおすすめします。ローソク足の数値がおかしくなってから遡って調査するより、不具合を早期に捉えられ、調査の手間を大きく削減できます。
プログラムは新しい相場メッセージを受信するたびに、前回処理したシーケンス番号を保持し、現在の番号と差分を計算します。番号の間隔が開いていたら、欠損したデータの番号範囲を記録する流れです。簡単な判定の考え方は下記の通りです。
last_seq = 10103 curr_seq = 10107 missing_num = curr_seq - last_seq - 1 if missing_num > 0: print (f"相場データの欠損区間を検出、欠損 Tick 数:{missing_num}")
ここで重要な実装のコツが一つあります。リアルタイムでメッセージを処理するスレッドの中で、同期的に補完用 API を呼び出してはいけません。金相場は値動きが激しいため、補完処理にリソースが取られると新しい Tick の受信が滞り、さらなるデータ欠損を引き起こす恐れがあります。補完の処理は独立した非同期タスクに分けて実行するようにしましょう。
3. 欠損件数だけで補完を実行するか判断しないこと
シーケンス番号はデータが失われたかどうかを知るだけで、欠損が戦略にどれだけ影響するかまでは測れません。同じ 2 件の Tick が欠けた場合でも、横ばいのレンジ相場なら計算結果への影響は小さいですが、急騰・急落の激変局面だと数秒のデータ空白がローソク足の形を大きく変え、板情報を元にした指標算出を崩してしまいます。
そのため番号の飛びを検知した際は 4 種類の情報を同時に保存し、総合的に補完 API を呼び出すか判断します。
- 現在受信したメッセージのシーケンス番号
- 相場データに付属する標準タイムスタンプ
- ローカルプログラムがメッセージを受け取ったシステム時刻
- WebSocket 長時間接続のオンライン状態
複数の情報からデータ欠損が起きた時間帯を正確に特定し、必要なタイミングだけ過去相場を取得することで、API の過剰な呼び出しを抑えて利用枠を節約できます。
4. 実装時の落とし穴|補完後の重複登録を回避する方法
データ補完が完了した後、データベースに同じレコードを二重に書き込んでしまう隠れたバグに注意しましょう。よくある事例として、リアルタイム配信で既にシーケンス 10107 の Tick を受信済みなのに、補完 AllTick API から 10104~10107 までの過去データを取得した場合、重複チェックを入れていないと同一相場データが 2 回保存され、約定量や平均価格の集計結果が大きく歪んでしまいます。
標準的な回避策として、「商品コード+タイムスタンプ+シーケンス番号」の組み合わせで一意のレコードを識別する複合ユニークキーを作成します。DB へ登録する前に同じ組み合わせのデータが存在するか検索し、該当レコードがない時だけ保存処理を実行する流れです。
また、リアルタイムで取得したデータと補完で取得した過去データを統合した後は、必ずタイムスタンプの昇順で並び替えを行い、時系列が逆転する事態を防ぎます。これにより後続のローソク足作成や定量指標の計算が正常に動作する状態を保てます。
まとめ
金相場収集スクリプトを作成する際、多くの開発者は配信の遅延を抑えることばかりに注力し、データの連続性を確認する仕組みを後回しにしがちです。しかし相場システムを 24 時間 365 日稼働させる場合、一時的なネットワークの揺れや接続切断といった通信トラブルを完全になくすことはできません。
私自身の開発フローでは、今ではシーケンス番号による連続性検証を相場収集の必須工程として組み込んでいます。値動きの穏やかな時間帯は補完処理が起動することは稀ですが、通信異常が発生した瞬間にデータ欠損の区間を特定でき、ローソク足の不具合が出てから生メッセージを遡って調査する手間を大幅に減らせます。
日内・高頻度の定量トレードを行う開発者にとって、リアルタイム相場データを取得するだけは基礎的な作業に過ぎません。データ検証と自動補完の仕組みを整備し、途切れない一貫したデータストリームを確保することが、バックテストと実運用の結果のズレを抑え、戦略を長期的に安定稼働させる核心的なポイントになります。