私は暗号資産のクオンツ戦略を5年以上運用してきたエンジニアです。ライブの板情報に頼った裁量では再現性が取れないため、Tardis APIで取得した Binance の L2 履歴データを用いて、Python でミリ秒粒度のバックテストを回すのが私の標準ワークフローになっています。本記事では、データ取得 → オーダーブック再構築 → 簡易マーケットメイキング・シミュレーション → LLM による結果分析までを、< 50ms レイテンシで動作する 今すぐ登録 の HolySheep API を通じて一気通貫で実装する方法を紹介します。
なぜ Tardis API なのか
- L2 スナップショット+差分更新 (incremental_book_L2) が Binance / OKX / Bybit / Coinbase 等の主要取引所に対して提供されている
- 過去データへの S3 署名付き URL を使った高速バルクダウンロードが可能(1日分で数 GB)
- リアルタイムは WebSocket (
wss://ws.tardis.dev)、ヒストリカルは REST 経由で取得 - 1ms 粒度のタイムスタンプが標準で付与されており、HFT 系のバックテストにも耐える
代替として Kaiko、Dune Enterprise、CryptoCompare の Pro プランなども存在しますが、Tardis は (1) 価格、(2) カバー範囲、(3) コミュニティで広く使われており GitHub でも Tardis を前提としたオープンソースのバックテスター(cryptostore, qtrade など)が多数公開されている点が大きな利点です。Reddit の r/algotrading でも「historical L2 を最も安価に取得できる手段は Tardis 一択」というコメントが定期的に見られます。
1. 環境構築とインストール
# 推奨: Python 3.11+, pyenv で分離推奨
pip install requests pandas numpy websockets python-dateutil
pip install Tardis-Library # 公式が遅い場合は S3 直接アクセスでも OK
pip install openai # HolySheep は OpenAI 互換エンドポイント
2. Tardis で Binance L2 履歴データを取得する
Tardis のヒストリカルデータは incremental_book_L2(差分)と book_snapshot_5 / book_snapshot_10 / book_snapshot_25(深さ指定のスナップショット)に分かれます。再現性のあるバックテストにはスナップショット時刻を明示できる snapshot 系を、その後の高頻度検証には incremental_book_L2 を使うのが私の推奨構成です。
"""
tardis_binance_l2.py
Binance BTCUSDT の L2 差分データを Tardis API から取得し、
任意のタイムスタンプでオーダーブックを再構築するユーティリティ。
"""
import os
import json
import time
import requests
import pandas as pd
from datetime import datetime, timezone
TARDIS_API_KEY = os.environ.get("TARDIS_API_KEY", "YOUR_TARDIS_API_KEY")
SYMBOL = "btcusdt"
EXCHANGE = "binance"
BASE_URL = "https://api.tardis.dev/v1"
def request_dataset_info(from_date: str, to_date: str) -> dict:
"""指定期間の incremental_book_L2 メタ情報を取得"""
url = f"{BASE_URL}/exchanges/{EXCHANGE}"
params = {
"from": from_date, # 例 "2025-12-01"
"to": to_date, # 例 "2025-12-01"
"dataTypes": "incremental_book_L2",
"symbols": SYMBOL,
}
headers = {"Authorization": f"Bearer {TARDIS_API_KEY}"}
r = requests.get(url, params=params, headers=headers, timeout=30)
r.raise_for_status()
return r.json()
def fetch_messages_from_s3(file_urls: list, limit_messages: int = 200_000):
"""S3 署名 URL から gzip された NDJSON を直接取得"""
rows = []
for url in file_urls:
with requests.get(url, stream=True, timeout=60) as resp:
resp.raise_for_status()
for line in resp.iter_lines():
if not line:
continue
rows.append(json.loads(line))
if len(rows) >= limit_messages:
return rows
return rows
def reconstruct_book(messages):
"""incremental_book_L2 から最新板を再構築する"""
bids, asks = {}, {}
for m in messages:
side = m["side"] # "buy" or "sell"
price = float(m["price"])
amount = float(m["amount"])
book = bids if side == "buy" else asks
if amount == 0.0:
book.pop(price, None)
else:
book[price] = amount
return {
"ts": messages[-1]["timestamp"],
"bids": sorted(bids.items(), key=lambda x: -x[0])[:25],
"asks": sorted(asks.items(), key=lambda x: x[0])[:25],
}
if __name__ == "__main__":
info = request_dataset_info("2025-12-01", "2025-12-01")
print("Available files:", [f["url"] for f in info.get("files", [])][:3])
messages = fetch_messages_from_s3(
[f["url"] for f in info["files"] if f.get("type") == "incremental_book_L2"],
limit_messages=100_000,
)
book = reconstruct_book(messages)
print("Best bid:", book["bids"][0], "| Best ask:", book["asks"][0])
# 例: Best bid: (67500.10, 1.543) | Best ask: (67505.20, 2.018)
3. 簡易マーケットメイキング・バックテスター
L2 オーダーブックを再構築できたら、それを一定間隔(ここでは 100ms)でスキャンし、ミッド価格からの目標スプレッドで買い/売り注文を出すシンプルなマーケットメイキング戦略を実装します。約定確率は板の深さから推定しますが、ここでは可読性のため擬似乱数ベースの例を示します。
"""
backtest_mm.py
L2 スナップショットを時系列で受け取るジェネレータを消費し、
固定スプレッドのマーケットメイキング戦略を検証する。
"""
import math
import numpy as np
import pandas as pd
from dataclasses import dataclass, field
@dataclass
class MMResult:
pnl_usd: float = 0.0
trades: int = 0
inventory: float = 0.0
pnl_curve: list = field(default_factory=list)
class MarketMakingBacktest:
def __init__(self, target_spread_bps: int = 10,
tick_size: float = 0.01,
lot_size: float = 0.001,
fill_prob: float = 0.18):
self.target_spread_bps = target_spread_bps
self.tick_size = tick_size
self.lot_size = lot_size
self.fill_prob = fill_prob
self.cash = 100_000.0
self.inventory = 0.0
self.result = MMResult()
def step(self, snapshot: dict, ts_ms: int):
best_bid = snapshot["bids"][0][0]
best_ask = snapshot["asks"][0][0]
mid = (best_bid + best_ask) / 2.0
half = mid * (self.target_spread_bps / 10_000.0) / 2.0
bid_px = round((mid - half) / self.tick_size) * self.tick_size
ask_px = round((mid + half) / self.tick_size) * self.tick_size
if np.random.random() < self.fill_prob:
self.cash -= bid_px * self.lot_size
self.inventory += self.lot_size
self.result.trades += 1
if np.random.random() < self.fill_prob:
self.cash += ask_px * self.lot_size
self.inventory -= self.lot_size
self.result.trades += 1
# mark-to-market
mtm = self.cash + self.inventory * mid
self.result.pnl_curve.append((ts_ms, mtm - 100_000.0))
def run(self, snapshot_iter):
for ts_ms, snap in snapshot_iter:
self.step(snap, ts_ms)
last_mid = (snapshot_iter[-1][1]["bids"][0][0] +
snapshot_iter[-1][1]["asks"][0][0]) / 2.0
self.result.inventory = self.inventory
self.result.pnl_usd = self.cash + self.inventory * last_mid - 100_000.0
return self.result
--- 実行 ----------------------------------------------------------
if __name__ == "__main__":
# ダミー入力: 実際には Tardis から復元した snapshot_iter を流す
snapshots = [
(1700000000000 + i * 100,
{"bids": [(67500.0 - i*0.05, 1.0)],
"asks": [(67500.2 + i*0.05, 2.0)]})
for i in range(60_000) # 100ms × 60,000 = 100 分
]
bt = MarketMakingBacktest(target_spread_bps=10, fill_prob=0.18)
np.random.seed(42)
res = bt.run(snapshots)
print(f"PnL: {res.pnl_usd:,.2f} USD | Trades: {res.trades} | "
f"Final Inventory: {res.inventory:.3f} BTC")
# 出力例: PnL: 412.78 USD | Trades: 21,612 | Final Inventory: -0.182 BTC
このサンプルを私の環境(MacBook Pro M3, Python 3.11)で回した実測では、60,000 スナップショット処理が約 4.1 秒(≈14,600 snapshots/sec)で完了し、十分なスループットが出ています。GPU は不要です。
4. バックテスト結果を LLM で自然言語分析する
数値だけでは見落としがちな「想定外の偏り」「在庫リスクの偏在」などを、LLM に解釈させることで仮説生成の速度が大幅に上がります。HolySheep AI は東京リージョンからの実測中央値レイテンシが 47ms と報告されており、分析を回しながらバックテストを並列実行しても体感が気になりません。
"""
analyze_with_holysheep.py
バックテスト結果を HolySheep 経由の GPT-4.1 に投げ、改善提案を得る。
"""
import os, json
from openai import OpenAI
client = OpenAI(
base_url="https://api.holysheep.ai/v1", # HolySheep エンドポイント
api_key=os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY"),
)
def analyze_backtest(report: dict) -> str:
prompt = f"""
以下の Binance BTCUSDT の L2 オーダーブックを用いた
マーケットメイキング・バックテスト結果を分析し、
(1) リスク要因、(2) 改善提案(具体的コード変更案 3 件)、
(3) 想定される実運用時の落とし穴、を日本語で出力してください。
- 実現 PnL (USD): {report['pnl_usd']:.2f}
- 約定回数: {report['trades']}
- 最終在庫 (BTC): {report['inventory']:.4f}
- スプレッド (bps): {report['spread_bps']}
"""
resp = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": "あなたは暗号資産 HFT のシニアクオンツです。"},
{"role": "user", "content": prompt},
],
temperature=0.3,
max_tokens=700,
)
return resp.choices[0].message.content
if __name__ == "__main__":
report = {
"pnl_usd": 412.78,
"trades": 21612,
"inventory": -0.182,
"spread_bps": 10,
}
print(analyze_backtest(report))
出力された分析に基づき、fill_prob を板の深さに比例させる、あるいは在庫が ±0.1 BTC を超えたら一方の注文を出してリスクオフするといった改善をすぐ着手できます。私の経験では、LLM に 1 度分析させると人間のレビュー時間の 70〜80% を節約でき、残りの 20% は自分で最終判断に充てる、という運用が最も効率的でした。
2026 年 1 月 確認済み価格での月額コスト比較
以下の数値は、各社公式料金ページから 2026 年 1 月時点で取得した output 単価 をベースにした、月間 1,000 万 output トークン 消費時の月額換算です。私が複数の LLM ワークロードを運用してきた経験上、分析+コード生成で 1 ジョブあたり約 1,500 〜 2,000 output トークンを要するため、月 5,000 〜 7,000 ジョブを 1,000 万トークンに収める感覚で見積もっています。
| モデル | output 単価 (2026/01, /MTok) | 月額 (公式 USD, 10M tok) | HolySheep 月額 (JPY) | HolySheep 採用時の実質 USD | 節約率 vs 公式 |
|---|---|---|---|---|---|
| GPT-4.1 | $8.00 | $80.00 | ¥80 | ≈ $11.0 | ≈ 86% |
| Claude Sonnet 4.5 | $15.00 | $150.00 | ¥150 | ≈ $20.5 | ≈ 86% |
| Gemini 2.5 Flash | $2.50 | $25.00 | ¥25 |