ふくふくHukuhuku Inc.
EP.20Data Fetch 9分公開: 2026-09-02

暗号資産のデータを取る ── 取引所ごとの差を吸収する

取引所ごとに認証も、ページングも、レート制限も違います。1つずつ実装すると数が増えるほど破綻するので、差を吸収する層を使います。

#暗号資産#Python#API
執筆 / 監修
松尾 亮合同会社ふくふく 代表社員

データ基盤・データパイプライン構築 / BI / 生成 AI 活用支援を専門とするエンジニア (28 年)。 本記事は AI 利用ポリシーに基づき、生成 AI の補助で執筆 → 人間が監修・編集して公開しています。

プロフィール詳細
シェア

暗号資産のデータは、株式のように取引所をまたいだ統一の相場があるわけではありません。取引所ごとに完全に独立しています。同じ銘柄でも取引所によって価格が違い、扱っている銘柄も違います。どこか1か所を見れば済む、という構造になっていません。

そして取引所ごとに の作りが違います。認証方式、の型、、時刻の単位、銘柄の表記。全部違います。3か所くらいまでは個別に書けますが、増えるほど保守が破綻します。

銘柄の表記の差は特に地味に効きます。同じ組み合わせを BTC/USDT と書く取引所、BTCUSDT と書く取引所、XBT を使う取引所があります。表記を揃えないまま集計すると、同じものが別々に数えられます

時刻の単位も揃っていません。秒で返す取引所とミリ秒で返す取引所があり、取り違えると1970年付近の日付になったり、遠い未来になったりします。桁数を見れば判別できるので、取得直後に確認する処理を入れておくと事故を防げます。

差を吸収する層を使う

は、多数の取引所を同じ書き方で扱えるようにするです。取引所ごとの差を内部で吸収してくれるので、取引所を変えるのが1行の変更で済みます

自分で書く場合でも、この形は真似する価値があります。取引所ごとの差を1か所に閉じ込め、上位のコードからは同じ形に見せる。下流のコードが取引所を意識しない状態を作るのが要点です。

取引所を変えても、呼び出し側は変わらない形にする
Python
import ccxt

def make_client(exchange_id: str):    """取引所ごとの差はここに閉じ込める。呼び出し側は同じ形で使う。"""    cls = getattr(ccxt, exchange_id)    return cls({        "enableRateLimit": True,      # 取引所ごとの制限に自動で従う        "timeout": 30_000,    })

def fetch_ohlcv(exchange_id: str, symbol: str, timeframe: str = "1d", limit: int = 500):    client = make_client(exchange_id)    # 返るのは [時刻(ミリ秒), 始値, 高値, 安値, 終値, 出来高] の並び    return client.fetch_ohlcv(symbol, timeframe=timeframe, limit=limit)
レート制限は自動で守らせる

enableRateLimit を有効にすると、取引所ごとの制限に合わせて自動で間隔を空けてくれます。自分で調べて実装するより確実です。取引所ごとの制限値は変わることがあるので、任せられるものは任せてください。

この層を挟んでおくと、取引所を増やすときの作業が「対応表に1行足す」だけになります。逆に個別に書き分けていると、増やすたびに認証との実装をやり直すことになります。最初の1か所で決めた形が、そのまま将来の手間を決めます

取れる期間には限りがある

多くの取引所は、1回の要求で返す件数に上限を設けています。500件や1000件が一般的です。長期の系列が欲しければ、時刻をずらしながら繰り返し取得することになります。

ここで注意が要るのが、取得の終わりをどう判断するかです。返ってきた件数が上限より少なければ終わり、と判断するのが基本ですが、取引の無い期間があると途中で件数が減ります。件数だけで判断すると、そこで打ち切ってしまいます。

時刻を進めながら繰り返す。進まなくなったら終わり
Python
import time

def fetch_all_ohlcv(client, symbol: str, since_ms: int, timeframe: str = "1d"):    """時刻が進まなくなったら終了とする。件数では判断しない。"""    out = []    cursor = since_ms    while True:        batch = client.fetch_ohlcv(symbol, timeframe=timeframe, since=cursor, limit=1000)        if not batch:            break
        out.extend(batch)        last_ts = batch[-1][0]        if last_ts <= cursor:            break                      # 進んでいない。これ以上は取れない        cursor = last_ts + 1
        if cursor > int(time.time() * 1000):            break                      # 現在時刻を追い越した    return out

取得の途中で取引所が停止することもあります。計画的な保守もあれば、突発的な障害もある。片方の取引所だけデータが欠けた期間ができるので、複数を並べて比較するときは欠損の位置を確認してから使ってください。

板情報は時系列とは別物

は、その瞬間の注文の並びです。約定した価格の履歴とは別のもので、過去にさかのぼって取ることはできません。取りたければ、取り続けて自分で貯めるしかありません。

この性質は EP.05 で扱った「取り直せないデータ」の典型です。取得した時点の記録を残さなければ、その瞬間の状態は永久に失われます。板を扱うなら、生の記録を残す設計が必須になります。

貯めると決めた場合、どこまで細かく残すかを先に決めてください。上位の数段だけでよいのか、全段が要るのか。全段を秒単位で残すと量が跳ね上がり、保管の費用が無視できなくなります。後から粗くはできても、細かくはできない点に注意が要ります。

また、板は更新が非常に速いので、定期的に問い合わせる方式では取りこぼします。連続した接続で変化を受け取る方式が用意されている取引所が多く、量も桁違いになるので、保存の設計から考える必要があります。次回は、市場データの時刻の話をまとめます。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp