入門

スリッページとは?板が薄いとボットの約定価格がズレる理由


※本記事にはアフィリエイト広告(プロモーション)が含まれています。

バックテストでは安定して勝っていたはずの戦略が、実運用に切り替えた途端に成績が悪化する——ボット開発をしていると一度は経験する悩みです。原因はいくつも考えられますが、見落とされがちなのが「スリッページ」です。この記事では、スリッページがなぜ起きるのか、板が薄いと何が問題になるのかを整理します。

スリッページとは何か

スリッページとは、注文を出したときに想定していた価格と、実際に約定した価格のズレのことです。たとえば「700万円で買えるはず」と思って成行注文を出したのに、実際には700万3000円で約定してしまった、というような現象を指します。

このズレは偶然のノイズではなく、注文方式と板(オーダーブック)の構造から必然的に発生するものです。板の仕組み自体については板情報の読み方の記事で整理しているので、先に読んでおくと理解しやすくなります。

なぜ板が薄いとスリッページが起きるのか

成行注文は「今出ている板を、良い価格から順番に食っていく」形で約定します。板には価格ごとに「この価格ならこれだけ売りたい(買いたい)」という数量が並んでいますが、その数量には限りがあります。

たとえば買いの成行注文を出す場合、次のように約定が進みます。

  1. 最も安い売り注文の数量をまず消費する
  2. その価格の数量で足りなければ、次に安い価格の売り注文を消費する
  3. これを注文数量がすべて約定するまで繰り返す

板が厚い(各価格帯の数量が多い)銘柄であれば、最初の1〜2価格帯だけで注文が約定し、ズレはごくわずかです。しかし板が薄い(数量が少ない)銘柄や時間帯では、数量を積み上げるために何段階も価格帯をまたぐことになり、平均約定価格が想定よりも大きくズレてしまいます。

板が薄くなりやすい典型的な状況には、次のようなものがあります。

  • 時価総額が小さいアルトコインのペア
  • 主要市場の取引時間外(流動性が下がる深夜帯など)
  • 急な価格変動が起きた直後(板が一時的に空になる)
  • マイナーな取引所や、取扱いが始まったばかりのペア

こうした状況では、板に出ている数量そのものが少なく、成行注文のサイズが板に対して相対的に大きくなりやすいため、スリッページが拡大します。

ボット運用への影響

裁量トレードであれば人間が板を見ながら感覚的に注文サイズを調整できますが、ボットは機械的に注文を出すため、板の薄さを考慮しないロジックだと想定外のコストを積み重ねてしまいます。

特に注意したいのがバックテストとの乖離です。多くのバックテストはヒストリカルデータの終値・始値をそのまま約定価格として計算しますが、これは「板が無限に厚い」という非現実的な前提です。実運用ではスリッページ分だけ不利な価格で約定するため、バックテスト上の成績が実運用では再現されないことがあります。バックテストが抱えるこの種の落とし穴についてはバックテストの罠の記事でも取り上げているので、あわせて確認してみてください。

取引回数が多い戦略ほど、1回あたりはわずかなスリッページでも積み重なると無視できないコストになります。この点は取引コストが成績に与える影響とあわせて評価する必要があります。

対策1: 成行ではなく指値を使う

最もシンプルな対策は、成行注文の代わりに指値注文を使うことです。指値であれば指定した価格より不利な価格で約定することはありません(ただし約定しないリスクは残ります)。成行・指値それぞれの特徴や使い分けは注文タイプの使い分けの記事で整理しています。

対策2: 発注サイズを板の厚みに対して制限する

発注前に板情報を取得し、注文サイズが板の厚みに対して大きすぎないかをチェックするロジックを入れる方法もあります。ccxtではfetch_order_bookで板のスナップショットを取得できるので、これを使って想定約定価格を概算できます。

def estimate_avg_fill_price(order_book_side: list[list[float]], qty: float) -> float | None:
    """板情報(price, amount のリスト)から成行注文の想定平均約定価格を概算する"""
    remaining = qty
    cost = 0.0
    for price, amount in order_book_side:
        fill = min(remaining, amount)
        cost += fill * price
        remaining -= fill
        if remaining <= 0:
            return cost / qty
    return None  # 板の数量が注文数量に足りない


# 例: asks = [[7_000_000, 0.02], [7_001_000, 0.03], [7_003_000, 0.1]]
asks = [[7_000_000, 0.02], [7_001_000, 0.03], [7_003_000, 0.1]]
avg_price = estimate_avg_fill_price(asks, qty=0.08)
print(avg_price)  # 想定平均約定価格(Noneなら発注を見送る、などの判断に使える)

この関数がNoneを返す、あるいはベスト価格との乖離が許容範囲を超える場合は発注を見送る、というガードをボットに組み込んでおくと、薄い板での不利な約定を減らせます。発注数量そのものの決め方はポジションサイズの計算式の記事も参考になります。

対策3: バックテストにスリッページを織り込む

実運用との乖離を小さくするには、バックテストの段階で一定のスリッページ率を仮定してコストを差し引いておくのが現実的です。固定bpsを一律で引く簡易な方法から、板の薄い銘柄では大きめのスリッページ率を設定するなど、銘柄・時間帯ごとに調整する方法まであります。完璧な再現は難しいものの、「スリッページ込みでも成績がプラスか」を事前に確認しておくだけで、実運用開始後の失望を減らせます。

※板の厚み・スプレッドは銘柄や相場状況によって大きく変動し、取引所ごとの特性も異なります。この記事の内容は一般的な考え方の整理であり、実際の数値は必ず利用する取引所・銘柄で確認してください。

まとめ

  • スリッページは、成行注文が薄い板を複数価格帯にわたって消費することで発生する、構造的に避けられないコスト
  • 板が薄くなりやすいのは、小型アルトコイン・取引時間外・急変動直後・マイナー取引所など
  • バックテストは板の厚みを考慮しないことが多く、実運用との成績乖離の原因になりやすい
  • 対策としては、指値注文の活用・発注サイズと板厚みのチェック・バックテストへのスリッページ織り込みが基本
  • 取引回数が多い戦略ほど、小さなスリッページの積み重ねが無視できなくなる

スリッページは地味な話題ですが、エントリーロジックをどれだけ磨いても、約定価格がズレ続けていては期待通りの成績にはなりません。板の厚みを意識した発注設計は、戦略そのものと同じくらい成績を左右する要素です。