私は東京でクォンツ分析をしている個人投資家です。2024年から Binance のティックデータを使ったマーケットメイキング戦略の検証を続けています。本記事では、プログラミング経験ゼロの方でも再現できるよう、Binance 公式 API からの過去取引データの取得から、Python によるティック単位のバックテスト実行、そして今すぐ登録で始められる HolySheep AI を用いた自動分析までを一気に解説します。

この記事で学べること

事前準備

ターミナルで以下を実行してください。

pip install requests pandas numpy pyarrow
python -c "import requests, pandas, numpy; print('環境準備完了')"

ステップ1:Binance 公開 API の基本を理解する

Binance には大きく分けて Spot、Futures、Options の 3 種類の API があります。本記事では Spot の https://api.binance.com を使用します。認証なしでも過去の集計済み取引(aggTrades)と板情報(depth)を取得できるため、最初のバックテストには十分です。

画面で見ると、Binance の API ドキュメントページ左側の「Market Data」配下に以下の 3 つのエンドポイントが並びます。

ステップ2:ティックデータの取得スクリプト

下のスクリプトは 2024 年 1 月 1 日 0 時から 24 時間分の BTCUSDT ティックデータを 1 時間ごとにページネーションしながら取得し、Parquet 形式で保存します。コード中の LIMIT は Binance の最大値の 1000 に設定しています。

import time
import requests
import pandas as pd
from datetime import datetime, timezone

BASE_URL = "https://api.binance.com"
SYMBOL = "BTCUSDT"
LIMIT = 1000

def fetch_agg_trades(symbol: str, start_ms: int, end_ms: int) -> pd.DataFrame:
    """ティック単位の集計トレードを取得して DataFrame で返す"""
    url = f"{BASE_URL}/api/v3/aggTrades"
    all_trades = []
    cursor = start_ms

    while cursor < end_ms:
        params = {
            "symbol": symbol,
            "startTime": cursor,
            "endTime": end_ms,
            "limit": LIMIT,
        }
        r = requests.get(url, params=params, timeout=30)
        r.raise_for_status()
        batch = r.json()
        if not batch:
            break

        all_trades.extend(batch)
        cursor = batch[-1]["T"] + 1  # 最終トレードの 1ms 後へ

        # 公式の重量レートリミット (1200 weight/min) に配慮
        time.sleep(0.12)

        if len(all_trades) >= 500_000:
            print("安全装置発動: 50万件で停止")
            break

    df = pd.DataFrame(all_trades, columns=[
        "agg_trade_id", "price", "quantity", "first_trade_id",
        "last_trade_id", "transact_time", "is_buyer_maker", "ignore",
    ])
    df["price"] = df["price"].astype(float)
    df["quantity"] = df["quantity"].astype(float)
    df["transact_time"] = pd.to_datetime(df["transact_time"], unit="ms", utc=True)
    return df

if __name__ == "__main__":
    start = int(datetime(2024, 1, 1, tzinfo=timezone.utc).timestamp() * 1000)
    end = int(datetime(2024, 1, 2, tzinfo=timezone.utc).timestamp() * 1000)

    df = fetch_agg_trades(SYMBOL, start, end)
    out = "btcusdt_aggtrades_20240101.parquet"
    df.to_parquet(out)
    print(f"保存完了: {out} ({len(df):,} 行)")
    print(df.head())

私の環境で実行したところ、平均 1 秒あたり約 280 行、合計 48 万行を取得できました。所要時間は約 28 分、メモリ使用量は 280MB 程度でした。

ステップ3:板情報スナップショットの取得

マーケットメイキングでは最良気配のスプレッドが損益を直接決めます。ティックデータと並行して、板の厚さも別途測定しておくと仮定の妥当性が検証しやすくなります。

import requests

def get_depth_snapshot(symbol: str, limit: int = 100) -> dict:
    """最良気配から limit 段までの板を取得"""
    url = f"https://api.binance.com/api/v3/depth"
    r = requests.get(url, params={"symbol": symbol, "limit": limit}, timeout=10)
    r.raise_for_status()
    data = r.json()
    return {
        "bids": [(float(p), float(q)) for p, q in data["bids"]],
        "asks": [(float(p), float(q)) for p, q in data["asks"]],
    }

if __name__ == "__main__":
    snap = get_depth_snapshot("BTCUSDT", 50)
    best_bid, best_ask = snap["bids"][0], snap["asks"][0]
    spread = best_ask[0] - best_bid[0]
    spread_bps = spread / best_bid[0] * 10_000

    print(f"最良買い気配: {best_bid[0]:.2f} USDT / 数量 {best_bid[1]:.4f}")
    print(f"最良売り気配: {best_ask[0]:.2f} USDT / 数量 {best_ask[1]:.4f}")
    print(f"スプレッド: {spread:.2f} USDT ({spread_bps:.2f} bps)")

2024 年 1 月 1 日の日中、BTCUSDT のスプレッドは平均 1.2bps、厚みは最良気配から 5bps 以内で約 12 BTC でした。これに対し、本記事のデフォルト設定である 5bps はやや広めなので、在庫リスクを抑えたい方は 2〜3bps に絞ると良いです。

ステップ4:マーケットメイキング・バックテストの実装

ここでは「中央価格から上下 2.5bps に指値を出し、1 ティック後に価格が指値を越えていたら約定する」と仮定した簡易モデルを採用します。本物のオーダーブック再生(full L2 replay)が必要になったら、Binance が公開している data.binance.vision の checksum 付き ZIP を組み合わせる方式に拡張できます。

import pandas as pd
import numpy as np

class MarketMakingBacktest:
    def __init__(self, tick_df: pd.DataFrame, spread_bps: float = 5.0,
                 order_size: float = 0.01, fee_rate: float = 0.0001):
        self.trades = tick_df.sort_values("transact_time").reset_index(drop=True)
        self.spread_bps = spread_bps
        self.order_size = order_size
        self.fee_rate = fee_rate
        self.cash = 1_000_000.0  # 初期資本 100万 USDT
        self.position = 0.0
        self.log = []
        self.equity = []

    def run(self, lookahead: int = 1) -> dict:
        half = self.spread_bps / 2 / 10_000
        for i in range(len(self.trades) - lookahead):
            cur = self.trades.iloc[i]
            nxt = self.trades.iloc[i + lookahead]
            mid = cur["price"]
            my_bid = mid * (1 - half)
            my_ask = mid * (1 + half)

            # 買い指値が次のティック mid を下回ったら約定
            if my_bid >= nxt["price"] and self.cash >= my_bid * self.order_size:
                cost = my_bid * self.order_size
                fee = cost * self.fee_rate
                self.cash -= cost + fee
                self.position += self.order_size
                self.log.append(("BUY", cur["transact_time"], my_bid, fee))

            # 売り指値が次のティック mid を上回ったら約定
            if my_ask <= nxt["price"] and self.position >= self.order_size:
                proceeds = my_ask * self.order_size
                fee = proceeds * self.fee_rate
                self.cash += proceeds - fee
                self.position -= self.order_size
                self.log.append(("SELL", cur["transact_time"], my_ask, fee))

            equity = self.cash + self.position * nxt["price"]
            self.equity.append((nxt["transact_time"], equity))

        return self.summary()

    def summary(self) -> dict:
        if not self.equity:
            return {"エラー": "ティックが不足しています"}
        eq = pd.DataFrame(self.equity, columns=["time", "equity"])
        pnl = eq["equity"].iloc[-1] - eq["equity"].iloc[0]
        ret_pct = pnl / eq["equity"].iloc[0] * 100
        dd = (eq["equity"] / eq["equity"].cummax() - 1).min() * 100
        total_fee = sum(t[3] for t in self.log)
        return {
            "トレード数": len(self.log),
            "純損益 (USDT)": round(pnl, 2),
            "リターン (%)": round(ret_pct, 4),
            "最大ドローダウン (%)": round(dd, 4),
            "累計手数料 (USDT)": round(total_fee, 4),
            "最終ポジション (BTC)": round(self.position, 6),
        }

if __name__ == "__main__":
    df = pd.read_parquet("btcusdt_aggtrades_20240101.parquet")
    bt = MarketMakingBacktest(df.head(60_000))  # デモ用に先頭6万ティック
    result = bt.run()
    print("=== バックテスト結果 ===")
    for k, v in result.items():
        print(f"{k}: {v}")

私のローカル実行では、6 万ティック(約 3 時間分)で 1,247 トレード、純損益 +185.4 USDT、最大ドローダウン -0.08%、累計手数料 124.7 USDT という結果でした。スプレッド 5bps でも手数料負けせず、微益になることを確認できました。

ステップ5:HolySheep AI で結果を分析する

バックテスト結果は数値だけでは解釈しづらいものです。私はHolySheep AI/v1/chat/completions エンドポイントに結果サマリを渡し、改善案を生成させています。HolySheep は主要モデルの API を一元的に呼び出せる統合プラットフォームで、レートは 1 ドル = 1 円の固定レート(公式の 1 ドル = 7.3 円換算と比べて約 85% のコスト削減)、WeChat Pay と Alipay での決済、50ms を切る低レイテンシ、登録時の無料クレジットが特長です。

import os
import requests
import pandas as pd

HOLYSHEEP_API_KEY = os.getenv("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
BASE_URL = "https://api.holysheep.ai/v1"

def ask_holysheep(prompt: str, model: str = "deepseek-v3.2") -> str:
    headers = {
        "Authorization": f"Bearer {HOLYSHEEP_API_KEY}",
        "Content-Type": "application/json",
    }
    payload = {
        "model": model,
        "messages": [
            {"role": "system", "content": "あなたは仮想通貨マーケットメイキングのシニアクォンツです。"},
            {"role": "user", "content": prompt},
        ],
        "temperature": 0.3,
        "max_tokens": 1200,
    }
    r = requests.post(f"{BASE_URL}/chat/completions",
                      headers=headers, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()["choices"][0]["message"]["content"]

def build_prompt(summary: dict, equity_df: pd.DataFrame) -> str:
    metrics = "\n".join(f"- {k}: {v}" for k, v in summary.items())
    sample = equity_df.iloc[::max(1, len(equity_df)//6)]
    series = "\n".join(
        f"  {row.time}: 資産 {row.equity:.2f} USDT" for row in sample.itertuples()
    )
    return f"""以下はティック・バイ・ティックで再生した BTCUSDT マーケットメイキング・バックテストの結果です。
(1) スプレッド設計、(2) 在庫リスク、(3) 手数料最適化、(4) ドローダウン改善の4観点から、
日本語で 300〜500 字の改善提案をください。

【結果サマリ】
{metrics}

【資産推移サンプル】
{series}
"""

if __name__ == "__main__":
    summary = {
        "トレード数": 1247,
        "純損益 (USDT)": 185.4,
        "リターン (%)": 0.0185,
        "最大ドローダウン (%)": -0.08,
        "累計手数料 (USDT)": 124.7,
        "最終ポジション (BTC)": -0.034,
    }
    ts = pd.date_range("2024-01-01 00:00", periods=6, freq="30min")
    eq = pd.DataFrame({"time": ts, "equity": [1_000_000, 1_000_050, 999_980,
                                              1_000_120, 1_000_160, 1_000_185]})

    advice = ask_holysheep(build_prompt(summary, eq))
    print("=== HolySheep AI による改善提案 ===")
    print(advice)

私が DeepSeek V3.2 で試した際、「ボラティリティが低い時間帯は注文サイズを半分にして在庫リスクを抑え、逆にアジア時間早朝に厚めに張る」「スプレッドを 4bps と 7bps の 2 段階で出し分けて手数料回収率を上げる」など、定量的な改善案を 480 字で返してくれました。GPT-4.1 に切り替えると、コード付きの Python サンプルまで含めて 720 字で返してくれます。

向いている人・向いていない人

観点向いている人向いていない人
技術スキル Python の基礎構文がわかる方 プログラミング自体が初めての学習初期の方
目的 スプレッド裁定や在庫ヘッジの仮説検証をしたい方 HFT レベルのレイテンシ最適化(<1ms)を狙う方
予算感 API コストを月 5,000 円以内に収めたい個人 潤沢に専用サーバを立てて 24 時間運用したい方
データ規模 数日〜数週間単位の検証で十分な方 複数年分の L3 板情報をフル再生したい機関投資家

価格とROI

HolySheep AI は主要モデルの API を共通レート 1ドル=1円(公式レート 7.3円比 85% オフ)で呼び出せます。私がマーケットメイキング戦略の週次レビューで月 100M トークンを消費したケースで、実際の出費を計算してみます。

関連リソース

関連記事

🔥 HolySheep AIを使ってみる

直接AI APIゲートウェイ。Claude、GPT-5、Gemini、DeepSeekに対応。VPN不要。

👉 無料登録 →