
MMbot作成に取り組んでいて気になったことを整理して、改善方法もあわせてまとめてみました。未検証の内容も多いので、今後の宿題タスクとして残しておきます。
✅ マーケットメイキングBotにおける分解要素と技術的懸念点
カテゴリ | 要素 | 現状 | 懸念・改善余地 | コメント |
---|---|---|---|---|
注文トリガー | スプレッドベース | ◯%開いた時 | 単純な閾値判断では遅延が生じる | 「スプレッドの時間変化」や「約定方向の偏り」も見るべき |
歩み値(Tape) | 未活用 or 部分活用 | 売買勢力の検出に有効 | TICK方向、連続約定のバースト検出に活用可能 | |
出来高 | 未活用 or 単純集計 | 時系列での急増急減をトリガーに | VWAP/累積出来高比率による異常検出も可 | |
データ取得 | API (REST/WebSocket) | API経由で取得中 | レイテンシ、正確性に不安あり | 一部のデータは整形済で「見えない情報」がある可能性 |
非公式プロトコル | 未対応 | 高速なバイナリ/UDPなど | DPKDやOnload経由のFIX/TCP接続なども含む | |
Kernel Bypass技術 | 未対応 | NIC経由で直接データ取得 | 高頻度系には必須に近いが技術的障壁高め | |
板情報の解釈 | ask, bid, size | 一般的に使用中 | sizeが見かけの注文である可能性(Iceberg, hidden) | オーダーブックの「偽装」「変動頻度」なども指標化可能 |
更新頻度とリズム | 未定義 | 意図的な頻繁な更新がトリガーになることも | 通常更新 vs 攻撃的更新の識別 | |
技術的ボトルネック | 通信遅延 | RESTとWebSocket中心 | 並列化、非同期最適化、ハードウェア対応 | asyncio以外にもトレードオフ要検討(Rust / Cythonなど) |
処理時間 | Pythonベースで1loop数秒以内 | ロジック分岐のシンプル化、事前計算 | Numba, Cython, Rust連携、GPU活用など検討余地 |
👀 見逃しがちな視点(要チェックポイント)
観点 | 説明 |
---|---|
板のフェイク注文率 | 実際に約定されないまま消される注文の割合を見ることで、虚偽板検出が可能 |
Market Pressure指標 | buy volume / total volume のような短期圧力指標 |
板の上下階層の変化 | Best ask/bid のみでなく、2~3段先の注文群の変化を見ることで大口の動きを予測 |
Spreadのボラティリティ | Spreadがどれくらい不安定かを定量的に評価し、ボットの反応タイミングを再設計 |
イベントベースの設計 | 定時loopではなく、データの変化があったときに非同期に即応する設計(on_changeトリガー) |
🚀 今後の強化アプローチ(速度・精度・戦略)
分類 | 強化案 | 技術的手段 |
---|---|---|
データ取得 | バイナリWebSocket(Bybit, Binance)などの高速Feedへの移行 | aiohttp からwebsockets + 自前デシリアライザ |
計算速度 | ループのJIT最適化 | Numba , Cython , Rust(pyO3) 統合 |
ロジック | スプレッド × Tape変化 × VWAP乖離 の複合判断トリガー | 状況に応じた信号ベースのポリシー切替設計 |
戦略多様化 | 特定パターンに応じてMM/逆張り/回避などを即時選択 | 状態識別(Regime Detection)による切替アルゴ |
自動検出 | 板操作・異常取引をBotが自動検出・フラグ付与 | MLで異常行動の検出(特徴量: spread, tape, cancel率等) |

以下に、6つの観点でMM (マーケットメイキング) Bot をより細分化し、“強く”“速く”動かすための要素と具体的な強化案をまとめてみました。
1. データ取得層の強化
チャンネル | 特性 | 強化ポイント |
---|---|---|
公式API (REST) | 安定・汎用だがレイテンシ高め | 監視やバックテスト用に限定 |
公式WebSocket | L2(板深度)+Trade(板外約定) | ― 高速なL2/Tape (歩み値)Feed 利用 ― JSON からバイナリ変換でパース負荷削減 |
マルチキャスト/ITCH | 一部取引所が提供(※CME 等) | ― UDP マルチキャスト受信でミリ秒以下レイテンシ実現 |
FIX/TCP | オーダー送信と一部市場データ | ― Kernel-bypass (DPDK, Solarflare Onload) ― ハードウェアタイムスタンプ |
非公式/スクレイピング | 歴史的には使われるが不安定 | モジュール化してフォールバック用に |
ポイント:
- 複数チャネルを同時に受信し、優先度付け(例:WebSocket > REST)
- 時刻同期 (PTP) を導入し、データ到達時間の精度向上
2. データ前処理・板構築
- データ序列化
- バイナリ → 構造体パース
- デドゥプリケート
- ダブり訂正、欠落時は差分再要請
- L2 再構築
- ask/bid/size/time/volume 以外にも「注文ID」「参加者フラグ(Maker/Taker)」を保持
- タイムスライス集計
- 1ms, 10ms, 100ms ごとに板情報と歩み値をスナップショット
見逃しがちな要素
- 注文ID の見える化 → キャンセルvsマッチの高速判定
- Participants Tag → 市場流動性プロバイダー vs 一般トレーダーの識別
3. 特徴量エンジニアリング
カテゴリ | 特徴量例 | 戦略適用例 |
---|---|---|
価格系 | スプレッド, ミッド, マイクロプライス | Spread-based quoting |
板インバランス | (BidSize – AskSize)/(BidSize + AskSize) | Imbalance が ±X を超えたら寄せる/引く |
取引フロー | 累積買い/売り約定量 (Volume Delta), Trade Count | 一定閾値でインベントリ補正 |
時間変化率 | スプレッドの 1ms/10ms 勾配 | 突発的広がりを察知して即座に引用幅拡張 |
VWAP/TWAP | 直近 N 本の VWAP, TWAP | スリッページ補正 |
Order Flow Imbalance | Aggressor Side 比率 | Momentum リバーサル or トレンド継続 |
+α:
- 「歩み値のタイムスタンプ分布」→ アグレッシブ注文の強弱を時間密度で把握
- 「板消失/復活頻度」→ Flash Crashes 兆候の検知
4. シグナル&オーダー生成
- 動的スプレッド設計
- 市場状況 (Volatility, Volume) に応じた自動調整
- ポジション依存 quoting
- 在庫バランスに応じて価格をシフト (Inventory Skew)
- 複合トリガー
- 例)
(Imbalance > α) AND (Spread > β) AND (VolumeDelta > γ)
- 例)
- ハイブリッドオーダータイプ
- 限定指値 + IOC、PEG(mid±δ) + マネージェドリミット
高速化テク:
- キャッシュ済みロジック → CPU キャッシュフレンドリーなデータレイアウト
- SIMD/AVX 命令によるパラメータ判定
5. リスク管理とフィードバック
- リアルタイム在庫リミット
- PnL, Notional, ΔInventory 制御
- フェイルセーフ
- API異常 → 代替通信(WebSocket送信経路)
- 自己学習ループ
- 市場環境変化に合わせて閾値をオンライン更新 (Bayesian 最適化など)
- 統計的モニタリング
- Latency, Fill Rate, Adverse Selection Rate を常時可視化
6. インフラ&レイテンシ最適化
- 物理レイテンシの削減
- 取引所近傍にサーバをコロケート
- ネットワークスタックのバイパス
- DPDK/TurboNIC によるカーネルバイパス
- ハードウェアタイムスタンプ
- NIC レベルでのパケット時刻取得
- 軽量言語 or ネイティブ実装
- C++ / Rust / FPGA でのコアロジック
まとめ
- 多層的データ取得 → APIだけに依存せず、取引所提供の最速市場データを活用
- 微細な特徴量設計 → 単なるスプレッドだけでなく、歩み値やインバランス、VWAPなど
- 動的かつ複合的トリガー → マーケットコンディション/在庫に適応
- 超低レイテンシインフラ → コロケ/DPDK/ハードウェアタイムスタンプ
- 自己最適化&リスク制御 → オンライン学習とリアルタイムモニタリング

これらを順に取り入れ、モジュール化した上で継続的な A/B テストを回せば、より強く・速いMM Bot が実現できるかもしれません。
あなた:
👇一部深掘り:自分用ログ「MM Bot のコア部分を “より速く” 実装するために」
高速化テク:
- キャッシュ済みロジック → CPU キャッシュフレンドリーなデータレイアウト
- SIMD/AVX 命令によるパラメータ判定
を実装する際に必要な技術スタックと実装方法
1. 推奨技術スタック
- 言語
- C++17/20:最もサポートが手厚い。GCC/Clang の自動ベクトル化や手動インストリンシック両対応。
- Rust:
packed_simd2
やstd::simd
(nightly)で安全に SIMD を扱える。
- コンパイラ設定
-O3 -march=native -funroll-loops -falign-loops=32 -falign-jumps=32 -fopt-info-vec
など自動ベクトル化を最大化
- ビルド/CI
- CMake + Ninja(並列ビルド)
- GitHub Actions / GitLab CI で
-march=…
を分岐テスト
- プロファイラ/ベンチマーク
- Intel VTune, Linux
perf
, Google Benchmark
- Intel VTune, Linux
2. キャッシュフレンドリーなデータレイアウト
2.1 構造体設計:SoA vs AoS
- AoS (Array of Structures)
struct OrderBookEntry { double price; double size; uint64_t timestamp; }; std::vector<OrderBookEntry> entries;
→ 各エントリのフィールドがバラバラにメモリ配置され、同種フィールドの連続アクセスでキャッシュミス多発
- SoA (Structure of Arrays)
struct OrderBookSoA { std::vector<double> price; std::vector<double> size; std::vector<uint64_t> timestamp; } book;
→ price[i]
が連続してキャッシュに乗るので、スプレッド計算や閾値比較をベクトル化しやすい
2.2 メモリアライメント
- 64バイト境界 にアライン
struct alignas(64) AlignedArray { double data[N]; };
- カスタムアロケータで 64‑byte 境界を保証(C++17
<memory_resource>
など)
2.3 プリフェッチとループ構造
- 先読みプリフェッチ:
for (size_t i = 0; i < N; ++i) { _mm_prefetch(reinterpret_cast<const char*>(&price[i + 8]), _MM_HINT_T0); process(price[i]); }
- ループアンローリング:
for (size_t i = 0; i < N; i += 4) { process(price[i]); process(price[i+1]); process(price[i+2]); process(price[i+3]); }
3. SIMD/AVX を使ったパラメータ判定
3.1 基本的な流れ
- 連続配列(SoA)のポインタをロード
_mm256_load_pd
などで 4 値同時にロード_mm256_cmp_pd
で閾値ベクトルと比較_mm256_movemask_pd
で結果ビットを抽出、マスク判定
3.2 C++ インストリンシック例
#include <immintrin.h> // AVX void check_spread_avx(const double* spread, size_t N, double threshold) { __m256d thresh_vec = _mm256_set1_pd(threshold); for (size_t i = 0; i < N; i += 4) { // 4 要素同時ロード __m256d v = _mm256_load_pd(&spread[i]); // v > threshold ? __m256d cmp = _mm256_cmp_pd(v, thresh_vec, _CMP_GT_OQ); // マスク取得 int mask = _mm256_movemask_pd(cmp); if (mask) { // mask のどこかで条件成立 → 注文トリガー handle_trigger(i, mask); } } }
3.3 Rust での SIMD(nightly)
#![feature(portable_simd)] use std::simd::{f64x4, SimdPartialOrd}; fn check_spread_simd(spread: &[f64], threshold: f64) { let thresh_vec = f64x4::splat(threshold); for chunk in spread.chunks_exact(4) { let v = f64x4::from_slice(chunk); let mask = v.simd_gt(thresh_vec).to_bitmask(); if mask != 0 { handle_trigger(chunk.as_ptr() as usize, mask); } } }
4. まとめ:実装ポイント
- データ構造 は SoA で揃え、メモリアラインメントを厳守
- ループ設計 はアンローリング+プリフェッチでキャッシュ活用最大化
- SIMD 演算 はインストリンシック or Rust の
std::simd
で並列比較 - ビルド設定 で自動ベクトル化も最大化(
-march=native -O3
) - プロファイリング でホットループを特定し、実際に命令発行数やキャッシュミス率を可視化
これらを適用することで、1 要素ずつ比較する従来の実装に比べ、数倍〜十数倍のスループット向上が期待できる。
あなた:
👇深掘り2:データ取得層の強化:自分用ログ

それぞれのチャネルについて「何を」「なぜ」「どう強化するか」を技術的な特徴をまとめました。
1. 公式API (REST)
- 何を取得できるか
- 板情報(L2スナップショット)、約定履歴、取引ペア情報、口座残高など
- 特性・課題
- HTTP リクエスト/レスポンスの往復が数十~百ミリ秒以上かかる
- レイテンシが一定で、かつリクエスト頻度制限 (Rate Limit) が厳しい
- 強化ポイント
- 用途を限定
- 監視・レポートやバックテスト用に限定し、リアルタイム戦略には使わない
- HTTP/2 or gRPC
- サポートしていれば HTTP/2 のマルチプレクシングを使う、あるいは gRPC 化でレイテンシを若干削減
- コネクションプーリング
- Keep‑Alive で TCP/TLS の再ハンドシェイクを避ける
- 並列化
- 必要最少限のエンドポイントに絞り、複数スレッド/コルーチンで同時取得
- 用途を限定
2. 公式WebSocket
- 何を取得できるか
- L2(板深度)の差分更新、Trade(約定)Feed、Ticker、キャンセル情報など
- 特性・課題
- JSON 形式が多く、文字列パースコストが発生
- 差分更新の粒度が高いほどメッセージ数が膨大
- 強化ポイント
- L2/Tape フィードの直接利用
- 一部取引所は「L2 diff + 歩み値」を別 Feed で提供。まとめて購読することで REST+diff の組み合わせよりも高速に完全な板再構築が可能
- バイナリ化パーサ
- JSON → バイナリ形式に変換(Protobuf, FlatBuffers など)してパース負荷を低減
- コアパーサの最適化
- SIMD 化できる高速 JSON パーサ(SimdJSON など)を採用
- バックプレッシャー制御
- 消費遅延が一定以上になると一時的に購読ストリームを絞り、キューオーバーフローを防ぐ
- L2/Tape フィードの直接利用
3. マルチキャスト/ITCH
- 何を取得できるか
- CME の MDP3/4、Nasdaq‐ITCH など、UDP マルチキャストで流れるバイナリ・マーケットデータ
- 特性・課題
- ミリ秒以下のレイテンシで配信されるが、UDP のためパケットロスに注意
- データは完全バイナリかつプロプライエタリ形式
- 強化ポイント
- 低遅延受信
- NIC をマルチキャストに直接アタッチ(
ip maddress
+SO_BINDTODEVICE
)
- NIC をマルチキャストに直接アタッチ(
- カーネルバイパス
- DPDK や Solarflare Onload でユーザー空間に直接パケットを引き上げ
- パケット再構成
- 欠損を検知したら FEC(Forward Error Correction)や再送要求プロトコルで補完
- マッピング&デマルシャリング
- 取引所公式の仕様ドキュメントに従い、Efficient C/C++ コードでフィールドを直接メモリに展開
- 低遅延受信
4. FIX/TCP
- 何を取得できるか
- オーダー送信、ステータス、約定通知に加え、一部マーケットデータをFIXメッセージで受信
- 特性・課題
- TCP ベースのセッション管理が必須、心拍や再接続処理が煩雑
- メッセージシリアル化コスト(Tag=Value 形式)
- 強化ポイント
- Kernel‑bypass
- UDP と同様に DPDK/Onload で TCP パケットを直接アプリに渡す
- ハードウェアタイムスタンプ
- NIC レベルでパケット受信・送信時刻を刻印し、実際の市場到達時間を高精度に記録
- 軽量FIXエンジン
- QuickFIX/J+Disruptor などの低レイテンシアーキテクチャを使い、自前で最適化
- セッション冗長化
- マスター/スタンバイ構成で TCP セッションをアクティブ-アクティブ or アクティブ-パッシブ
- Kernel‑bypass
5. 非公式/スクレイピング
- 何を取得できるか
- ウェブサイト上の板情報、チャートリプレイ、非公開Feed の逆コンパイル
- 特性・課題
- HTML/JS の DOM 操作を伴い安定性・可用性に欠ける
- 規約違反リスクや構造変更の都度メンテ必要
- 強化ポイント
- モジュール化
- あくまでフォールバック用としてライブラリ化。正式チャネルに異常が出た場合のみトグルで起動
- ヘッドレスブラウザ or API逆解析
- Puppeteer+CDP (Chrome Debug Protocol) で最小限 JS 実行に絞る
- 監視アラート
- DOM 構造変化検知でスクレイピング失敗を即通知
- モジュール化
ポイントまとめ
- 複数チャネルの同時受信 & 優先度付け
- 例:最優先 → マルチキャスト/Fix, 次点 → WebSocket, 最終フォールバック → REST/Scraping
- PTP (Precision Time Protocol) 導入
- ミリ秒以下の時刻同期で、各チャネル到達時間を揃え、真正なティック時系列を再構築
これらを組み合わせることで、どのチャネルでどの情報がもっとも“速く”“正確”に取れるかをリアルタイムに判断し、MM Bot の市場認識精度と注文反応速度を最大化できる。
このポストがきっかけで自分でも色々調べることができた。感謝。 https://t.co/Cp3qCxtLDE
— よだか(夜鷹/yodaka) (@yodakablog) April 20, 2025