File size: 4,807 Bytes
f86fb3b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | #pragma once
#include <cstdint>
#include <array>
#include <map>
#include <unordered_map>
#include <vector>
#include <functional>
#include <optional>
#include "../core/types.hpp"
#include "../core/cache_line.hpp"
#include "../core/object_pool.hpp"
namespace quant::order_book {
// Intrusive doubly linked list node for zero-allocation order tracking
struct Order {
core::OrderId order_id{0};
core::ClientId client_id{0};
core::ClientOrderId client_order_id{0};
core::Symbol symbol;
core::Price price;
core::Quantity qty{0};
core::Quantity leaves_qty{0};
core::Side side{core::Side::UNKNOWN};
core::OrderType order_type{core::OrderType::LIMIT};
core::TimestampNs timestamp_ns{0};
Order* prev{nullptr};
Order* next{nullptr};
};
struct alignas(core::CACHELINE_SIZE) PriceLevel {
core::Price price;
core::Quantity total_volume{0};
uint32_t order_count{0};
Order* head{nullptr};
Order* tail{nullptr};
void append(Order* order) noexcept {
order->next = nullptr;
order->prev = tail;
if (tail) {
tail->next = order;
} else {
head = order;
}
tail = order;
total_volume += order->leaves_qty;
++order_count;
}
void remove(Order* order) noexcept {
if (order->prev) {
order->prev->next = order->next;
} else {
head = order->next;
}
if (order->next) {
order->next->prev = order->prev;
} else {
tail = order->prev;
}
total_volume -= order->leaves_qty;
--order_count;
}
};
struct L2Level {
double price{0.0};
double volume{0.0};
uint32_t count{0};
};
struct alignas(core::CACHELINE_SIZE) L2Snapshot {
static constexpr size_t MAX_DEPTH = 10;
std::array<L2Level, MAX_DEPTH> bids;
std::array<L2Level, MAX_DEPTH> asks;
size_t bid_count{0};
size_t ask_count{0};
core::TimestampNs timestamp_ns{0};
};
class alignas(core::CACHELINE_SIZE) OrderBook {
public:
static constexpr size_t MAX_ORDERS = 131072; // 128k orders in memory pool
explicit OrderBook(core::Symbol symbol) : symbol_(symbol), order_pool_() {}
~OrderBook() = default;
OrderBook(const OrderBook&) = delete;
OrderBook& operator=(const OrderBook&) = delete;
// Direct O(1) order lookup
[[nodiscard]] Order* find_order(core::OrderId order_id) noexcept {
auto it = orders_map_.find(order_id);
return it != orders_map_.end() ? it->second : nullptr;
}
[[nodiscard]] Order* find_order_by_client_id(core::ClientOrderId client_order_id) noexcept {
auto it = client_orders_map_.find(client_order_id);
return it != client_orders_map_.end() ? it->second : nullptr;
}
// Allocate order from zero-allocation pool
template <typename... Args>
[[nodiscard]] Order* allocate_order(Args&&... args) {
return order_pool_.allocate(std::forward<Args>(args)...);
}
void free_order(Order* order) noexcept {
order_pool_.deallocate(order);
}
// Add resting limit order to the book
bool add_resting_order(Order* order) noexcept;
// Remove / Cancel resting order
bool remove_order(Order* order) noexcept;
// Reduce order quantity (partial fill or modify)
bool reduce_order_qty(Order* order, core::Quantity fill_qty) noexcept;
// Best bid / ask price
[[nodiscard]] std::optional<core::Price> best_bid() const noexcept;
[[nodiscard]] std::optional<core::Price> best_ask() const noexcept;
// Market metrics
[[nodiscard]] double get_mid_price() const noexcept;
[[nodiscard]] double get_weighted_microprice() const noexcept;
[[nodiscard]] double get_book_imbalance() const noexcept;
// Extract L2 Top of Book snapshot
void get_l2_snapshot(L2Snapshot& snapshot) const noexcept;
[[nodiscard]] core::Symbol symbol() const noexcept { return symbol_; }
[[nodiscard]] size_t order_count() const noexcept { return orders_map_.size(); }
// Bid and Ask books
// Bids sorted descending (highest price first), Asks sorted ascending (lowest price first)
auto& bids() noexcept { return bids_; }
auto& asks() noexcept { return asks_; }
const auto& bids() const noexcept { return bids_; }
const auto& asks() const noexcept { return asks_; }
private:
core::Symbol symbol_;
core::ObjectPool<Order, MAX_ORDERS> order_pool_;
std::unordered_map<core::OrderId, Order*> orders_map_;
std::unordered_map<core::ClientOrderId, Order*> client_orders_map_;
// Sorted price levels
std::map<core::Price, PriceLevel, std::greater<core::Price>> bids_;
std::map<core::Price, PriceLevel, std::less<core::Price>> asks_;
};
} // namespace quant::order_book
|