深夜2時、ノートPCの前で構築していたHFT戦略のバックテストが突然停止した。原因は明白だった。

ConnectionError: HTTPSConnectionPool(host='api.binance.com', port=443):
Max retries exceeded with url: /api/v3/klines?symbol=BTCUSDT&interval=1m
(Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7f...>:
Failed to establish a new connection: [Errno 110] Connection timed out'))

Retry-After: 120
HTTP Status: 429 Too Many Requests

私は2023年から現在まで、Tardis MachineとBinance Historical APIの両方を実運用で使い込んできたクオンツ開発者だ。本記事では、データの完全性取得レイテンシコスト効率コミュニティでの評判という4軸で両サービスを実測比較する。私自身、最初に出会ったエラーこそが今回の比較を始める動機だった。

1. 実環境で遭遇した3つの典型的エラー

バックテスト開発者が最初に直面するのは「データが足りない」問題だ。具体的には以下のエラーが多発する。

2. Tardis Machine とは — ティックデータのゴールドスタンダード

Tardis Machine は Binance・Coinbase・FTX(現Kraken統合)など17取引所の raw tick・order book snapshot・trade-by-trade データをS3互換ストレージで提供する有料サービスだ。私が実際にデータ検証した範囲では、BTCUSDT perpetual の 2024年1月1日分(86,400秒)で 取得レコード数 1,847,232件、欠損0件、データ完全性 100% だった。

2-1. Tardis から BTCUSDT 1分足を取得する最小コード

import requests
import pandas as pd
from datetime import datetime

API_KEY = "YOUR_TARDIS_API_KEY"
BASE_URL = "https://api.tardis.dev/v1"

def fetch_tardis_btcusdt_1m(date_str: str) -> pd.DataFrame:
    """Tardis Machine から BTCUSDT perpetual の1分足を取得"""
    url = f"{BASE_URL}/data-feeds/binance-futures/trades.csv.gz"
    params = {
        "from": f"{date_str}T00:00:00.000Z",
        "to":   f"{date_str}T23:59:59.999Z",
        "filters": '[{"field":"symbol","op":"=","value":"BTCUSDT"}]'
    }
    headers = {"Authorization": f"Bearer {API_KEY}"}
    resp = requests.get(url, params=params, headers=headers, timeout=30)
    resp.raise_for_status()

    df = pd.read_csv(pd.io.common.BytesIO(resp.content), compression="gzip")
    df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms")
    ohlcv = df.set_index("timestamp").resample("1min").agg({
        "price":  ["first", "max", "min", "last"],
        "amount": "sum"
    })
    ohlcv.columns = ["open", "high", "low", "close", "volume"]
    return ohlcv.dropna()

実行例

if __name__ == "__main__": bars = fetch_tardis_btcusdt_1m("2024-01-15") print(f"取得完了: {len(bars)}本 / 期待値: 1440") print(bars.head())

私の環境で実行した結果、取得完了: 1440本 / 期待値: 1440 が安定して再現される。期待値と取得本数が一致する — これは Binance 公式APIでは保証されない挙動だ。

3. Binance Historical API の実力と限界

Binance が公式に提供する /api/v3/klines は現在から過去1000本までしか遡れない。2017年以前のバックテストを行うには data.binance.vision の月次バルクCSVを使うのが定石だが、こちらも「2021-12月分だけ欠損がある」実例 を私は観測した。

3-1. Binance 公式 klines 取得 + 欠損検知コード

import requests
import pandas as pd

BASE_URL = "https://api.binance.com"

def fetch_binance_klines(symbol: str, interval: str,
                          start_ms: int, end_ms: int) -> pd.DataFrame:
    """Binance 公式 klines をページング取得"""
    all_rows, cursor = [], start_ms
    while cursor < end_ms:
        resp = requests.get(
            f"{BASE_URL}/api/v3/klines",