CBOE Emulator  1.0
limit_tree.hpp
1 // A single side (buy/sell) of the LimitOrderBook.
2 // Copyright 2020 Christian Kauten
3 //
4 // Author: Christian Kauten (kautenja@auburn.edu)
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
17 
18 #ifndef DATA_FEED_LIMIT_ORDER_BOOK_LIMIT_TREE_HPP
19 #define DATA_FEED_LIMIT_ORDER_BOOK_LIMIT_TREE_HPP
20 
21 #include "structures.hpp"
22 #include "tsl/robin_map.h"
23 
25 namespace DataFeed {
26 
28 namespace LOB {
29 
31 typedef tsl::robin_map<Price, Limit*> PriceLimitMap;
32 
33 // ---------------------------------------------------------------------------
34 // MARK: set_best
35 // ---------------------------------------------------------------------------
36 
43 template<Side side>
44 void set_best(Limit** best, Limit* limit);
45 
51 template<>
52 inline void set_best<Side::Buy>(Limit** highest_buy, Limit* limit) {
53  if (*highest_buy == nullptr) *highest_buy = limit;
54  else if (limit->key > (*highest_buy)->key) *highest_buy = limit;
55 }
56 
62 template<>
63 inline void set_best<Side::Sell>(Limit** lowest_sell, Limit* limit) {
64  if (*lowest_sell == nullptr) *lowest_sell = limit;
65  else if (limit->key < (*lowest_sell)->key) *lowest_sell = limit;
66 }
67 
68 // ---------------------------------------------------------------------------
69 // MARK: find_best
70 // ---------------------------------------------------------------------------
71 
77 template<Side side>
78 void find_best(Limit** best);
79 
84 template<>
85 inline void find_best<Side::Buy>(Limit** highest_buy) {
86  if ((*highest_buy)->parent == nullptr) // removing root node
87  // set left because if right existed it would be a better limit already
88  *highest_buy = static_cast<Limit*>((*highest_buy)->left);
89  else // removing non-root node
90  *highest_buy = static_cast<Limit*>((*highest_buy)->parent);
91  if (*highest_buy != nullptr) // highest buy exists
92  *highest_buy = static_cast<Limit*>(BST::max(*highest_buy));
93 }
94 
99 template<>
100 inline void find_best<Side::Sell>(Limit** lowest_sell) {
101  if ((*lowest_sell)->parent == nullptr) // removing root node
102  // set right because if left existed it would be a better limit already
103  *lowest_sell = static_cast<Limit*>((*lowest_sell)->right);
104  else // removing non-root node
105  *lowest_sell = static_cast<Limit*>((*lowest_sell)->parent);
106  if (*lowest_sell != nullptr) // lowest sell exists
107  *lowest_sell = static_cast<Limit*>(BST::min(*lowest_sell));
108 }
109 
110 // ---------------------------------------------------------------------------
111 // MARK: can_match
112 // ---------------------------------------------------------------------------
113 
121 template<Side side>
122 bool can_match(Price limit, Price market);
123 
130 template<>
131 inline bool can_match<Side::Buy>(Price limit, Price market) {
132  // short circuit on price > 0: 0 is sentinel for no limit
133  // the price should be less than or equal to the best on the buy side.
134  // i.e., the submitted order is a sell limit with a lower price
135  return market == 0 || market <= limit;
136 }
137 
144 template<>
145 inline bool can_match<Side::Sell>(Price limit, Price market) {
146  // short circuit on price > 0: 0 is sentinel for no limit
147  // the price should be greater than or equal to the best on the sell side.
148  // i.e., the submitted order is a buy limit with a higher price
149  return market == 0 || market >= limit;
150 }
151 
153 template<Side side>
154 struct LimitTree {
156  Limit* root = nullptr;
160  Limit* best = nullptr;
167 
169  void clear() {
170  // delete all the limits
171  for(auto item = limits.begin(); item != limits.end(); item++)
172  delete item->second;
173  // clear the pairs from the map
174  limits.clear();
175  // set remaining tracers to 0
176  root = nullptr;
177  best = nullptr;
178  count = 0;
179  volume = 0;
180  }
181 
186  void limit(Order* order) {
187  if (limits.count(order->price) == 0) { // first order at limit price
188  // create the limit and set the order's limit to the limit
189  order->limit = new Limit(order);
190  // the limit price is new, add it to the limit tree
191  BST::insert(
192  reinterpret_cast<BST::Node<Price>**>(&root),
193  static_cast<BST::Node<Price>*>(order->limit)
194  );
195  // set the best price
196  set_best<side>(&best, order->limit);
197  // put the limit into the price to limit mapping
198  limits.emplace(order->limit->key, order->limit);
199  } else { // push to existing queue of orders at limit price
200  // set the order's limit to the limit node for the order's price
201  order->limit = limits.at(order->price);
202  // increment the count of the orders at this limit node
203  ++order->limit->count;
204  // increment the volume of the orders at this limit node
205  order->limit->volume += order->quantity;
206  // add the order to the queue of orders for the limit node
207  DLL::append(
208  reinterpret_cast<DLL::Node**>(&order->limit->order_tail),
209  static_cast<DLL::Node*>(order)
210  );
211  }
212  // update the count and volume for the entire tree
213  ++count;
214  volume += order->quantity;
215  // set the last best price
216  if (best != nullptr) last_best_price = best->key;
217  }
218 
219  // TODO: use object pool for limit reuse?
224  void cancel(Order* order) {
225  // unwrap the limit for the order
226  auto limit_ = order->limit;
227  if (order->prev == nullptr && order->next == nullptr) { // last Order
228  // remove the limit from the tree
229  BST::remove(
230  reinterpret_cast<BST::Node<Price>**>(&root),
231  static_cast<BST::Node<Price>*>(limit_)
232  );
233  // replace the best limit if necessary
234  if (best == limit_)
235  find_best<side>(&best);
236  // remove the limit from the price map
237  limits.erase(limit_->key);
238  delete limit_;
239  } else { // at least 1 other Order in queue
240  --limit_->count;
241  limit_->volume -= order->quantity;
242  // remove the order from the queue (update head and tail)
243  DLL::remove(
244  reinterpret_cast<DLL::Node**>(&limit_->order_head),
245  reinterpret_cast<DLL::Node**>(&limit_->order_tail),
246  static_cast<DLL::Node*>(order)
247  );
248  }
249  // update the count and volume for the entire tree
250  --count;
251  volume -= order->quantity;
252  // set the last best price
253  if (best != nullptr) last_best_price = best->key;
254  }
255 
262  template<typename Callback>
263  void market(Order* order, Callback did_fill) {
264  // find orders until there are none
265  while (best != nullptr && can_match<side>(best->key, order->price)) {
266  // get the next match as the front of the best price
267  auto match = best->order_head;
268  if (match->quantity >= order->quantity) { // current match can fill
269  if (match->quantity == order->quantity) { // limit order filled
270  // remove the current match from the book
271  cancel(match);
272  did_fill(match->uid);
273  } else { // limit order partially filled
274  // remove the market order quantity from the limit quantity
275  match->quantity -= order->quantity;
276  // update the match's limit volume
277  match->limit->volume -= order->quantity;
278  // update the volume for the entire tree
279  volume -= order->quantity;
280  }
281  // clear the remaining quantity for the order
282  order->quantity = 0;
283  return;
284  } // else: current match can NOT fill
285  // decrement the remaining quantity of the market order
286  order->quantity -= match->quantity;
287  // remove the current match from the book
288  cancel(match);
289  did_fill(match->uid);
290  }
291 
292  }
293 
299  inline Volume volume_at(Price price) const {
300  if (limits.count(price)) return limits.at(price)->volume;
301  return 0;
302  }
303 
309  inline Count count_at(Price price) const {
310  if (limits.count(price)) return limits.at(price)->count;
311  return 0;
312  }
313 };
314 
315 } // namespace LOB
316 
317 } // namespace DataFeed
318 
319 #endif // DATA_FEED_LIMIT_ORDER_BOOK_LIMIT_TREE_HPP
DataFeed::LOB::Order::quantity
Quantity quantity
the number of shares in the order
Definition: structures.hpp:60
DataFeed::LOB::LimitTree::market
void market(Order *order, Callback did_fill)
Perform a market order of given quantity on the given limit tree.
Definition: limit_tree.hpp:263
DataFeed::LOB::Limit::count
Count count
the number of orders at this limit price
Definition: structures.hpp:92
DataFeed::LOB::LimitTree::limit
void limit(Order *order)
Place a limit order on the limit tree.
Definition: limit_tree.hpp:186
DataFeed::LOB::LimitTree::volume
Volume volume
the total volume of orders for this tree
Definition: limit_tree.hpp:166
DataFeed::LOB::LimitTree::count_at
Count count_at(Price price) const
Return the number of orders at the given limit price.
Definition: limit_tree.hpp:309
DataFeed::LOB::Volume
uint64_t Volume
a type for limit total volume
Definition: structures.hpp:87
DataFeed::LOB::LimitTree::root
Limit * root
the sorted tree of orders in the book
Definition: limit_tree.hpp:156
DataFeed::LOB::Limit::order_tail
Order * order_tail
the last order in the queue (last to execute)
Definition: structures.hpp:100
DataFeed::LOB::LimitTree::limits
PriceLimitMap limits
a mapping of limit prices to limits
Definition: limit_tree.hpp:158
DataFeed::LOB::can_match
bool can_match(Price limit, Price market)
Return true if the market price can match with the limit price.
DataFeed::LOB::set_best
void set_best(Limit **best, Limit *limit)
Set the best to the given limit if the given limit is better.
DataFeed
Logic for sending and receiving messages on a financial data feed.
Definition: heartbeat.hpp:28
DataFeed::LOB::Order
A single order in the LimitOrderBook.
Definition: structures.hpp:54
DataFeed::LOB::Limit::order_head
Order * order_head
the first order in the queue (next to execute)
Definition: structures.hpp:98
DataFeed::Price
uint64_t Price
A type for order prices.
Definition: messages.hpp:103
DataFeed::LOB::LimitTree::last_best_price
Price last_best_price
the last best price
Definition: limit_tree.hpp:162
DataFeed::LOB::Limit
A price limit containing a FIFO queue of Order objects.
Definition: structures.hpp:90
DataFeed::LOB::LimitTree
A single side (buy/sell) of the LimitOrderBook.
Definition: limit_tree.hpp:154
DataFeed::LOB::find_best
void find_best(Limit **best)
Find the next best when removing the best from the tree.
DataFeed::LOB::PriceLimitMap
tsl::robin_map< Price, Limit * > PriceLimitMap
a map of prices to limit pointers
Definition: limit_tree.hpp:31
DataFeed::LOB::Price
uint64_t Price
a type for order prices
Definition: structures.hpp:48
DataFeed::LOB::Order::price
const Price price
the limit price for the order (market price if market order)
Definition: structures.hpp:62
DataFeed::LOB::LimitTree::cancel
void cancel(Order *order)
Remove an order from the limit tree.
Definition: limit_tree.hpp:224
DataFeed::LOB::LimitTree::count
Count count
the total number of active orders for this tree
Definition: limit_tree.hpp:164
DataFeed::LOB::Count
uint32_t Count
a type for limit price order counts
Definition: structures.hpp:85
DataFeed::LOB::Limit::volume
Volume volume
the total amount of volume at this limit price (sum of order shares)
Definition: structures.hpp:96
DataFeed::LOB::LimitTree::clear
void clear()
Clear all the limits in the tree.
Definition: limit_tree.hpp:169
DataFeed::LOB::Order::limit
Limit * limit
the limit this order falls under
Definition: structures.hpp:64
DataFeed::LOB::LimitTree::best
Limit * best
the best order
Definition: limit_tree.hpp:160
DataFeed::LOB::LimitTree::volume_at
Volume volume_at(Price price) const
Return the volume of orders at the given limit price.
Definition: limit_tree.hpp:299