
低レイテンシトレーディングシステムのためのC++
なぜ最速のトレーディング企業はすべてをC++で書くのか
なぜ C++ が速度の言語なのか
レイテンシに敏感なスタック全体において、C++は今でもマッチングの経路を独占しています。Globex 型の会場、多くの株式フィード、そして暗号資産のエンジン(Hyperliquid クラスのインフラを含む)は、途中に GC の一時停止が潜むことのない、予測可能なマシンコードへとコンパイルされます。
C++ が低レイテンシ取引に特に適している理由は何でしょうか。
- ガベージコレクターがない——予測不能な一時停止がありません。メモリがいつ割り当てられ、いつ解放されるかを正確に制御できます。
- ハードウェアへの近さ——CPU のキャッシュライン、SIMD 命令、メモリマップド I/O、カーネルバイパスネットワーキングへの直接アクセス。
- コンパイル時計算——テンプレートメタプログラミングは、処理を実行時からコンパイル時へ移し、手書きのアセンブリと同じくらい高速なコードを生み出します。
- 予測可能なレイテンシ——注意深いコーディングによって、最小限のジッターでサブマイクロ秒のティック・トゥ・トレードレイテンシを達成できます。
現実的な話:最速のデスクにおけるティック・トゥ・トレードの予算は、しばしばサブマイクロ秒です。一つの余計なメモリ割り当てや一つのキャッシュミスが、その予算全体を食い尽くしてしまいます——そのためチームは、生産ラインのようにホットパスを守ります。
メモリ管理——スタック、ヒープ、カスタムアロケータ
低レイテンシの C++ では、何を計算するかよりも、メモリをどう割り当てるかの方が重要です。スタック割り当てとヒープ割り当ての差は、レイテンシにおいて 100 倍にもなり得ます。
// Stack allocation — near-instant, deterministic
struct OrderUpdate {
uint64_t order_id;
double price;
uint32_t quantity;
char side; // 'B' or 'S'
};
void process_tick(const MarketData& tick) {
OrderUpdate update{}; // Stack — zero allocation cost
update.price = tick.mid_price();
// ... process on the hot path
}
// Heap allocation — slow, non-deterministic (avoid on hot path)
auto* order = new OrderUpdate{}; // Calls malloc — BAD on hot path
本番システムはカスタムアロケータに頼ることで、ホットパスが一般的なヒープを呼び出さないようにします。
- プールアロケータ——大きなブロックを事前に割り当て、固定サイズのチャンクを切り出します。断片化がなく、割り当ては O(1) です。
- アリーナアロケータ——割り当てごとにポインタを前方に進め、一度にすべて解放します。メッセージ単位の処理に最適です。
- ヒュージページ——2MB または 1GB のページは TLB ミスを減らし、オーダーブックのデータが数メガバイトに及ぶ場合に重要です。
現代の C++ は、RAII(Resource Acquisition Is Initialization)とスマートポインタによって、安全なメモリ管理を扱いやすくします。
// RAII — resource lifetime tied to scope
{
auto connection = std::make_unique<TcpConnection>(endpoint);
connection->send(order_message);
} // Connection automatically closed here
// Shared ownership for reference-counted resources
auto config = std::make_shared<TradingConfig>(load_config());
engine.set_config(config); // Multiple owners, automatic cleanupロックフリーなデータ構造と並行性
ミューテックスは低レイテンシコードの敵です。1 回の std::mutex::lock() 呼び出しは、競合がない場合でも 20〜100 ナノ秒かかることがあり——競合がある場合には、スレッドをマイクロ秒単位で停止させることさえあります。トレーディングシステムは代わりにロックフリーなデータ構造を使います。
トレーディングにおいて最も重要なロックフリー構造は、単一生産者単一消費者(SPSC)キューです。
template<typename T, size_t Capacity>
class SPSCQueue {
alignas(64) std::array<T, Capacity> buffer_;
alignas(64) std::atomic<size_t> head_{0};
alignas(64) std::atomic<size_t> tail_{0};
public:
bool try_push(const T& item) {
const auto tail = tail_.load(std::memory_order_relaxed);
const auto next = (tail + 1) % Capacity;
if (next == head_.load(std::memory_order_acquire))
return false; // Full
buffer_[tail] = item;
tail_.store(next, std::memory_order_release);
return true;
}
bool try_pop(T& item) {
const auto head = head_.load(std::memory_order_relaxed);
if (head == tail_.load(std::memory_order_acquire))
return false; // Empty
item = buffer_[head];
head_.store((head + 1) % Capacity, std::memory_order_release);
return true;
}
};
主要な設計原則。
alignas(64)——各アトミック変数は独自のキャッシュラインを持ち、CPU コア間でのフォールスシェアリングを防ぎます。- メモリオーダリング——
acquire/releaseセマンティクスはseq_cstよりも安価で、プロデューサー・コンシューマーパターンには十分です。 - 2 の冪のサイズ設定——本番では、1024 や 4096 のようなサイズを使うことで、剰余演算がビット単位の AND になります。
典型的な配線構成では、NIC スレッドがエンキューし、戦略スレッドがデキューします——トポロジーを正しく組めば、伝送経路にミューテックスは一切不要です。
テンプレート——コンパイル時計算
C++ のテンプレートは、処理を実行時からコンパイル時へ移すことを可能にします。トレーディングにおいて、これはあなたのバイナリが、取引する正確なプロトコル、商品、戦略に特化することを意味します——ホットパスに実行時の分岐はありません。
// Compile-time FIX protocol field parsing
template<int Tag>
struct FIXField;
template<> struct FIXField<35> { // MsgType
static constexpr const char* name = "MsgType";
using type = char;
};
template<> struct FIXField<44> { // Price
static constexpr const char* name = "Price";
using type = double;
};
// Zero-overhead dispatch based on message type
template<char MsgType>
void handle_message(const char* raw, size_t len) {
if constexpr (MsgType == 'D') {
// New Order Single — inline at compile time
parse_new_order(raw, len);
} else if constexpr (MsgType == '8') {
// Execution Report
parse_execution(raw, len);
}
}
if constexpr の分岐は完全にコンパイル時に解決されます——生成されたマシンコードには、分岐オーバーヘッドがゼロの関連する経路だけが含まれます。この技法をリンク時最適化(LTO)と組み合わせることで、プロトコルの解析が本質的に一直線のメモリ読み取りの列へと展開されたバイナリが生成されます。
consteval、コンセプト、コンパイル時コンテナといった現代の C++20/23 の機能は、これをさらに一歩進め、注文検証のパイプライン全体をコンパイル時に計算できるようにします。
キャッシュに優しい設計とカーネルバイパスネットワーキング
サブマイクロ秒のレイテンシにおいては、CPU のキャッシュ階層が最も重要な最適化対象になります。メインメモリへのキャッシュミスは約 100 ナノ秒のコストがかかります——これは、レイテンシの合計予算が 500 ナノ秒である場合、永遠に等しい時間です。
// BAD: Array of Pointers (AoP) — cache-hostile
std::vector<std::unique_ptr<Order>> orders; // Each access = pointer chase + cache miss
// GOOD: Struct of Arrays (SoA) — cache-friendly
struct OrderBook {
std::vector<double> prices; // Contiguous in memory
std::vector<uint32_t> quantities; // Contiguous in memory
std::vector<uint64_t> order_ids; // Contiguous in memory
};
// Iterating prices = sequential cache line reads = fast
ネットワーキングにおいては、Linux カーネルの TCP/IP スタックが、パケットごとに 5〜15 マイクロ秒のレイテンシを追加します。トレーディング企業はそれを完全に迂回します。
- DPDK(Data Plane Development Kit)——ユーザー空間から NIC を直接ポーリングし、カーネルを迂回します。サブマイクロ秒のパケット処理を実現します。
- Solarflare OpenOnload——お馴染みのソケット API を保ったカーネルバイパス。株式や先物のトレーディングで広く使われています。
- FPGA NIC——Xilinx Alveo などのカードは、マーケットデータの解析と注文の生成をハードウェア上で行い、ナノ秒レベルのレイテンシを実現します。
分散型取引所さえ、これらの原則から利益を得ています。GaiaExのようなプラットフォームを動かしている Hyperliquid の L1 チェーンは、高スループット・低レイテンシのコンセンサスを念頭に設計されており、それに接続するマーケットメーカーは、価格更新を受け取ってから注文を提出するまでの時間を最小化するために、最適化された C++ クライアントを使用しています。
取引所のマッチングエンジンはどう構築されるか
すべての取引所の中心にはマッチングエンジンがあります——買い注文と売り注文をペアにするコンポーネントです。それは金融のすべてのソフトウェアの中で最もレイテンシに敏感な部分であり、ほぼ常に C++ で書かれています。
簡略化されたマッチングエンジンのアーキテクチャ。
class MatchingEngine {
// One order book per instrument
std::unordered_map<Symbol, OrderBook> books_;
void on_new_order(const Order& order) {
auto& book = books_[order.symbol];
auto matches = book.match(order);
for (const auto& fill : matches) {
publish_execution(fill); // To trading firms
update_market_data(fill); // To data feed
}
if (order.remaining_qty > 0) {
book.insert(order); // Rest on the book
}
}
};
本番のマッチングエンジンは、この骨格をはるかに超えて最適化されています。
- 価格・時間優先——同じ価格の注文は、ナノ秒単位のタイムスタンプで記録された到着順に成立します。
- 事前に割り当てられた注文プール——マッチング中にヒープ割り当てを行いません。注文は固定プールから再利用されます。
- ロックレス設計——各商品のオーダーブックは専用のコア上で動作します。ブック間のロックは不要です。
- 決定論的な再現——すべての注文とマッチングは、規制対応と災害復旧のために永続ストレージへジャーナル化されます。
このレベルのシステムを構築することこそ、C++ が本当に輝く場所です。他のどのメインストリームの言語も、メモリレイアウト、スレッドスケジューリング、キャッシュの挙動、ネットワーク I/O——超低レイテンシエンジニアリングの 4 本の柱——を同時に制御する力を与えてはくれません。次の取引所を構築するのであれ、マーケットメーカーとしてそれに接続するのであれ、プロップファームで実行を最適化するのであれ、C++ は依然として揺るぎない王者です。

