11auto to_side(
char buy_sell_indicator)
noexcept ->
Side {
17auto BookManager::in_universe(std::string_view
symbol)
const ->
bool {
18 return m_universe.empty() || m_universe.contains(std::string {
symbol});
21auto BookManager::entry(std::uint16_t
stock_locate)
const -> BookEntry* {
28auto BookManager::ensure_entry(std::uint16_t
stock_locate, std::string_view
symbol) -> BookEntry* {
30 m_books_by_locate.resize(
static_cast<std::size_t
>(
stock_locate) + 1);
33 if (slot->book.symbol().empty() && !
symbol.empty()) {
34 slot->book.set_symbol(std::string {
symbol});
38 if (!in_universe(
symbol)) {
41 m_books_by_locate[
stock_locate] = std::make_unique<BookEntry>();
47auto BookManager::emit_bbo_if_changed(BookEntry& target) ->
void {
48 const Bbo current = target.book.bbo();
49 if (current != target.last_bbo) {
50 target.last_bbo = current;
52 m_bbo_callback(target.book, current);
57template <
typename AddMessage>
58auto BookManager::handle_add_order(
const AddMessage& add) ->
void {
60 if (target !=
nullptr) {
61 target->book.add_order(
62 add.order_reference_number, to_side(add.buy_sell_indicator), add.shares, add.price
64 emit_bbo_if_changed(*target);
68auto BookManager::handle_order_executed(
const OrderExecutedMessage& exec) ->
void {
69 BookEntry* target = entry(exec.stock_locate);
70 if (target ==
nullptr) {
73 if (m_trade_callback) {
74 const auto price = target->book.order_price(exec.order_reference_number);
75 const auto side = target->book.order_side(exec.order_reference_number);
76 if (
price.has_value()) {
78 trade.timestamp = exec.timestamp;
79 trade.stock_locate = exec.stock_locate;
80 trade.symbol = target->book.symbol();
82 trade.shares = exec.executed_shares;
83 trade.match_number = exec.match_number;
84 trade.side =
side.has_value() ?
static_cast<char>(*side) :
'\0';
85 trade.printable =
true;
86 m_trade_callback(trade);
89 target->book.execute_order(exec.order_reference_number, exec.executed_shares);
90 emit_bbo_if_changed(*target);
93auto BookManager::handle_order_executed_with_price(
const OrderExecutedWithPriceMessage& exec
95 BookEntry* target = entry(exec.stock_locate);
96 if (target ==
nullptr) {
99 if (m_trade_callback) {
100 const auto side = target->book.order_side(exec.order_reference_number);
102 trade.timestamp = exec.timestamp;
103 trade.stock_locate = exec.stock_locate;
104 trade.symbol = target->book.symbol();
106 trade.shares = exec.executed_shares;
107 trade.match_number = exec.match_number;
108 trade.side =
side.has_value() ?
static_cast<char>(*side) :
'\0';
109 trade.printable = exec.printable ==
'Y';
110 m_trade_callback(trade);
112 target->book.execute_order(exec.order_reference_number, exec.executed_shares);
113 emit_bbo_if_changed(*target);
116auto BookManager::handle_order_cancel(
const OrderCancelMessage& cancel) ->
void {
117 if (BookEntry* target = entry(cancel.stock_locate)) {
118 target->book.reduce_order(cancel.order_reference_number, cancel.cancelled_shares);
119 emit_bbo_if_changed(*target);
123auto BookManager::handle_order_delete(
const OrderDeleteMessage& del) ->
void {
124 if (BookEntry* target = entry(del.stock_locate)) {
125 target->book.delete_order(del.order_reference_number);
126 emit_bbo_if_changed(*target);
130auto BookManager::handle_order_replace(
const OrderReplaceMessage& replace) ->
void {
131 if (BookEntry* target = entry(replace.stock_locate)) {
132 target->book.replace_order(
133 replace.original_order_reference_number,
134 replace.new_order_reference_number,
138 emit_bbo_if_changed(*target);
142auto BookManager::handle_non_cross_trade(
const NonCrossTradeMessage& trade) ->
void {
144 if (!m_trade_callback) {
148 tape_entry.timestamp = trade.timestamp;
149 tape_entry.stock_locate = trade.stock_locate;
152 tape_entry.shares = trade.shares;
153 tape_entry.match_number = trade.match_number;
154 tape_entry.side = trade.buy_sell_indicator;
155 tape_entry.printable =
true;
156 m_trade_callback(tape_entry);
159auto BookManager::handle_cross_trade(
const CrossTradeMessage& cross) ->
void {
160 if (!m_trade_callback) {
164 tape_entry.timestamp = cross.timestamp;
165 tape_entry.stock_locate = cross.stock_locate;
168 tape_entry.shares = cross.shares;
169 tape_entry.match_number = cross.match_number;
170 tape_entry.printable =
true;
171 tape_entry.is_cross =
true;
172 tape_entry.cross_type = cross.cross_type;
173 m_trade_callback(tape_entry);
176auto BookManager::handle_stock_directory(
const StockDirectoryMessage& directory) ->
void {
177 if (directory.stock_locate >= m_symbol_by_locate.size()) {
178 m_symbol_by_locate.resize(
static_cast<std::size_t
>(directory.stock_locate) + 1);
184 if (
const auto* add = std::get_if<AddOrderMessage>(&message)) {
185 handle_add_order(*add);
186 }
else if (
const auto* add_mpid = std::get_if<AddOrderMPIDAttributionMessage>(&message)) {
187 handle_add_order(*add_mpid);
188 }
else if (
const auto* executed = std::get_if<OrderExecutedMessage>(&message)) {
189 handle_order_executed(*executed);
190 }
else if (
const auto* executed_with_price =
191 std::get_if<OrderExecutedWithPriceMessage>(&message)) {
192 handle_order_executed_with_price(*executed_with_price);
193 }
else if (
const auto* cancel = std::get_if<OrderCancelMessage>(&message)) {
194 handle_order_cancel(*cancel);
195 }
else if (
const auto* del = std::get_if<OrderDeleteMessage>(&message)) {
196 handle_order_delete(*del);
197 }
else if (
const auto* replace = std::get_if<OrderReplaceMessage>(&message)) {
198 handle_order_replace(*replace);
199 }
else if (
const auto* trade = std::get_if<NonCrossTradeMessage>(&message)) {
200 handle_non_cross_trade(*trade);
201 }
else if (
const auto* cross = std::get_if<CrossTradeMessage>(&message)) {
202 handle_cross_trade(*cross);
203 }
else if (
const auto* directory = std::get_if<StockDirectoryMessage>(&message)) {
204 handle_stock_directory(*directory);
208template auto BookManager::handle_add_order(
const AddOrderMessage&) -> void;
213 return found !=
nullptr ? &found->book :
nullptr;
217 for (
const auto& slot : m_books_by_locate) {
218 if (slot && slot->book.symbol() ==
symbol) {
227 found !=
nullptr && !found->book.symbol().empty()) {
228 return found->book.
symbol();
Full-market order book manager that fans out ITCH messages to per-symbol L3Book instances.
auto process(const Message &message) -> void
Processes one parsed ITCH message, updating the relevant book and emitting BBO/trade events as approp...
auto book_for_symbol(std::string_view symbol) const -> const L3Book *
The book for a symbol, or nullptr if none is tracked.
auto book(std::uint16_t stock_locate) const -> const L3Book *
The book for a locate code, or nullptr if none is tracked.
auto symbol_for_locate(std::uint16_t stock_locate) const -> std::string_view
The symbol associated with a locate code (empty if unknown).
A single-symbol, order-level (L3) limit order book with allocation-light internals.
auto symbol() const noexcept -> const std::string &
The stock symbol associated with this book (may be empty).
std::uint16_t stock_locate
Side
Which side of the book an order rests on.
std::variant< SystemEventMessage, StockDirectoryMessage, StockTradingActionMessage, RegSHOMessage, MarketParticipantPositionMessage, MWCBDeclineLevelMessage, MWCBStatusMessage, IPOQuotingPeriodUpdateMessage, LULDAuctionCollarMessage, OperationalHaltMessage, AddOrderMessage, AddOrderMPIDAttributionMessage, OrderExecutedMessage, OrderExecutedWithPriceMessage, OrderCancelMessage, OrderDeleteMessage, OrderReplaceMessage, NonCrossTradeMessage, CrossTradeMessage, BrokenTradeMessage, NOIIMessage, RetailPriceImprovementIndicatorMessage, DLCRMessage > Message
A variant able to hold any one of the ITCH 5.0 message structs.
BasicPrice< std::uint32_t, 4 > StandardPrice
Price scale for every ITCH price field except MWCB decline levels.
auto to_string(const char *source, size_t size) -> std::string
Converts a fixed-width character array to a string, trimming trailing spaces and NUL characters.
Add Order, With MPID Attribution (F): like Add Order, but attributed to a market participant.
Add Order, No MPID Attribution (A): a new displayable order has been accepted and placed on the book.