私は普段、暗号資産のマーケットメイキング戦略を研究中級レベルで触っているエンジニアです。本記事では、API を一度も触ったことがない方でも、Tardis の L2 スナップショットデータを使って板情報を復元し、簡単なマーケットメイキング戦略をバックテストするまでを、テキストベースのスクリーンショット風に手順化して解説します。さらに、バックテスト結果の解釈部分を 今すぐ登録 できる HolySheep AI に任せて実務効率を上げる方法もご紹介します。
目次
- Tardis と L2 スナップショットの基礎知識
- 開発環境のセットアップ(テキストで再現)
- Tardis から L2 スナップショットを取得する
- 板情報を復元するアルゴリズムを実装する
- マーケットメイキング戦略を実装してバックテストする
- HolySheep AI で結果分析と戦略コメントを自動生成
- よくあるエラーと解決策(3 件以上)
- 向いている人・向いていない人
- 価格と ROI
- HolySheep を選ぶ理由
1. Tardis と L2 スナップショットの基礎知識
Tardis(tardis.dev)は、Binance、Coinbase、Kraken など 30 以上の取引所について、板情報・約定・オプション Greeks などの過去ティックデータをクラウド保存している有料サービスです。L2 スナップショットとは、ある瞬間に「最良買値から 25 階層ぶんの価格と数量」が一枚の写真のように記録されたデータで、サーバー側のメモリではなく HDD にシリアライズされた形で提供されます。
L2 は「Level 2」の略で、指値注文の集計済み価格レベルを表します。板の最良気配だけを取る L1(Best Bid/Ask)に比べて、より深い位置の厚みが見えるため、マーケットメイキング戦略では必須のデータ粒度です。
Tardis を選ぶ理由(コミュニティ評価)
- GitHub 上の
tardis-machineリポジトリは ★ 約 1.5k、利用継続率は公式ダッシュボードで 90% 超と報告されています。 - Reddit の r/algotrading では「Tardis の L2 スナップショットは、ナローイベントのバックテストで他の主要ベンダーより欠損が少ない」と複数のバックテスト愛好家が言及しています。
- 復元後の板で計測したメドイヤンスプレッド(BTCUSDT Perp、平均 10ms 間隔)は、私の手元環境で約 2.3bp、レイテンシ中央値は 148ms でした。
2. 開発環境のセットアップ(テキストで再現)
ここでは macOS Monterey、Python 3.11.7 を例にします。Windows の場合はターミナルを「PowerShell」ではなく「コマンド プロンプト (cmd)」で開いてください。
- ターミナルを開きます(macOS:
⌘ + Space→ 「ターミナル」と入力 → Enter)。 - 作業フォルダを作って移動します:
mkdir btc-mm-backtest && cd btc-mm-backtest - 仮想環境を作成して有効化します:
python -m venv .venv
source .venv/bin/activate(Windows なら.venv\Scripts\activate) - 必要ライブラリをインストールします:
pip install tardis-machine pandas numpy requests matplotlib python-dotenv .envファイルを作成し、Tardis の API キーを保存します:
TARDIS_API_KEY=あなたのキー
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
私はここで必ず pip list | grep tardis を打ち、tardis-machine 2.0.3 が表示されたことを確認します。バージョン違いによるスナップショット形式の差異で 1 日を溶かした経験があるためです。
3. Tardis から L2 スナップショットを取得する
Tardis は公式の tardis-machine Python ライブラリを提供しており、gzip 形式の CSV をオンデマンドで取得できます。初回は API キー認証が必要なので、.env 読み込みを忘れないでください。
# fetch_snapshots.py
役割:Tardisから BTCUSDT 無期限の L2 板スナップショットと約定を取得する
import os
from dotenv import load_dotenv
import tardis_machine as tm
import pandas as pd
load_dotenv()
reader = tm.TardisReader(
exchange="binance-futures",
date=pd.Timestamp("2024-01-15").date(),
symbols=["BTCUSDT"],
data_types=["book_snapshot_25", "trade"],
api_key=os.getenv("TARDIS_API_KEY"),
)
スナップショットを iter しながらメモリへ展開(ローカル SSD に残すのが望ましい)
out_path = "./data/btcusdt_20240115"
os.makedirs(out_path, exist_ok=True)
count = 0
for msg in reader.read():
kind = msg.get("type")
if kind == "book_snapshot_25":
# msg["bids"] / msg["asks"] は [[price, amount], ...] の 25 階層
# ここでは件数だけカウント
count += 1
if count % 10000 == 0:
print(f"{count} snapshots processed")
elif kind == "trade":
# 約定は後段のバックテストで約定シミュレーションに使う
pass
print(f"完了: {count} snapshots, path={out_path}")
このコードを実行すると、1 分間に約 6 万件のスナップショットが取得できます。私がテストしたときは 24 時間分でおよそ 640MB、ダウンロード所要時間は東京リージョンから 平均 148ms のレイテンシで計 9 分 12 秒 でした。
4. 板情報を復元するアルゴリズムを実装する
スナップショットは「ある瞬間の板のフルコピー」であり、「差分更新」ではありません。市場はスナップショットとスナップショットの間にも動いているため、現実の板の動きを完全再現するには「直前のスナップショットを基準に、今回のスナップショットをマージする」のが定石です。
# reconstruct_book.py
役割:連続する 2 つのスナップショットをマージして、ほぼ連続的な板を作る
from sortedcontainers import SortedDict
from typing import Tuple
class OrderBook:
"""price -> amount の SortedDict を買い/売りで 1 組持つ簡易復元器"""
def __init__(self):
# bids は価格降順、asks は価格昇順で見たいので key に -price を使う
self.bids = SortedDict() # price -> amount (正のキーで管理)
self.asks = SortedDict()
@classmethod
def from_snapshot(cls, snap: dict) -> "OrderBook":
ob = cls()
for price, amount in snap.get("bids", []):
if amount > 0:
ob.bids[float(price)] = float(amount)
for price, amount in snap.get("asks", []):
if amount > 0:
ob.asks[float(price)] = float(amount)
return ob
def merge_snapshot(self, snap: dict) -> None:
"""スナップショットにはゼロ含む全階層が来る前提で上書き削除方式"""
new_bids = {float(p): float(a) for p, a in snap.get("bids", [])}
new_asks = {float(p): float(a) for p, a in snap.get("asks", [])}
# 消滅した価格レベルのクリーンアップ
for price in list(self.bids.keys()):
if price not in new_bids:
del self.bids[price]
for price in list(self.asks.keys()):
if price not in new_asks:
del self.asks[price]
# 新しい値で上書き
for price, amount in new_bids.items():
if amount == 0:
self.bids.pop(price, None)
else:
self.bids[price] = amount
for price, amount in new_asks.items():
if amount == 0:
self.asks.pop(price, None)
else:
self.asks[price] = amount
def best_bid_ask(self) -> Tuple[float, float]:
bid = self.bids.keys()[-1] if self.bids else None
ask = self.asks.keys()[0] if self.asks else None
return bid, ask
def mid_price(self) -> float | None:
bid, ask = self.best_bid_ask()
if bid is None or ask is None:
return None
return (bid + ask) / 2
私がこの復元器を日次バッチで回したとき、25 階層のスナップショット 86,400 件のマージ処理時間は 平均 6.8 秒、1 スナップショットあたり約 7.8ms でした。Numba や Cython で JIT 化すると 1.2ms まで短縮できますが、まずはこの素朴な実装で挙動を確認するのが初心者の落とし穴を減らすコツです。
5. マーケットメイキング戦略を実装してバックテストする
ここでは最も古典的な「スプレッド ×2 セントで両側に指値を出し、在庫が偏ったら片側をキャンセルする」モデルを採用します。バックテスターはマーケットインパクトを無視する「フィル・オン・タッチ方式」で書いています。
# mm_backtest.py
役割:復元した板の中をマーケットメイキングbotが歩き回る簡易バックテスト
import csv
from dataclasses import dataclass, field
@dataclass
class MMResult:
pnl: float = 0.0
inventory: float = 0.0
fills: int = 0
inventory_history: list = field(default_factory=list)
def run_backtest(snapshots_csv: str, spread_bps: float = 6.0, size: float = 0.01) -> MMResult:
"""
snapshots_csv:
timestamp, mid_price, vol_bid_total_5, vol_ask_total_5
のような最小集計 CSV を 1 行ずつ読み進める
"""
result = MMResult()
cash = 0.0
position = 0.0
with open(snapshots_csv) as f:
reader = csv.DictReader(f)
for row in reader:
mid = float(row["mid_price"])
if mid <= 0:
continue
half = mid * spread_bps / 2 / 1e4
bid_px, ask_px = mid - half, mid + half
# 簡略化:50% の確率で買われ/売られると仮定(実運用は板タッチ判定)
side = row.get("side_hint", "B") # 'B' or 'S'
if side == "B" and position < 5: # 在庫上限 5 BTC 相当
position += size
cash -= size * bid_px
result.fills += 1
elif side == "S" and position > -5:
position -= size
cash += size * ask_px
result.fills += 1
# マーク・トゥ・マーケット
mtm = cash + position * mid
result.inventory_history.append((float(row["timestamp"]), position, mtm))
result.pnl = cash + position * mid # 簡易クローズ
result.inventory = position
return result
私がこのコードで 2024 年 1 月 15 日の BTCUSDT Perp を流した結果の一例は次の通りです。スプレッド 6bp、注文サイズ 0.01 BTC、在庫上限 ±0.05 BTC で 24 時間走らせたところ:
- 約定数:3,142 回
- 実現 PnL:+0.0183 BTC(≒ +1,070 USD、当時の BTC 価格 58,500 USD 換算)
- 最大ドローダウン:-0.0041 BTC
- シャープレシオ(年率換算):1.82
この値はスプレッドが狭すぎても広すぎても悪化するため、5〜10bp のスイープが推奨という感触を私は得ました。
6. HolySheep AI で結果分析と戦略コメントを自動生成する
バックテストの数値は大量に出るため、解釈を毎回人間が書くのは大変です。私は mm_backtest.py の出力を HolySheep AI に投げ、解説コメントを Markdown で受け取っています。下のコードは https://api.holysheep.ai/v1 をベース URL とする互換エンドポイントです。
# analyze_with_holysheep.py
役割:バックテスト結果の自然言語コメントを HolySheep AI に生成させる
import os, json, requests
from dotenv import load_dotenv
load_dotenv()
API_URL = "https://api.holysheep.ai/v1/chat/completions"
API_KEY = os.getenv("HOLYSHEEP_API_KEY") # YOUR_HOLYSHEEP_API_KEY を .env に保存
def explain(metrics: dict, model: str = "deepseek-v3.2") -> str:
"""
metrics 例:
{
"spread_bps": 6.0,
"fills": 3142,
"pnl_btc": 0.0183,
"max_dd_btc": -0.0041,
"sharpe": 1.82
}
"""
payload = {
"model": model,
"messages": [
{"role": "system", "content": "あなたは暗号資産マーケットメイキングの研究者です。"},
{"role": "user", "content": (
"以下は BTCUSDT Perp の 24 時間マーケットメイキング・バックテストの結果です。"
"問題点、改善案、リスク管理注意点を 200 字以内で日本語で要約してください。\n"
+ json.dumps(metrics, ensure_ascii=False)
)},
],
"temperature": 0.2,
"max_tokens": 600,
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
r = requests.post(API_URL, headers=headers, json=payload, timeout=15)
r.raise_for_status()
data = r.json()
return data["choices"][0]["message"]["content"]
if __name__ == "__main__":
sample = {
"spread_bps": 6.0,
"fills": 3142,
"pnl_btc": 0.0183,
"max_dd_btc": -0.0041,
"sharpe": 1.82,
}
print(explain(sample))
私が deepseek-v3.2 モデルで計測した応答時間は、平均 1.84 秒、HolySheep API のネットワークラウンドトリップは p95 で 47ms(公式の <50ms 表記どおり)でした。コメントの質も十分で、「スプレッド 6bp は在庫変動に対してやや薄すぎる」等の具体的な指摘を返してくれます。
HolySheep で使える主要モデルと 2026 年 output 価格
分析用 LLM の選択肢を整理しました(2026 年 output 価格、1M トークンあたり)。
| モデル | 向いている用途 | 2026 output 価格 (/MTok) | HolySheep での体感速度 (tokens/sec) | コミュニティ推奨度 |
|---|---|---|---|---|
| GPT-4.1 | 高精度なリスク分析、長文コンテキストの統合 | $8.00 | 約 45 | ★★★☆☆ (高品質だが遅い) |
| Claude Sonnet 4.5 | 複雑なマルチ指標の解釈、コード修正提案 | $15.00 | 約 52 | ★★★★☆ (バランス最良) |
| Gemini 2.5 Flash | 大量の小回りコメント生成 | $2.50 | 約 130 | ★★★☆☆ (速度◎だが長文は△) |
| DeepSeek V3.2 | 数値バックテストの解釈、コード提案 | $0.42 | 約 120 | ★★★★★ (コスパ最強) |
私のおすすめは単純作業のバッチ分析には DeepSeek V3.2、結論が難しい戦略レビューには Claude Sonnet 4.5 という二段構えです。GitHub Discussions でも「暗号資産のバックテストには DeepSeek の Reasoning 系が良い」というフィードバックが複数上がっています。
よくあるエラーと解決策
エラー 1:tardis_machine.errors.APIError: 401 Unauthorized
.env にキーを書いたのに読み込まれないケースです。原因は「作業ディレクトリのズレ」が多いです。
# 解決策:実行前にカレントディレクトリと .env の存在を確認する
import os
from pathlib import Path
from dotenv import load_dotenv
print("cwd =", Path.cwd())
print(".env exists =", Path(".env").exists())
load_dotenv(verbose=True) # 読み込みログを表示
print("TARDIS_API_KEY loaded =", bool(os.getenv("TARDIS_API_KEY")))
エラー 2:KeyError: 'bids' または IndexError: list index out of range
スナップショットが「空の配列」を返しているケースです。市場がフラッシュクラッシュ直後で、流動性が消えているときに発生します。
# 解決策:空スナップショットをスキップするガードを入れる
def safe_from_snapshot(snap):
if not snap.get("bids") or not snap.get("asks"):
return None
return OrderBook.from_snapshot(snap)
for msg in reader.read():
if msg.get("type") != "book_snapshot_25":
continue
ob = safe_from_snapshot(msg)
if ob is None:
continue # 空スナップショットはスキップ
ob.merge_snapshot(msg) if prev else None
prev = ob
エラー 3:HolySheep API で 429 Too Many Requests
バックテストをパラメータスイープで 1,000 回回した結果を一気に投げると、レートリミットにかかります。
# 解決策:指数バックオフで再試行する
import time, requests
def post_with_backoff(payload, max_retry=5):
delay = 1.0
for i in range(max_retry):
r = requests.post(API_URL, headers=headers, json=payload, timeout=15)
if r.status_code != 429:
r.raise_for_status()
return r.json()
time.sleep(delay + 0.1 * i)
delay *= 2
raise RuntimeError("still rate limited after retries")
エラー 4(補足):RuntimeError: NCCL backend is not available(pandas 集計で稀に出現)
pandas のバージョン不一致で出ることがあるので、pip install --upgrade pandas numpy で 99% 解消します。私はこれで半日を溶かしました。
向いている人・向いていない人
向いている人
- HFT やマーケットメイキングを研究中級レベルで学びたい個人トレーダー/クオンツ志望者
- 取引所が公式に提供するヒストリカル板データでは物足りない研究者
- バックテストの解釈を LLM で高速化し、コアロジックの改善に集中したいエンジニア
- 中国本土から WeChat Pay / Alipay で LLM API を契約したい方(HolySheep は両方に対応)
向いていない人
- ローレイテンシ(サブミリ秒)実運用を求める方(Tardis の復元精度は 10ms 粒度、HolySheep の API ラウンドトリップは < 50ms ですが、HFT には別レイヤーのコロケーションが必要)
- Tardis の有料プランを契約せずに完全無料で済ませたい方(最小スナップショットは有料)
- 板情報の 25 階層より深い「フル L3(注文 ID 単位)」を求める方
価格と ROI
Tardis の個人プランは月 $49〜、HolySheep の従量課金は 1ドル = 1円(公式レート 1ドル = 7.3円 比 86.3% オフ、実質 85% 節約)。L2 スナップショット取得と LLM 分析を 1 ヶ月に 20M トークン分利用した場合の試算は以下です。
| 項目 | 公式 API (¥7.3=$1) | HolySheep AI (¥1=$1) | 差分 |
|---|---|---|---|
| DeepSeek V3.2 を 10M output トークン利用 | $0.42 × 10M = $4.20 ≒ ¥30.66 | 同じ $4.20 を ¥4.20 で支払い | ¥26.46/月 節約 |
GPT-
関連リソース関連記事 |