背景:金融データ収集の練習として、EUR/USD、USD/JPYといった外国為替通貨ペアのリアルタイムレートを取得するプログラムを作成しました。最初はHTTPの定時ポーリングで実装しましたが、デモでは動作するものの、更新頻度を上げるとデータの遅延という問題が発生しました。今回の失敗をもとに、ポーリングからWebSocketによる長時間接続へ切り替え、リアルタイム外国為替APIから相場データを取得する学習記録をまとめます。
最初にデモコードを書いたときは、定時ループでAPIにリクエストを送信して為替レートを取得していました。更新頻度が低い状況であれば実装が簡単で、少ないコードで通貨ペアの価格を取得できます。
しかし実際の相場に近づけようと行情更新頻度を高めると、問題が顕在化します。リクエスト回数が急増するだけでなく、プログラムが取得する価格と市場の実際レートに時間のズレが生じ、遅延が目立つようになります。
遅延の問題を解決するため、「クライアントから何度もリクエストを送るのではなく、サーバー側から最新相場をプッシュ配信してもらえないか」と考え、WebSocketによる長時間接続の方式を採用しました。何度もHTTPリクエストを繰り返す方式と比べ、リアルタイム外国為替APIと長時間接続を確立しプッシュデータを受信することで遅延を抑え、データ伝送経路を安定させられます。相場閲覧ツールの作成、簡易的なクオンツデータ収集、Tickデータを保存して分析学習を行う場面などでは、ストリーム配信方式が適しています。
2種類の相場取得方式を学習・比較
従来のHTTPインターフェースはリクエスト‑レスポンスモデルです。クライアントがリクエストを送信すると、サーバーがデータを返し、通信が終了すると接続が切断されます。
✅向いている場面:過去相場の照会、低頻度での為替レート確認
✅不向きな場面:低遅延が求められる高頻度リアルタイム相場取得
WebSocket長時間接続では持続的な通信経路を維持します。接続確立後、監視したい通貨ペアを購読するだけで、サーバーから価格変動データが次々と送信されてきます。EURUSDを例にすると、配信されるデータには主に下記の情報が含まれます。
- 売値・買値の情報
- 相場更新のタイムスタンプ
- 通貨ペアの識別子
- 価格変動に関する情報
取得した生データを活用し、動的な相場グラフを描画したり、ファイルやデータベースに書き出したりして、データ分析の学習素材として利用することも可能です。
| 方式 | 仕組み | 学習・練習に適した場面 | 課題点 |
|---|---|---|---|
| HTTP定時ポーリング | 周期的にAPIへリクエストを送信 | 過去データ取得、低頻度確認 | 高頻度実行時リクエスト量が増大、相場に遅延が発生 |
| WebSocket長時間接続 | 持続接続を確立、購読後サーバーがTickデータをプッシュ配信 | リアルタイム相場収集、クオンツデモ開発 | 切断時の自動再接続、タイムゾーンのフォーマット調整を自身で実装する必要がある |
コード実践:Python+WebSocketで外国為替リアルタイムTickデータを取得
学習時の習慣として、相場受信処理を独立させて実装しています。生データの受信だけを担当させることで、後からデータ保存、価格計算といった機能を追加しても、相場受信ロジックを壊すことがなく、結合度を抑えてデバッグしやすくなります。
下記はそのまま実行可能な練習用コードです。
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
symbol = data.get("symbol")
price = data.get("price")
timestamp = data.get("timestamp")
print(
symbol,
price,
timestamp
)
def on_open(ws):
request = {
"action": "subscribe",
"symbol": "EURUSD",
"type": "tick"
}
ws.send(json.dumps(request))
def on_error(ws, error):
print(error)
def on_close(ws):
print("websocket closed")
ws = websocket.WebSocketApp(
"wss://api.alltick.co/forex/websocket",
on_open=on_open,
on_message=on_message,
on_error=on_error,
on_close=on_close
)
ws.run_forever()
コードのロジックはシンプルです。接続が完了したら購読リクエストを送信し、サーバーからメッセージが届いたらデータを解析して出力します。学習する際はon_messageのコールバック内に処理を追加し、データ保存や簡易な価格判定などの機能を試してみてください。
学習で遭遇したトラブルと注意点
1. 時刻フォーマットの統一処理を行う
外国為替市場は世界複数のタイムゾーンにまたがっており、APIによって返却される時刻規格が異なります。UTC時刻を返すものもあれば、取引所ローカル時刻を返すものも存在します。そのまま保存すると、K線描画や価格統計の練習をする際に時系列の順番が崩れてしまいます。
私の対応方針:データ受信後、統一された時刻フォーマットに変換してから保存し、画面表示時に必要に応じてローカルタイムに再変換します。タイムゾーンに起因するバグを回避できます。
2. 接続切断への対応を忘れない
WebSocketはリクエストを繰り返す必要がないものの、ネットワークの揺らぎにより接続が突然切断される場合があります。長時間プログラムを動かしたい場合は自動再接続ロジックを実装し、再接続完了後に再度通貨ペアの購読を実行しなければ相場データが受信できなくなります。課題制作のときに見落としがちなポイントです。
3. コールバック関数内に重い処理を書かない
行情の配信量が多くなった場合、複雑な計算やディスク書き込みなどの重い処理をon_messageコールバックに直接記述しないでください。生データを一時的にキャッシュし、別の処理モジュールで非同期に処理するようにし、メッセージ受信がブロックされデータロストが発生するのを防ぎます。
学習まとめ
リアルタイム外国為替APIは相場収集プログラムの一部に過ぎません。少数の通貨ペアのレートをたまに確認するだけなら、単純なHTTPリクエストで十分です。一方、リアルタイム相場を監視し大量のTick生データを扱う学習を行う場合は、WebSocket長時間接続がより適切な選択肢となります。
Pythonは豊富なライブラリが揃っており、金融データ関連の学習やデモ開発に向いています。事前にデータ構造とモジュールの役割を計画しておけば、後から機能を追加するのも容易になります。関連する実装を試す際はAllTick APIを活用することで、WebSocketによる相場接続のプロトタイプを素早く検証できます。
