深夜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つの典型的エラー
バックテスト開発者が最初に直面するのは「データが足りない」問題だ。具体的には以下のエラーが多発する。
- 401 Unauthorized: APIキー期限切れまたはIP制限
- 429 Too Many Requests: レート制限超過(Binance公式は1200リクエスト/分)
- Timestamp gap detected: OHLCV再構築時のティック欠損
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",