CppTrader 1.0.5.0
C++ Trader
Loading...
Searching...
No Matches
order_book.cpp
Go to the documentation of this file.
1
11
12namespace CppTrader {
13namespace Matching {
14
16 : _manager(manager),
17 _symbol(symbol),
18 _best_bid(nullptr),
19 _best_ask(nullptr),
20 _best_buy_stop(nullptr),
21 _best_sell_stop(nullptr),
22 _best_trailing_buy_stop(nullptr),
23 _best_trailing_sell_stop(nullptr),
24 _last_bid_price(0),
25 _last_ask_price(std::numeric_limits<uint64_t>::max()),
26 _matching_bid_price(0),
27 _matching_ask_price(std::numeric_limits<uint64_t>::max()),
28 _trailing_bid_price(0),
29 _trailing_ask_price(std::numeric_limits<uint64_t>::max())
30{
31}
32
34{
35 // Release bid price levels
36 for (auto& bid : _bids)
37 _manager._level_pool.Release(&bid);
38 _bids.clear();
39
40 // Release ask price levels
41 for (auto& ask : _asks)
42 _manager._level_pool.Release(&ask);
43 _asks.clear();
44
45 // Release buy stop orders levels
46 for (auto& buy_stop : _buy_stop)
47 _manager._level_pool.Release(&buy_stop);
48 _buy_stop.clear();
49
50 // Release sell stop orders levels
51 for (auto& sell_stop : _sell_stop)
52 _manager._level_pool.Release(&sell_stop);
53 _sell_stop.clear();
54
55 // Release trailing buy stop orders levels
56 for (auto& trailing_buy_stop : _trailing_buy_stop)
57 _manager._level_pool.Release(&trailing_buy_stop);
58 _trailing_buy_stop.clear();
59
60 // Release trailing sell stop orders levels
61 for (auto& trailing_sell_stop : _trailing_sell_stop)
62 _manager._level_pool.Release(&trailing_sell_stop);
63 _trailing_sell_stop.clear();
64}
65
66LevelNode* OrderBook::AddLevel(OrderNode* order_ptr)
67{
68 LevelNode* level_ptr = nullptr;
69
70 if (order_ptr->IsBuy())
71 {
72 // Create a new price level
73 level_ptr = _manager._level_pool.Create(LevelType::BID, order_ptr->Price);
74
75 // Insert the price level into the bid collection
76 _bids.insert(*level_ptr);
77
78 // Update the best bid price level
79 if ((_best_bid == nullptr) || (level_ptr->Price > _best_bid->Price))
80 _best_bid = level_ptr;
81 }
82 else
83 {
84 // Create a new price level
85 level_ptr = _manager._level_pool.Create(LevelType::ASK, order_ptr->Price);
86
87 // Insert the price level into the ask collection
88 _asks.insert(*level_ptr);
89
90 // Update the best ask price level
91 if ((_best_ask == nullptr) || (level_ptr->Price < _best_ask->Price))
92 _best_ask = level_ptr;
93 }
94
95 return level_ptr;
96}
97
98LevelNode* OrderBook::DeleteLevel(OrderNode* order_ptr)
99{
100 // Find the price level for the order
101 LevelNode* level_ptr = order_ptr->Level;
102
103 if (order_ptr->IsBuy())
104 {
105 // Update the best bid price level
106 if (level_ptr == _best_bid)
107 _best_bid = (_best_bid->left != nullptr) ? _best_bid->left : ((_best_bid->parent != nullptr) ? _best_bid->parent : _best_bid->right);
108
109 // Erase the price level from the bid collection
110 _bids.erase(Levels::iterator(&_bids, level_ptr));
111 }
112 else
113 {
114 // Update the best ask price level
115 if (level_ptr == _best_ask)
116 _best_ask = (_best_ask->right != nullptr) ? _best_ask->right : ((_best_ask->parent != nullptr) ? _best_ask->parent : _best_ask->left);
117
118 // Erase the price level from the ask collection
119 _asks.erase(Levels::iterator(&_asks, level_ptr));
120 }
121
122 // Release the price level
123 _manager._level_pool.Release(level_ptr);
124
125 return nullptr;
126}
127
128LevelUpdate OrderBook::AddOrder(OrderNode* order_ptr)
129{
130 // Find the price level for the order
131 LevelNode* level_ptr = order_ptr->IsBuy() ? (LevelNode*)GetBid(order_ptr->Price) : (LevelNode*)GetAsk(order_ptr->Price);
132
133 // Create a new price level if no one found
135 if (level_ptr == nullptr)
136 {
137 level_ptr = AddLevel(order_ptr);
138 update = UpdateType::ADD;
139 }
140
141 // Update the price level volume
142 level_ptr->TotalVolume += order_ptr->LeavesQuantity;
143 level_ptr->HiddenVolume += order_ptr->HiddenQuantity();
144 level_ptr->VisibleVolume += order_ptr->VisibleQuantity();
145
146 // Link the new order to the orders list of the price level
147 level_ptr->OrderList.push_back(*order_ptr);
148 ++level_ptr->Orders;
149
150 // Cache the price level in the given order
151 order_ptr->Level = level_ptr;
152
153 // Price level was changed. Return top of the book modification flag.
154 return LevelUpdate(update, *order_ptr->Level, (order_ptr->Level == (order_ptr->IsBuy() ? _best_bid : _best_ask)));
155}
156
157LevelUpdate OrderBook::ReduceOrder(OrderNode* order_ptr, uint64_t quantity, uint64_t hidden, uint64_t visible)
158{
159 // Find the price level for the order
160 LevelNode* level_ptr = order_ptr->Level;
161
162 // Update the price level volume
163 level_ptr->TotalVolume -= quantity;
164 level_ptr->HiddenVolume -= hidden;
165 level_ptr->VisibleVolume -= visible;
166
167 // Unlink the empty order from the orders list of the price level
168 if (order_ptr->LeavesQuantity == 0)
169 {
170 level_ptr->OrderList.pop_current(*order_ptr);
171 --level_ptr->Orders;
172 }
173
174 Level level(*level_ptr);
175
176 // Delete the empty price level
178 if (level_ptr->TotalVolume == 0)
179 {
180 // Clear the price level cache in the given order
181 order_ptr->Level = DeleteLevel(order_ptr);
182 update = UpdateType::DELETE;
183 }
184
185 // Price level was changed. Return top of the book modification flag.
186 return LevelUpdate(update, level, ((order_ptr->Level == nullptr) || (order_ptr->Level == (order_ptr->IsBuy() ? _best_bid : _best_ask))));
187}
188
189LevelUpdate OrderBook::DeleteOrder(OrderNode* order_ptr)
190{
191 // Find the price level for the order
192 LevelNode* level_ptr = order_ptr->Level;
193
194 // Update the price level volume
195 level_ptr->TotalVolume -= order_ptr->LeavesQuantity;
196 level_ptr->HiddenVolume -= order_ptr->HiddenQuantity();
197 level_ptr->VisibleVolume -= order_ptr->VisibleQuantity();
198
199 // Unlink the empty order from the orders list of the price level
200 level_ptr->OrderList.pop_current(*order_ptr);
201 --level_ptr->Orders;
202
203 Level level(*level_ptr);
204
205 // Delete the empty price level
207 if (level_ptr->TotalVolume == 0)
208 {
209 // Clear the price level cache in the given order
210 order_ptr->Level = DeleteLevel(order_ptr);
211 update = UpdateType::DELETE;
212 }
213
214 // Price level was changed. Return top of the book modification flag.
215 return LevelUpdate(update, level, ((order_ptr->Level == nullptr) || (order_ptr->Level == (order_ptr->IsBuy() ? _best_bid : _best_ask))));
216}
217
218LevelNode* OrderBook::AddStopLevel(OrderNode* order_ptr)
219{
220 LevelNode* level_ptr = nullptr;
221
222 if (order_ptr->IsBuy())
223 {
224 // Create a new price level
225 level_ptr = _manager._level_pool.Create(LevelType::ASK, order_ptr->StopPrice);
226
227 // Insert the price level into the buy stop orders collection
228 _buy_stop.insert(*level_ptr);
229
230 // Update the best buy stop order price level
231 if ((_best_buy_stop == nullptr) || (level_ptr->Price < _best_buy_stop->Price))
232 _best_buy_stop = level_ptr;
233 }
234 else
235 {
236 // Create a new price level
237 level_ptr = _manager._level_pool.Create(LevelType::BID, order_ptr->StopPrice);
238
239 // Insert the price level into the sell stop orders collection
240 _sell_stop.insert(*level_ptr);
241
242 // Update the best sell stop order price level
243 if ((_best_sell_stop == nullptr) || (level_ptr->Price > _best_sell_stop->Price))
244 _best_sell_stop = level_ptr;
245 }
246
247 return level_ptr;
248}
249
250LevelNode* OrderBook::DeleteStopLevel(OrderNode* order_ptr)
251{
252 // Find the price level for the order
253 LevelNode* level_ptr = order_ptr->Level;
254
255 if (order_ptr->IsBuy())
256 {
257 // Update the best buy stop order price level
258 if (level_ptr == _best_buy_stop)
259 _best_buy_stop = (_best_buy_stop->right != nullptr) ? _best_buy_stop->right : _best_buy_stop->parent;
260
261 // Erase the price level from the buy stop orders collection
262 _buy_stop.erase(Levels::iterator(&_buy_stop, level_ptr));
263 }
264 else
265 {
266 // Update the best sell stop order price level
267 if (level_ptr == _best_sell_stop)
268 _best_sell_stop = (_best_sell_stop->left != nullptr) ? _best_sell_stop->left : _best_sell_stop->parent;
269
270 // Erase the price level from the sell stop orders collection
271 _sell_stop.erase(Levels::iterator(&_sell_stop, level_ptr));
272 }
273
274 // Release the price level
275 _manager._level_pool.Release(level_ptr);
276
277 return nullptr;
278}
279
280void OrderBook::AddStopOrder(OrderNode* order_ptr)
281{
282 // Find the price level for the order
283 LevelNode* level_ptr = order_ptr->IsBuy() ? (LevelNode*)GetBuyStopLevel(order_ptr->StopPrice) : (LevelNode*)GetSellStopLevel(order_ptr->StopPrice);
284
285 // Create a new price level if no one found
286 if (level_ptr == nullptr)
287 level_ptr = AddStopLevel(order_ptr);
288
289 // Update the price level volume
290 level_ptr->TotalVolume += order_ptr->LeavesQuantity;
291 level_ptr->HiddenVolume += order_ptr->HiddenQuantity();
292 level_ptr->VisibleVolume += order_ptr->VisibleQuantity();
293
294 // Link the new order to the orders list of the price level
295 level_ptr->OrderList.push_back(*order_ptr);
296 ++level_ptr->Orders;
297
298 // Cache the price level in the given order
299 order_ptr->Level = level_ptr;
300}
301
302void OrderBook::ReduceStopOrder(OrderNode* order_ptr, uint64_t quantity, uint64_t hidden, uint64_t visible)
303{
304 // Find the price level for the order
305 LevelNode* level_ptr = order_ptr->Level;
306
307 // Update the price level volume
308 level_ptr->TotalVolume -= quantity;
309 level_ptr->HiddenVolume -= hidden;
310 level_ptr->VisibleVolume -= visible;
311
312 // Unlink the empty order from the orders list of the price level
313 if (order_ptr->LeavesQuantity == 0)
314 {
315 level_ptr->OrderList.pop_current(*order_ptr);
316 --level_ptr->Orders;
317 }
318
319 // Delete the empty price level
320 if (level_ptr->TotalVolume == 0)
321 {
322 // Clear the price level cache in the given order
323 order_ptr->Level = DeleteStopLevel(order_ptr);
324 }
325}
326
327void OrderBook::DeleteStopOrder(OrderNode* order_ptr)
328{
329 // Find the price level for the order
330 LevelNode* level_ptr = order_ptr->Level;
331
332 // Update the price level volume
333 level_ptr->TotalVolume -= order_ptr->LeavesQuantity;
334 level_ptr->HiddenVolume -= order_ptr->HiddenQuantity();
335 level_ptr->VisibleVolume -= order_ptr->VisibleQuantity();
336
337 // Unlink the empty order from the orders list of the price level
338 level_ptr->OrderList.pop_current(*order_ptr);
339 --level_ptr->Orders;
340
341 // Delete the empty price level
342 if (level_ptr->TotalVolume == 0)
343 {
344 // Clear the price level cache in the given order
345 order_ptr->Level = DeleteStopLevel(order_ptr);
346 }
347}
348
349LevelNode* OrderBook::AddTrailingStopLevel(OrderNode* order_ptr)
350{
351 LevelNode* level_ptr = nullptr;
352
353 if (order_ptr->IsBuy())
354 {
355 // Create a new price level
356 level_ptr = _manager._level_pool.Create(LevelType::ASK, order_ptr->StopPrice);
357
358 // Insert the price level into the trailing buy stop orders collection
359 _trailing_buy_stop.insert(*level_ptr);
360
361 // Update the best trailing buy stop order price level
362 if ((_best_trailing_buy_stop == nullptr) || (level_ptr->Price < _best_trailing_buy_stop->Price))
363 _best_trailing_buy_stop = level_ptr;
364 }
365 else
366 {
367 // Create a new price level
368 level_ptr = _manager._level_pool.Create(LevelType::BID, order_ptr->StopPrice);
369
370 // Insert the price level into the trailing sell stop orders collection
371 _trailing_sell_stop.insert(*level_ptr);
372
373 // Update the best trailing sell stop order price level
374 if ((_best_trailing_sell_stop == nullptr) || (level_ptr->Price > _best_trailing_sell_stop->Price))
375 _best_trailing_sell_stop = level_ptr;
376 }
377
378 return level_ptr;
379}
380
381LevelNode* OrderBook::DeleteTrailingStopLevel(OrderNode* order_ptr)
382{
383 // Find the price level for the order
384 LevelNode* level_ptr = order_ptr->Level;
385
386 if (order_ptr->IsBuy())
387 {
388 // Update the best trailing buy stop order price level
389 if (level_ptr == _best_trailing_buy_stop)
390 _best_trailing_buy_stop = (_best_trailing_buy_stop->right != nullptr) ? _best_trailing_buy_stop->right : _best_trailing_buy_stop->parent;
391
392 // Erase the price level from the trailing buy stop orders collection
393 _trailing_buy_stop.erase(Levels::iterator(&_trailing_buy_stop, level_ptr));
394 }
395 else
396 {
397 // Update the best trailing sell stop order price level
398 if (level_ptr == _best_trailing_sell_stop)
399 _best_trailing_sell_stop = (_best_trailing_sell_stop->left != nullptr) ? _best_trailing_sell_stop->left : _best_trailing_sell_stop->parent;
400
401 // Erase the price level from the trailing sell stop orders collection
402 _trailing_sell_stop.erase(Levels::iterator(&_trailing_sell_stop, level_ptr));
403 }
404
405 // Release the price level
406 _manager._level_pool.Release(level_ptr);
407
408 return nullptr;
409}
410
411void OrderBook::AddTrailingStopOrder(OrderNode* order_ptr)
412{
413 // Find the price level for the order
414 LevelNode* level_ptr = order_ptr->IsBuy() ? (LevelNode*)GetTrailingBuyStopLevel(order_ptr->StopPrice) : (LevelNode*)GetTrailingSellStopLevel(order_ptr->StopPrice);
415
416 // Create a new price level if no one found
417 if (level_ptr == nullptr)
418 level_ptr = AddTrailingStopLevel(order_ptr);
419
420 // Update the price level volume
421 level_ptr->TotalVolume += order_ptr->LeavesQuantity;
422 level_ptr->HiddenVolume += order_ptr->HiddenQuantity();
423 level_ptr->VisibleVolume += order_ptr->VisibleQuantity();
424
425 // Link the new order to the orders list of the price level
426 level_ptr->OrderList.push_back(*order_ptr);
427 ++level_ptr->Orders;
428
429 // Cache the price level in the given order
430 order_ptr->Level = level_ptr;
431}
432
433void OrderBook::ReduceTrailingStopOrder(OrderNode* order_ptr, uint64_t quantity, uint64_t hidden, uint64_t visible)
434{
435 // Find the price level for the order
436 LevelNode* level_ptr = order_ptr->Level;
437
438 // Update the price level volume
439 level_ptr->TotalVolume -= quantity;
440 level_ptr->HiddenVolume -= hidden;
441 level_ptr->VisibleVolume -= visible;
442
443 // Unlink the empty order from the orders list of the price level
444 if (order_ptr->LeavesQuantity == 0)
445 {
446 level_ptr->OrderList.pop_current(*order_ptr);
447 --level_ptr->Orders;
448 }
449
450 // Delete the empty price level
451 if (level_ptr->TotalVolume == 0)
452 {
453 // Clear the price level cache in the given order
454 order_ptr->Level = DeleteTrailingStopLevel(order_ptr);
455 }
456}
457
458void OrderBook::DeleteTrailingStopOrder(OrderNode* order_ptr)
459{
460 // Find the price level for the order
461 LevelNode* level_ptr = order_ptr->Level;
462
463 // Update the price level volume
464 level_ptr->TotalVolume -= order_ptr->LeavesQuantity;
465 level_ptr->HiddenVolume -= order_ptr->HiddenQuantity();
466 level_ptr->VisibleVolume -= order_ptr->VisibleQuantity();
467
468 // Unlink the empty order from the orders list of the price level
469 level_ptr->OrderList.pop_current(*order_ptr);
470 --level_ptr->Orders;
471
472 // Delete the empty price level
473 if (level_ptr->TotalVolume == 0)
474 {
475 // Clear the price level cache in the given order
476 order_ptr->Level = DeleteTrailingStopLevel(order_ptr);
477 }
478}
479
480uint64_t OrderBook::CalculateTrailingStopPrice(const Order& order) const noexcept
481{
482 // Get the current market price
483 uint64_t market_price = order.IsBuy() ? GetMarketTrailingStopPriceAsk() : GetMarketTrailingStopPriceBid();
484 int64_t trailing_distance = order.TrailingDistance;
485 int64_t trailing_step = order.TrailingStep;
486
487 // Convert percentage trailing values into absolute ones
488 if (trailing_distance < 0)
489 {
490 trailing_distance = (int64_t)((-trailing_distance * market_price) / 10000);
491 trailing_step = (int64_t)((-trailing_step * market_price) / 10000);
492 }
493
494 uint64_t old_price = order.StopPrice;
495
496 if (order.IsBuy())
497 {
498 // Calculate a new stop price
499 uint64_t new_price = (market_price < (std::numeric_limits<uint64_t>::max() - trailing_distance)) ? (market_price + trailing_distance) : std::numeric_limits<uint64_t>::max();
500
501 // If the new price is better and we get through the trailing step
502 if (new_price < old_price)
503 if ((old_price - new_price) >= (uint64_t)trailing_step)
504 return new_price;
505 }
506 else
507 {
508 // Calculate a new stop price
509 uint64_t new_price = (market_price > (uint64_t)trailing_distance) ? (market_price - trailing_distance) : 0;
510
511 // If the new price is better and we get through the trailing step
512 if (new_price > old_price)
513 if ((new_price - old_price) >= (uint64_t)trailing_step)
514 return new_price;
515 }
516
517 return old_price;
518}
519
520} // namespace Matching
521} // namespace CppTrader
const LevelNode * GetAsk(uint64_t price) const noexcept
Get the order book ask price level with the given price.
OrderBook(MarketManager &manager, const Symbol &symbol)
const Levels & trailing_sell_stop() const noexcept
Get the order book trailing sell stop orders container.
Definition order_book.h:84
const LevelNode * GetTrailingBuyStopLevel(uint64_t price) const noexcept
Get the order book trailing buy stop level with the given price.
const LevelNode * GetBid(uint64_t price) const noexcept
Get the order book bid price level with the given price.
const LevelNode * GetSellStopLevel(uint64_t price) const noexcept
Get the order book sell stop level with the given price.
const Levels & trailing_buy_stop() const noexcept
Get the order book trailing buy stop orders container.
Definition order_book.h:82
const LevelNode * GetTrailingSellStopLevel(uint64_t price) const noexcept
Get the order book trailing sell stop level with the given price.
const Levels & sell_stop() const noexcept
Get the order book sell stop orders container.
Definition order_book.h:74
const LevelNode * GetBuyStopLevel(uint64_t price) const noexcept
Get the order book buy stop level with the given price.
const Levels & buy_stop() const noexcept
Get the order book buy stop orders container.
Definition order_book.h:72
Market manager definition.
UpdateType
Update type.
Definition update.h:21
C++ Trader project definitions.
Definition errors.h:16
Order book definition.
Level(LevelType type, uint64_t price) noexcept
Definition level.inl:30
uint64_t Price
Level price.
Definition level.h:36
Price level node.
Definition level.h:79
uint64_t Price
Order price.
Definition order.h:138
bool IsBuy() const noexcept
Is the order with buy side?
Definition order.h:231