OnixS C++ SGX Titan ITCH Market Data Handler  1.2.2
API documentation
OrderBookHolder.cpp
Go to the documentation of this file.
1 /*
2 * Copyright Onix Solutions Limited [OnixS]. All rights reserved.
3 *
4 * This software owned by Onix Solutions Limited [OnixS] and is protected by copyright law
5 * and international copyright treaties.
6 *
7 * Access to and use of the software is governed by the terms of the applicable ONIXS Software
8 * Services Agreement (the Agreement) and Customer end user license agreements granting
9 * a non-assignable, non-transferable and non-exclusive license to use the software
10 * for it's own data processing purposes under the terms defined in the Agreement.
11 *
12 * Except as otherwise granted within the terms of the Agreement, copying or reproduction of any part
13 * of this source code or associated reference material to any other location for further reproduction
14 * or redistribution, and any amendments to this copyright notice, are expressly prohibited.
15 *
16 * Any reproduction or redistribution for sale or hiring of the Software not in accordance with
17 * the terms of the Agreement is a violation of copyright law.
18 */
19 
20 #include "OrderBookHolder.h"
21 
22 #include <util/String.h>
23 
26 
27 #include <boost/foreach.hpp>
28 
29 ONIXS_HANDLER_NAMESPACE_BEGIN
30 
31 OrderBookCreator::OrderBookCreator(size_t bookDepth, OrderBookAllocator* bookAllocator) :
32  bookDepth_(bookDepth),
33  bookAllocator_(bookAllocator)
34 {
35  BOOST_ASSERT(bookAllocator_!= nullptr);
36 }
37 
40  bookDepth_(other.bookDepth_),
41  bookAllocator_(other.bookAllocator_)
42 {
43  BOOST_ASSERT(bookAllocator_!= nullptr);
44 };
45 
46 boost::shared_ptr<OrderBookInternal> OrderBookCreator::operator()(const OrderBookId& id) const
47 {
48  BOOST_ASSERT(bookAllocator_!= nullptr);
49  void* location = bookAllocator_->alloc();
50  BOOST_ASSERT(location != nullptr);
51 
52  if(location == nullptr)
53  throw std::logic_error("book memory exhausted.");
54 
55  return boost::shared_ptr<OrderBookInternal>(new(location) OrderBookInternal(id, bookDepth_, bookDepth_));
56 }
57 
59 {
60  OnixS::HandlerCore::MarketData::FullOrderDepthBookCreator<OrderBookInternal, false>::reset();
61 }
62 
63 OrderBookHolder::OrderBookHolder(const OnOrderBookUpdatedCallback& onOrderBookUpdated, OrderBookAllocator* bookAllocator, size_t bookDepth) :
64  impl_(new BookRegistry(OrderBookCreator(bookDepth, bookAllocator))),
65  onOrderBookUpdated_(onOrderBookUpdated),
66  snapshotRecoveryInProgress_(false)
67 {
68  BOOST_ASSERT(bookAllocator != nullptr);
69  BOOST_ASSERT(bookDepth > 0);
70 }
71 
73 {
74  snapshotRecoveryInProgress_ = true;
75 }
76 
78 {
79  snapshotRecoveryInProgress_ = false;
80 
81  BOOST_FOREACH(BookPtr ptr, books_)
82  {
83  BOOST_ASSERT(ptr);
84  onOrderBookUpdated_(*ptr);
85  }
86 }
87 
89 {
90  BOOST_ASSERT(impl_.get() != nullptr);
91 
92  BookPtr bookPtr = impl_->get(message.orderBookId());
93 
94  if(!bookPtr)
95  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown security id: %d", message.orderBookId()).c_str());
96 
97  if(message.side() == Side::Sell)
98  {
99  BOOST_ASSERT(checkOrderExistence(bookPtr->askOrders().orders(), message.orderId(), false));
100  bookPtr->askOrders().update(Order(message.orderId(), message.price(), message.quantity()));
101  }
102  else if(message.side() == Side::Buy)
103  {
104  BOOST_ASSERT(checkOrderExistence(bookPtr->bidOrders().orders(), message.orderId(), false));
105  bookPtr->bidOrders().update(Order(message.orderId(), message.price(), message.quantity()));
106  }
107  else
108  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown side, %d", message.side()).c_str());
109 
110  books_.insert(bookPtr);
111 
112  onBookChanged(*bookPtr);
113 }
114 
115 
116 namespace {
117  struct FindById : public std::binary_function<const Order*, OrderId, bool>
118  {
119  bool operator()(const Order* order, OrderId id) const
120  {
121  BOOST_ASSERT(order != nullptr);
122  return (order->id_ == id);
123  }
124  };
125 }
126 
127 template <typename OrderList>
128 bool OrderBookHolder::checkOrderExistence(const OrderList& list, OrderId orderId, bool shouldExist)
129 {
130  typename OrderList::const_iterator pos = std::find_if(list.begin(), list.end(), std::bind2nd(FindById(), orderId));
131 
132  if(shouldExist)
133  if(pos == list.end())
134  throw OperationException (__FUNCTION__, OnixS::Util::format("Order does not exist, %llu", orderId).c_str());
135 
136  if(!shouldExist)
137  if(pos != list.end())
138  throw OperationException (__FUNCTION__, OnixS::Util::format("Order already exists, %llu", orderId).c_str());
139 
140  return true;
141 }
142 
143 
144 Side::Enum OrderBookHolder::getOrderSide(BookPtr bookPtr, OrderId orderId)
145 {
146  if(std::find_if(bookPtr->askOrders().orders().begin(), bookPtr->askOrders().orders().end(), std::bind2nd(FindById(), orderId)) != bookPtr->askOrders().orders().end())
147  return Side::Sell;
148  else if(std::find_if(bookPtr->bidOrders().orders().begin(), bookPtr->bidOrders().orders().end(), std::bind2nd(FindById(), orderId)) != bookPtr->bidOrders().orders().end())
149  return Side::Buy;
150  else
151  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown side for order, %llu", orderId).c_str());
152 }
153 
155 {
156  BOOST_ASSERT(!snapshotRecoveryInProgress_);
157 
158  BOOST_ASSERT(impl_.get() != nullptr);
159 
160  BookPtr bookPtr = impl_->get(message.orderBookId());
161 
162  if(!bookPtr)
163  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown book id: %d", message.orderBookId()).c_str());
164 
165  const OrderId orderId = message.orderId();
166 
167  if(message.side() == Side::Sell)
168  {
169  BOOST_ASSERT(checkOrderExistence(bookPtr->askOrders().orders(), orderId, true));
170 
171  const Order& order = bookPtr->askOrders().find(orderId);
172  const Price price = order.price_;
173  const Quantity oldQuantity = order.quantity_;
174 
175  bookPtr->askOrders().remove(orderId);
176 
177  const Quantity newQuantity = oldQuantity - message.executedQuantity();
178 
179  if(newQuantity != 0)
180  bookPtr->askOrders().update(Order(orderId, price, newQuantity));
181  }
182  else if(message.side() == Side::Buy)
183  {
184  BOOST_ASSERT(checkOrderExistence(bookPtr->bidOrders().orders(), orderId, true));
185 
186  const Order& order = bookPtr->bidOrders().find(orderId);
187  const Price price = order.price_;
188  const Quantity oldQuantity = order.quantity_;
189 
190  bookPtr->bidOrders().remove(orderId);
191 
192  const Quantity newQuantity = oldQuantity - message.executedQuantity();
193 
194  if(newQuantity != 0)
195  bookPtr->bidOrders().update(Order(orderId, price, newQuantity));
196  }
197  else
198  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown side, %d", message.side()).c_str());
199 
200  onBookChanged(*bookPtr);
201 }
202 
204 {
205  BOOST_ASSERT(!snapshotRecoveryInProgress_);
206  BOOST_ASSERT(impl_.get() != nullptr);
207 
208  if(!message.printable())
209  return;
210 
211  BookPtr bookPtr = impl_->get(message.orderBookId());
212 
213  if(!bookPtr)
214  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown book id: %d", message.orderBookId()).c_str());
215 
216  const OrderId orderId = message.orderId();
217 
218  if(message.side() == Side::Sell)
219  {
220  BOOST_ASSERT(checkOrderExistence(bookPtr->askOrders().orders(), orderId, true));
221 
222  const Order& order = bookPtr->askOrders().find(orderId);
223  const Price price = order.price_;
224  const Quantity oldQuantity = order.quantity_;
225 
226  bookPtr->askOrders().remove(orderId);
227 
228  const Quantity newQuantity = oldQuantity - message.executedQuantity();
229 
230  if(newQuantity != 0)
231  bookPtr->askOrders().update(Order(orderId, price, newQuantity));
232  }
233  else if(message.side() == Side::Buy)
234  {
235  BOOST_ASSERT(checkOrderExistence(bookPtr->bidOrders().orders(), orderId, true));
236 
237  const Order& order = bookPtr->bidOrders().find(orderId);
238  const Price price = order.price_;
239  const Quantity oldQuantity = order.quantity_;
240 
241  bookPtr->bidOrders().remove(orderId);
242 
243  const Quantity newQuantity = oldQuantity - message.executedQuantity();
244 
245  if(newQuantity != 0)
246  bookPtr->bidOrders().update(Order(orderId, price, newQuantity));
247  }
248  else
249  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown side, %d", message.side()).c_str());
250 
251  onBookChanged(*bookPtr);
252 }
253 
255 {
256  BOOST_ASSERT(!snapshotRecoveryInProgress_);
257  BOOST_ASSERT(impl_.get() != nullptr);
258 
259  BookPtr bookPtr = impl_->get(message.orderBookId());
260 
261  if (!bookPtr)
262  throw OperationException(__FUNCTION__, OnixS::Util::format("Unknown book id: %d", message.orderBookId()).c_str());
263 
264  const OrderId orderId = message.orderId();
265  const Side::Enum side = getOrderSide(bookPtr, orderId);
266 
267  if (side == Side::Sell)
268  {
269  const Price price =
270  bookPtr->askOrders().find(orderId).price_;
271 
272  bookPtr->askOrders().remove(orderId);
273  bookPtr->askOrders().update(Order(orderId, price, message.quantity()));
274  }
275  else if (side == Side::Buy)
276  {
277  const Price price =
278  bookPtr->bidOrders().find(orderId).price_;
279 
280  bookPtr->bidOrders().remove(orderId);
281  bookPtr->bidOrders().update(Order(orderId, price, message.quantity()));
282  }
283 
284  onBookChanged(*bookPtr);
285 }
286 
288 {
289  BOOST_ASSERT(!snapshotRecoveryInProgress_);
290  BOOST_ASSERT(impl_.get() != nullptr);
291 
292  BookPtr bookPtr = impl_->get(message.orderBookId());
293 
294  if(!bookPtr)
295  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown book id: %d", message.orderBookId()).c_str());
296 
297  const OrderId orderId = message.orderId();
298 
299  if(message.side() == Side::Sell)
300  {
301  BOOST_ASSERT(checkOrderExistence(bookPtr->askOrders().orders(), orderId, true));
302  bookPtr->askOrders().remove(orderId);
303  }
304  else if(message.side() == Side::Buy)
305  {
306  BOOST_ASSERT(checkOrderExistence(bookPtr->bidOrders().orders(), orderId, true));
307  bookPtr->bidOrders().remove(orderId);
308  }
309  else
310  throw OperationException (__FUNCTION__, OnixS::Util::format("Unknown side, %d", message.side()).c_str());
311 
312  onBookChanged(*bookPtr);
313 }
314 
316 {
317  BOOST_ASSERT(impl_.get() != nullptr);
318 
319  BOOST_FOREACH(BookPtr ptr, books_)
320  {
321  BOOST_ASSERT(ptr);
322  ptr->clear();
323  }
324 
325  books_.clear();
326 }
327 
328 void OrderBookHolder::onBookOutOfDate(const boost::function<void(const OrderBookInternal&)>& onOrderBookOutOfDate)
329 {
330  BOOST_FOREACH(BookPtr ptr, books_)
331  {
332  BOOST_ASSERT(ptr);
333  onOrderBookOutOfDate(*ptr);
334  }
335 }
336 
337 void OrderBookHolder::onBookChanged(const OrderBookInternal& book)
338 {
339  if (!snapshotRecoveryInProgress_)
340  onOrderBookUpdated_(book);
341 }
342 
343 ONIXS_HANDLER_NAMESPACE_END
OrderBookRegistry< OrderBookId, OrderBookInternal, OrderBookCreator > BookRegistry
UInt64 OrderId
Alias for OrderId type.
Definition: Defines.h:40
OrderBookHolder(const OnOrderBookUpdatedCallback &onOrderBookUpdated, OrderBookAllocator *bookAllocator, size_t bookDepth=DefaultBookDepth)
OnixS::HandlerCore::MarketData::FullOrderDepthBookCreator< OrderBookInternal, false > FullOrderDepthBookCreator
Quantity executedQuantity() const
The quantity being executed.
Side::Enum side() const
The type of order being added.
Definition: AddOrderMsg.h:52
OrderBookId orderBookId() const
The Order Book ID.
Quantity quantity() const
The new visible quantity of the order.
OrderBookId orderBookId() const
The Order Book ID.
Price price() const
The display price of the new order.
Definition: AddOrderMsg.h:71
UInt64 Quantity
Alias for Quantity type.
Definition: Defines.h:46
UInt32 OrderBookId
Alias for Security Id type.
Definition: Defines.h:43
Side::Enum side() const
The type of order being added.
void onBookOutOfDate(const boost::function< void(const OrderBookInternal &)> &onOrderBookOutOfDate)
Side::Enum side() const
The type of order being added.
OrderId orderId() const
The identifier assigned to the new order.
Definition: AddOrderMsg.h:40
OrderBookCreator(size_t bookDepth, OrderBookAllocator *bookAllocator)
Quantity executedQuantity() const
The quantity being executed.
boost::function< void(const OrderBookInternal &)> OnOrderBookUpdatedCallback
void onOrderExecutedWithPrice(const OrderExecutedWithPriceMsg &)
OrderId orderId() const
The order ID is associated with the executed order.
OrderBookId orderBookId() const
The Order Book ID.
Definition: AddOrderMsg.h:46
OrderId orderId() const
The order ID is associated with the executed order.
Quantity quantity() const
The visible quantity of the order.
Definition: AddOrderMsg.h:65
OrderId orderId() const
The ID of the order being deleted.
Side::Enum side() const
The type of order being added.
boost::shared_ptr< OrderBookInternal > operator()(const OrderBookId &id) const
OrderBookId orderBookId() const
The Order Book ID.