Spaces:
Sleeping
Sleeping
File size: 5,206 Bytes
d982819 c997ee9 d982819 137eca0 d982819 137eca0 c997ee9 d982819 137eca0 c997ee9 d982819 137eca0 d982819 c997ee9 d982819 ee1dfbc d982819 c997ee9 d982819 c997ee9 d982819 c997ee9 137eca0 c997ee9 d982819 c997ee9 d982819 c997ee9 137eca0 | 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 | #pragma once
#include <map>
#include <unordered_map>
#include <list>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <atomic>
#include <functional>
#include <optional>
#include <chrono>
#include <vector>
#include "Types.h"
#include "Order.h"
#include "Trade.h"
class Orderbook {
public:
using OnTradeCallback = std::function<void(const Trade&)>;
using OnOrderCallback = std::function<void(const Order&)>;
using OnSnapshotCallback = std::function<void(const OrderbookSnapshot&)>;
Orderbook();
~Orderbook();
Orderbook(const Orderbook&) = delete;
Orderbook& operator=(const Orderbook&) = delete;
Orderbook(Orderbook&&) = delete;
Orderbook& operator=(Orderbook&&) = delete;
// ─── Core API ─────────────────────────────────────────────────────────────
Trades AddOrder (OrderPointer order);
void CancelOrder(OrderId orderId);
Trades ModifyOrder(OrderModify order);
// ─── Query API ────────────────────────────────────────────────────────────
std::size_t Size() const;
bool HasOrder(OrderId) const;
OrderbookSnapshot GetSnapshot() const;
Price BestBid() const;
Price BestAsk() const;
Price MidPrice() const;
Price Spread() const;
// ─── Statistics ───────────────────────────────────────────────────────────
uint64_t GetTotalOrders() const noexcept { return stats_.totalOrders.load(); }
uint64_t GetTotalTrades() const noexcept { return stats_.totalTrades.load(); }
uint64_t GetTotalCancels() const noexcept { return stats_.totalCancels.load(); }
uint64_t GetTotalVolume() const noexcept { return stats_.totalVolume.load(); }
uint64_t GetSequenceNumber() const noexcept { return stats_.seqNum.load(); }
// ─── Event Hooks ──────────────────────────────────────────────────────────
void SetOnTrade(OnTradeCallback cb) { onTrade_ = std::move(cb); }
void SetOnOrderAdded(OnOrderCallback cb) { onAdded_ = std::move(cb); }
void SetOnOrderCancelled(OnOrderCallback cb) { onCancelled_ = std::move(cb); }
// BUG FIX #3: No longer public — called internally only, no longer calls
// AddOrderInternal directly to avoid recursive MatchOrders → stack overflow.
void CheckAndTriggerStops(Price lastTrade);
private:
struct OrderEntry {
OrderPointer order;
OrderPointers::iterator location;
};
struct LevelData {
Quantity quantity{0};
uint32_t count{0};
enum class Action { Add, Remove, Match };
};
std::map<Price, OrderPointers, std::greater<Price>> bids_;
std::map<Price, OrderPointers, std::less<Price>> asks_;
std::unordered_map<OrderId, OrderEntry> orders_;
std::unordered_map<Price, LevelData> levelData_;
std::multimap<Price, OrderPointer> stopBuys_;
std::multimap<Price, OrderPointer, std::greater<Price>> stopSells_;
// BUG FIX #3: Deferred stop injection buffer — stops collected here during
// MatchOrders and injected AFTER matching loop exits, preventing recursive
// MatchOrders calls that could cause stack overflow on stop chains.
std::vector<OrderPointer> pendingStops_;
mutable std::mutex ordersMutex_;
std::thread pruneThread_;
std::condition_variable shutdownCV_;
std::atomic<bool> shutdown_{false};
struct Stats {
std::atomic<uint64_t> totalOrders{0};
std::atomic<uint64_t> totalTrades{0};
std::atomic<uint64_t> totalCancels{0};
std::atomic<uint64_t> totalVolume{0};
std::atomic<uint64_t> seqNum{0};
std::atomic<Price> lastTradePrice{0};
std::atomic<Quantity> lastTradeQty{0};
} stats_;
OnTradeCallback onTrade_;
OnOrderCallback onAdded_;
OnOrderCallback onCancelled_;
void PruneGoodForDayOrders();
void CancelOrdersInternal(const OrderIds& ids);
void CancelOrderInternal (OrderId orderId);
Trades AddOrderInternal (OrderPointer order);
bool CanMatch (Side side, Price price) const;
bool CanFullyFill (Side side, Price price, Quantity qty) const;
Trades MatchOrders ();
Trade MakeTrade (OrderPointer bid, OrderPointer ask, Quantity qty);
void UpdateLevelData (Price price, Quantity qty, LevelData::Action action);
void OnOrderAdded (OrderPointer order);
void OnOrderCancelled (OrderPointer order);
void OnOrderMatched (Price price, Quantity qty, bool fullyFilled);
}; |