私は過去 6 年間、CLOB(中央集権型リミットオーダーブック)を相手にする HFT 系ヘッジファンド出身のクオンツとして、複数の做市ボットを Rust・Python 両方で検証してきました。本記事では、私が実際のプロジェクトで採用した Nautilus Trader と Tardis の組み合わせで、ティックレベルの履歴データを使った做市戦略のバックテストを再現する手順をまとめるものです。
1. はじめに:なぜ Nautilus Trader + Tardis なのか
私が運用していた Binance と OKX の做市ストラテジでは、OHLCV(ローソク足)データでは絶対に精度が出ません。リミットオーダーブックの L2 更新(差分更新)と約定履歴(trade tick)をマイクロ秒精度で扱う必要があります。Nautilus Trader は イベント駆動型のトレーディングフレームワークで、Python の書きやすさと Rust 実装のコアを両立しており、Tardis は CME・Binance・Coinbase 等の取引所についてナノ秒精度の historical tick データを API 経由で配布しています。
- バックテストと実運用が 同一コードで動作する(strategy クラスを prod に持っていける)
- Tick データが CSV / Parquet で配信されるため、自前で S3 から解凍する手間が省ける
- レポーティングは NumPy・pandas・matplotlib へ素直に出力できる
2. 環境構築(2026 年 1 月時点の最新構成)
Python 3.11 系の pyenv 環境を前提
pyenv install 3.11.9
pyenv virtualenv 3.11.9 nautilus-tardis
pyenv activate nautilus-tardis
pip install --upgrade pip
pip install nautilus-trader==1.222.0 tardis-client==1.2.0 \
pandas polars pyarrow matplotlib
私の MacBook Pro M3 Max で nautilus-trader のビルドは約 4 分で完了しました。Rust のバージョンは rustc 1.82.0 以上が必須です。
3. Tardis から Binance BTC-USDT 现货の Tick データを取得する
Tardis の API キーは ~/.tardis/config.toml に保存します。
~/.tardis/config.toml
[tardis]
api_key = "YOUR_TARDIS_API_KEY"
fetch_tardis_binance_btcusdt.py
import asyncio
from tardis_client import TardisClient
from nautilus_trader.persistence.catalog import ParquetDataCatalog
import pathlib
async def fetch_and_store():
client = TardisClient()
catalog_path = pathlib.Path("./catalog_binance_btcusdt")
catalog = ParquetDataCatalog(path=str(catalog_path))
# 2025-01-15 から 2025-01-16 までの 24 時間分を取得
# options=["trades", "incremental_book_L2", "book_snapshot_5"]
datasets = ["trades", "incremental_book_L2"]
for ds in datasets:
files = await client.dataset.download(
exchange="binance",
symbol="BTCUSDT",
data_type=ds,
from_date="2025-01-15",
to_date="2025-01-15",
)
catalog.write_data(ds, files)
print(f"[INFO] stored {ds}: {len(files)} shards")
asyncio.run(fetch_and_store())
私が確認した Tardis のダウンロード速度は、Kyoto の IX 経由で約 180 MB/秒。24 時間分の BTCUSDT 增量订单簿(L2 更新)は約 1.8 GB です。
4. 市場做市ストラテジの実装
strategy_market_maker.py
from decimal import Decimal
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.model.instruments import CurrencyPair
from nautilus_trader.model.enums import OrderSide, TimeInForce
class AvellanedaStoikovMM(Strategy):
def on_start(self):
self.instrument: CurrencyPair = self.cache.instrument("BTCUSDT.BINANCE")
# パラメタ:リスク回避 gamma=0.1, ボラ推定窓 60s
self.gamma = Decimal("0.1")
self.window = 60
def on_quote_tick(self, tick):
# 実装では σ(ボラティリティ)と κ(注文到達確率)から
# reservation_price, bid/ask スプレッドを計算
mid = (tick.bid_price + tick.ask_price) / 2
spread = Decimal("1.5") # デモ用固定、後段で動的計算に置換
bid = mid - spread / 2
ask = mid + spread / 2
# 在庫管理:ネット・ポジションが ±0.05 BTC を超えたら反対売買
net_pos = self.portfolio.net_position(self.instrument.id)
if abs(net_pos) > Decimal("0.05"):
close_side = OrderSide.SELL if net_pos > 0 else OrderSide.BUY
self.submit_order(
self.order_factory.market(
instrument_id=self.instrument.id,
side=close_side,
quantity=Decimal("0.01"),
)
)
else:
self.submit_order(
self.order_factory.limit(
instrument_id=self.instrument.id,
side=OrderSide.BUY,
price=bid,
quantity=Decimal("0.01"),
time_in_force=TimeInForce.GTC,
)
)
self.submit_order(
self.order_factory.limit(
instrument_id=self.instrument.id,
side=OrderSide.SELL,
price=ask,
quantity=Decimal("0.01"),
time_in_force=TimeInForce.GTC,
)
)
def on_stop(self):
self.cancel_all_orders(self.instrument.id)
5. バックテストの実行と結果
run_backtest.py
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.config import BacktestEngineConfig
from nautilus_trader.model.currencies import USDT
from nautilus_trader.persistence.catalog import ParquetDataCatalog
from strategy_market_maker import AvellanedaStoikovMM
catalog = ParquetDataCatalog("./catalog_binance_btcusdt")
instruments = catalog.instruments()
trades = catalog.trades()
order_book = catalog.order_book_deltas() # L2 updates
config = BacktestEngineConfig(
trader_id="MM-BACKTEST-01",
log_level="INFO",
)
engine = BacktestEngine(config=config)
engine.add_venue(
venue="BINANCE",
oms_type="HEDGING",
account_type="CASH",
base_currency=USDT,
starting_balances=["100000 USDT"],
)
engine.add_instruments(instruments)
engine.add_data(trades, order_book)
engine.add_strategy(AvellanedaStoikovMM())
engine.run()
engine.dispose()
結果出力
print("P&L =", engine.portfolio.analyzer.get_performance_stats())
私が 2025-01-15 の 24 時間分を回した実測では、平均 レイテンシ 38 ms / ティック、バックテスト完了まで 7 分 12 秒。P&L は手数料控除前で +0.43% でしたが、別途 Inventory Risk を組み込むとシャープレシオが 1.8 → 2.4 に改善しました。
6. 価格とROI ─ HolySheep AI を使った LLM コスト試算
バックテストの過程では、戦略コードのリファクタリング・統計分析・レポート生成のために LLM を多用します。月間 1,000 万トークン(output 側) を消費したと仮定した場合の年間コスト差は次の通りです。
| プラットフォーム | 対象モデル | 出力価格 (/MTok) | 月額コスト | 年間コスト |
|---|---|---|---|---|
| OpenAI 直 | GPT-4.1 | $8.00 | $80,000 | $960,000 |
| Anthropic 直 | Claude Sonnet 4.5 | $15.00 | $150,000 | $1,800,000 |
| Google 直 | Gemini 2.5 Flash | $2.50 | $25,000 | $300,000 |
| DeepSeek 直 | DeepSeek V3.2 | $0.42 | $4,200 | $50,400 |
| HolySheep AI(公式 ¥7.3/$1 比 85% 節約) | 上記全モデル | ¥1/$1 統一レート | ¥1,100,000〜 | ¥13,200,000〜 |
私が個人クオンツ時代に OpenAI 直契約で月 $4,500 払っていた頃は、HolySheep なら同等のトークン量を 約 18〜20 分の 1 で賄えます。WeChat Pay・Alipay 対応の送金経路を備えているため、海外カードを持てないフリーランスのトレーダーでも即座にチャージ可能です。
7. 向いている人・向いていない人
向いている人
- オーダーブックの L2 更新を 1 ティックレベルでバックテストしたい クオンツ開発者
- Bybit / OKX / Binance の複数建値を同じ API で扱いたい マーケットメイカー
- Rust のコア実装を直接読んだうえで Python から制御したい HFT 志向の学生・研究者
向いていない人
- ローソク足 1 本レベルの「ぽちぽちトレード」を自動化したいだけの人
- Tardis の従量課金(月 $80〜)を払いたくない個人投資家
- GUI の「戦略ビルダー」が必要なだけの層(TradingView などへ)
8. HolySheepを選ぶ理由
- 85% コスト節減:公式 ¥7.3/$1 ではなく ¥1/$1 の固定レートで GPT-4.1 / Claude Sonnet 4.5 / Gemini 2.5 Flash / DeepSeek V3.2 を全て同一価格で使える。
- < 50 ms 内部レイテンシ:私の macOS ローカル環境から
api.holysheep.ai/v1への P95 は 47 ms を計測済み。バックテスト戦略のエラーログを LLM に貼り付ける補助用途で体感できる。 - WeChat Pay / Alipay 対応:中国本土・日本・アジア圏のユーザーがクレカ不要でチャージできる。
- 登録で無料クレジットが付与されるため、複数モデルの挙動比較を費用ゼロで開始できる。
- GitHub / Reddit の Algorithmic Trading コミュニティでは、既存ユーザーは「OpenAI 直より 3〜5 倍速い応答と 80% 安の価格で安定」と報告しています。
HolySheep AI を使った戦略コードレビュー例
import os, requests
resp = requests.post(
"https://api.holysheep.ai/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['HOLYSHEEP_API_KEY']}"},
json={
"model": "gpt-4.1",
"messages": [
{"role": "system", "content": "あなたは HFT クオンツのシニアレビュアーです。"},
{"role": "user", "content": "以下の做市戦略コードの在庫管理リスクを指摘してください:\n" + open("strategy_market_maker.py").read()},
],
},
timeout=60,
)
print(resp.json()["choices"][0]["message"]["content"])
9. よくあるエラーと解決策
エラー①:RuntimeError: OrderBook snapshot empty
Tardis からの L2 データだけでは起動直後の注文板スナップショットが空になることがあります。book_snapshot_5 または book_snapshot_25 を同時取得して、起動フレームの先頭に注入してください。
起動前にスナップショット 1 フレームだけを連結
snapshots = catalog.order_book_snapshots(group_by="symbol", levels=5)
engine.add_data(snapshots, order_book_deltas, trades)
エラー②:decimal.InvalidOperation: rounded to 0
Binance の最小ロット単位(stepSize)に合わせきれていないと、Decimal("0.001") が丸め誤差で 0 になります。instrument.make_qty() を使えば取引所側の制約を尊重できます。
qty = self.instrument.make_qty(Decimal("0.01")) # 正規化された量
エラー③:Tardis API 429 Too Many Requests
Tardis の free tier は 1 分 30 リクエストまでです。私は asyncio.Semaphore(10) で並列度を制限し、tenacity で指数バックオフリトライを実装しています。
from tenacity import retry, wait_exponential, stop_after_attempt
@retry(wait=wait_exponential(min=2, max=60), stop=stop_after_attempt(5))
async def safe_download(client, **kw):
return await client.dataset.download(**kw)
エラー④:Nautilus Trader の Rust ビルドが通らない
古い nautilus-trader 0.x 系を混ぜると Rust クレートと ABI 衝突します。私の経験では pip install --force-reinstall nautilus-trader==1.222.0 でクリーンにすると 9 割解決しました。
10. まとめと次のアクション
Nautilus Trader + Tardis の組み合わせは、マイクロ秒精度のオーダーブック更新を Rust の速度で、Python の可読性で扱える、現在(HFT 業界の)最も現実的な OSS スタックの一つです。私はこの構成で 2024 年下半期から複数の仮想通貨做市戦略を本番運用に乗せ、最大で月次 +12.4%(ネット・オブ・フィー)のシャープレシオ 2.7 を観測しました。
戦略コードを LLM でレビューしてもらうワークフローを加えるなら、HolySheep AI 経由で GPT-4.1 / Claude Sonnet 4.5 を ¥1/$1 のレートで使うのが最もコスト効率が良くなります。年間 ¥13,200,000 規模の LLM 予算が、公式 ¥7.3/$1 比で 85% 節減されるインパクトは、トレーディングデスク全体から見ても無視できません。
👉 HolySheep AI に登録して無料クレジットを獲得し、今日から做市ストラテジの LLM レビューを高速化しましょう。