C++ SDK

OrderBook

Lock-free order book data structures, SIMD price matching, and real-time updates

OrderBook

The OrderBook class provides a lock-free, cache-optimized representation of market depth with wait-free reads and obstruction-free writes, designed for HFT applications requiring sub-microsecond access.

Architecture

+----------------------------------------------------------+
|                      OrderBook                            |
|  +------------------------+  +------------------------+  |
|  |      Bid Side          |  |      Ask Side          |  |
|  |  (Sorted Descending)   |  |  (Sorted Ascending)    |  |
|  |  +------------------+  |  |  +------------------+  |  |
|  |  | Level 0 (Best)   |  |  |  | Level 0 (Best)   |  |  |
|  |  | Price: 50000.00  |  |  |  | Price: 50000.01  |  |  |
|  |  | Qty: 10.5        |  |  |  | Qty: 8.2         |  |  |
|  |  | Orders: 15       |  |  |  | Orders: 12       |  |  |
|  |  +------------------+  |  |  +------------------+  |  |
|  |  | Level 1          |  |  |  | Level 1          |  |  |
|  |  | Price: 49999.99  |  |  |  | Price: 50000.02  |  |  |
|  |  +------------------+  |  |  +------------------+  |  |
|  |  |       ...        |  |  |  |       ...        |  |  |
|  +------------------------+  +------------------------+  |
+----------------------------------------------------------+

Basic Usage

Creating an OrderBook

#include <lxdex/orderbook.hpp>

using namespace lxdex;

// Create order book with default capacity
OrderBook book("BTC-USD");

// Create with specified depth
OrderBook book("BTC-USD", {
    .max_levels = 1000,
    .use_simd = true,
    .cache_aligned = true
});

Subscribing to Order Book Updates

Client client({.endpoints = {"wss://api.lux.network/ws"}});
client.connect();

// Subscribe with callback
client.subscribe_orderbook("BTC-USD", [](const OrderBook& book) {
    // Called on I/O thread with lock-free read access
    auto [bid, ask] = book.best_bid_ask();

    if (bid && ask) {
        auto spread = ask->price - bid->price;
        auto mid = (bid->price + ask->price) / 2;

        std::cout << "Spread: " << spread.to_string()
                  << " Mid: " << mid.to_string() << '\n';
    }
});

Accessing Book Data

// Best bid/ask (O(1))
auto [bid, ask] = book.best_bid_ask();

// Specific level (O(1))
auto level = book.bid_level(5);  // 5th best bid

// All bids/asks (O(n))
for (const auto& level : book.bids()) {
    std::cout << level.price.to_string() << " x "
              << level.quantity.to_string() << '\n';
}

// Top N levels
auto top_bids = book.top_bids(10);
auto top_asks = book.top_asks(10);

Price Level Structure

namespace lxdex {

struct PriceLevel {
    Price price;
    Quantity quantity;
    uint32_t order_count;
    Timestamp last_update;

    // Calculated fields
    [[nodiscard]] Price notional() const noexcept {
        return price * quantity;
    }
};

// Cache-line aligned for performance
static_assert(sizeof(PriceLevel) <= 64);
static_assert(alignof(PriceLevel) == 64);

}  // namespace lxdex

Lock-Free Implementation

Wait-Free Reads

// Multiple reader threads can access simultaneously
// No locks, no contention, deterministic latency

std::thread reader1([&book] {
    while (running) {
        auto bid = book.best_bid();  // Wait-free O(1)
        process_bid(bid);
    }
});

std::thread reader2([&book] {
    while (running) {
        auto spread = book.spread();  // Wait-free O(1)
        process_spread(spread);
    }
});

Obstruction-Free Writes

// Single writer thread applies updates
// Uses atomic compare-and-swap for consistency

void apply_update(OrderBook& book, const BookUpdate& update) {
    switch (update.type) {
        case UpdateType::Set:
            book.set_level(update.side, update.price, update.quantity);
            break;
        case UpdateType::Delete:
            book.delete_level(update.side, update.price);
            break;
    }
}

Memory Ordering

// SeqLock pattern for consistent snapshots
class OrderBook {
    mutable std::atomic<uint64_t> sequence_{0};
    std::array<PriceLevel, MAX_LEVELS> bids_;
    std::array<PriceLevel, MAX_LEVELS> asks_;

public:
    // Reader: retry until consistent read
    std::optional<PriceLevel> best_bid() const noexcept {
        PriceLevel level;
        uint64_t seq1, seq2;

        do {
            seq1 = sequence_.load(std::memory_order_acquire);
            if (seq1 & 1) continue;  // Write in progress

            level = bids_[0];  // Read

            std::atomic_thread_fence(std::memory_order_acquire);
            seq2 = sequence_.load(std::memory_order_relaxed);
        } while (seq1 != seq2);

        if (level.quantity.raw() == 0) return std::nullopt;
        return level;
    }

    // Writer: increment sequence before and after
    void set_level(Side side, Price price, Quantity qty) noexcept {
        sequence_.fetch_add(1, std::memory_order_release);  // Odd = writing
        std::atomic_thread_fence(std::memory_order_release);

        // Perform update...

        std::atomic_thread_fence(std::memory_order_release);
        sequence_.fetch_add(1, std::memory_order_release);  // Even = done
    }
};

SIMD Price Matching

AVX-512 Implementation

#include <lxdex/simd/avx512.hpp>

// Find price level using SIMD (8 prices per comparison)
std::optional<size_t> find_price_level_avx512(
    const std::array<int64_t, 1024>& prices,
    int64_t target_price,
    size_t count
) {
    __m512i target = _mm512_set1_epi64(target_price);

    for (size_t i = 0; i < count; i += 8) {
        __m512i prices_vec = _mm512_load_epi64(&prices[i]);
        __mmask8 mask = _mm512_cmpeq_epi64_mask(prices_vec, target);

        if (mask != 0) {
            return i + __builtin_ctz(mask);
        }
    }

    return std::nullopt;
}

NEON Implementation (ARM)

#include <lxdex/simd/neon.hpp>

// Find price level using NEON (2 prices per comparison)
std::optional<size_t> find_price_level_neon(
    const std::array<int64_t, 1024>& prices,
    int64_t target_price,
    size_t count
) {
    int64x2_t target = vdupq_n_s64(target_price);

    for (size_t i = 0; i < count; i += 2) {
        int64x2_t prices_vec = vld1q_s64(&prices[i]);
        uint64x2_t cmp = vceqq_s64(prices_vec, target);

        if (vgetq_lane_u64(cmp, 0)) return i;
        if (vgetq_lane_u64(cmp, 1)) return i + 1;
    }

    return std::nullopt;
}

Automatic Dispatch

// Runtime SIMD detection
OrderBook book("BTC-USD", {
    .use_simd = true,  // Auto-detect best SIMD
    .simd_hint = SimdHint::Auto  // Or: AVX512, AVX2, NEON, Scalar
});

// Manual dispatch
#if defined(__AVX512F__)
    auto idx = find_price_level_avx512(prices, target, count);
#elif defined(__AVX2__)
    auto idx = find_price_level_avx2(prices, target, count);
#elif defined(__ARM_NEON)
    auto idx = find_price_level_neon(prices, target, count);
#else
    auto idx = find_price_level_scalar(prices, target, count);
#endif

Book Snapshots

Full Snapshot

// Get immutable snapshot (copy)
auto snapshot = book.snapshot();

// Process snapshot on different thread
std::thread processor([snapshot = std::move(snapshot)] {
    for (const auto& level : snapshot.bids()) {
        analyze_level(level);
    }
});

Incremental Updates

// Subscribe to incremental updates
client.subscribe_orderbook_incremental("BTC-USD",
    // Snapshot callback (called first)
    [&book](const OrderBookSnapshot& snap) {
        book.apply_snapshot(snap);
    },
    // Delta callback (called for each update)
    [&book](const OrderBookDelta& delta) {
        book.apply_delta(delta);
    }
);

Delta Structure

struct OrderBookDelta {
    std::string symbol;
    uint64_t sequence;
    Timestamp timestamp;

    struct Change {
        Side side;
        Price price;
        Quantity quantity;  // 0 = delete level
    };

    std::vector<Change> changes;
};

// Apply delta
void OrderBook::apply_delta(const OrderBookDelta& delta) {
    if (delta.sequence != expected_sequence_) {
        // Gap detected - request full snapshot
        return;
    }

    for (const auto& change : delta.changes) {
        if (change.quantity.raw() == 0) {
            delete_level(change.side, change.price);
        } else {
            set_level(change.side, change.price, change.quantity);
        }
    }

    ++expected_sequence_;
}

Market Metrics

Spread and Mid-Price

// Spread (O(1))
auto spread = book.spread();
std::cout << "Spread: " << spread.to_string() << '\n';

// Mid-price (O(1))
auto mid = book.mid_price();
std::cout << "Mid: " << mid.to_string() << '\n';

// Weighted mid-price (O(1))
auto wmid = book.weighted_mid_price();
std::cout << "Weighted Mid: " << wmid.to_string() << '\n';

Market Depth

// Total quantity at price levels
auto bid_depth = book.bid_depth(10);  // Sum of top 10 bid levels
auto ask_depth = book.ask_depth(10);

// Cumulative depth up to price
auto depth_to_price = book.cumulative_depth_to_price(
    Side::Bid,
    Price::from_string("49000.00")
);

// Depth required to move price by X%
auto depth_to_move = book.depth_to_move_price(
    Side::Ask,
    0.01  // 1%
);

Order Book Imbalance

// Imbalance ratio: (bid_qty - ask_qty) / (bid_qty + ask_qty)
auto imbalance = book.imbalance(5);  // Top 5 levels
// Returns: [-1.0, 1.0], positive = more bids

// Volume-weighted imbalance
auto vwap_imbalance = book.vwap_imbalance(5);

Order Book Views

Aggregated View

// Aggregate by price bucket
auto aggregated = book.aggregate(Price::from_string("10.00"));  // $10 buckets

for (const auto& [price_bucket, total_qty] : aggregated.bids()) {
    std::cout << price_bucket.to_string() << " : "
              << total_qty.to_string() << '\n';
}

Filtered View

// Filter by minimum quantity
auto large_orders = book.filter([](const PriceLevel& level) {
    return level.quantity >= Quantity::from_string("10.0");
});

// Filter by price range
auto range_view = book.price_range(
    Price::from_string("49000.00"),
    Price::from_string("51000.00")
);

Cache-Friendly Design

Memory Layout

// Cache-line aligned price levels
struct alignas(64) PriceLevel {
    int64_t price;      // 8 bytes
    int64_t quantity;   // 8 bytes
    uint32_t orders;    // 4 bytes
    uint32_t flags;     // 4 bytes
    int64_t timestamp;  // 8 bytes
    char padding[32];   // Pad to 64 bytes
};

// Contiguous storage for cache efficiency
class OrderBook {
    // Hot data (accessed every tick)
    alignas(64) std::array<PriceLevel, 16> hot_bids_;
    alignas(64) std::array<PriceLevel, 16> hot_asks_;

    // Warm data (accessed occasionally)
    alignas(64) std::vector<PriceLevel> bids_;
    alignas(64) std::vector<PriceLevel> asks_;
};

Prefetching

// Manual prefetch for known access patterns
void OrderBook::prefetch_top_levels() const noexcept {
    // Prefetch best bid/ask into L1 cache
    __builtin_prefetch(&hot_bids_[0], 0, 3);  // Read, high locality
    __builtin_prefetch(&hot_asks_[0], 0, 3);

    // Prefetch next levels into L2 cache
    __builtin_prefetch(&hot_bids_[1], 0, 2);
    __builtin_prefetch(&hot_asks_[1], 0, 2);
}

// Use before accessing book
book.prefetch_top_levels();
auto [bid, ask] = book.best_bid_ask();

Benchmarks

Microbenchmarks

#include <benchmark/benchmark.h>
#include <lxdex/orderbook.hpp>

static void BM_BestBidAsk(benchmark::State& state) {
    lxdex::OrderBook book("BTC-USD");
    // Setup book with 1000 levels...

    for (auto _ : state) {
        auto [bid, ask] = book.best_bid_ask();
        benchmark::DoNotOptimize(bid);
        benchmark::DoNotOptimize(ask);
    }
}
BENCHMARK(BM_BestBidAsk);

static void BM_ApplyDelta(benchmark::State& state) {
    lxdex::OrderBook book("BTC-USD");
    lxdex::OrderBookDelta delta{/* ... */};

    for (auto _ : state) {
        book.apply_delta(delta);
    }
}
BENCHMARK(BM_ApplyDelta);

BENCHMARK_MAIN();

Performance Numbers

OperationLatency (p50)Latency (p99)Notes
best_bid_ask()12ns45nsLock-free
spread()15ns50nsLock-free
mid_price()18ns55nsLock-free
top_bids(10)89ns210nsCopy 10 levels
apply_delta()45ns120nsSingle update
find_price_simd()8ns25nsAVX-512, 1000 levels

Thread Safety Summary

OperationRead ThreadWrite Thread
best_bid()Wait-free-
best_ask()Wait-free-
spread()Wait-free-
bids()Wait-free-
asks()Wait-free-
snapshot()Wait-free-
set_level()-Single writer
delete_level()-Single writer
apply_delta()-Single writer

Example: Market Making

#include <lxdex/client.hpp>
#include <lxdex/orderbook.hpp>

class MarketMaker {
    Client& client_;
    OrderBook book_;
    Price spread_target_{100000};  // 0.001 in fixed-point
    Quantity quote_size_{1'00000000};  // 1.0

public:
    MarketMaker(Client& client, std::string_view symbol)
        : client_(client), book_(symbol) {}

    void on_book_update(const OrderBook& book) {
        book_ = book;  // Lock-free copy
        requote();
    }

    void requote() {
        auto mid = book_.mid_price();
        if (!mid) return;

        Price bid_price = *mid - spread_target_ / 2;
        Price ask_price = *mid + spread_target_ / 2;

        // Cancel existing orders
        client_.cancel_all_orders();

        // Place new quotes
        client_.place_order(OrderBuilder()
            .symbol(book_.symbol())
            .side(Side::Buy)
            .type(OrderType::Limit)
            .price(bid_price)
            .quantity(quote_size_)
            .build());

        client_.place_order(OrderBuilder()
            .symbol(book_.symbol())
            .side(Side::Sell)
            .type(OrderType::Limit)
            .price(ask_price)
            .quantity(quote_size_)
            .build());
    }
};

int main() {
    Client client({.endpoints = {"wss://api.lux.network/ws"}});
    client.connect();

    MarketMaker mm(client, "BTC-USD");

    client.subscribe_orderbook("BTC-USD", [&mm](const OrderBook& book) {
        mm.on_book_update(book);
    });

    // Run forever
    std::this_thread::sleep_for(std::chrono::hours{24 * 365});
}