21 template<
class MsgType>
24 os<<o.front().limitPrice()<<
": ";
28 std::experimental::make_ostream_joiner(os,
" "),
37 template<
class MsgType>
39 order_book<MsgType>::internal_order::internal_order(sequence_number_t seq, element_type
const &o)
noexcept(
true)
40 : element_type(o), sequence_number_(seq) {
43 template<
class MsgType>
44 inline typename order_book<MsgType>::internal_order &
45 order_book<MsgType>::internal_order::operator=(internal_order
const &o)
noexcept(
true) {
46 this->~internal_order();
47 new (
this) internal_order(o);
51 template<
class MsgType>
54 return l.front().limitPrice()<r.front().limitPrice();
57 template<
class MsgType>
60 return r.front().limitPrice()<l.front().limitPrice();
63 template<
class MsgType>
66 return std::find_if_not(
69 [](
auto const &v) {
return v.empty();}
73 template<
class MsgType>
76 return this->c.front();
79 template<
class MsgType>
82 assert(sequence_number<std::numeric_limits<sequence_number_t>::max()-1);
83 if (
this->c.empty()) {
84 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
86 auto iter=std::lower_bound(
90 [](
auto const &l,
auto const &r) {
91 return l.front().limitPrice()>r.limitPrice();
94 if (iter!=
this->c.end()) {
95 assert(iter->front().limitPrice()<=o.limitPrice());
96 if (iter->front().limitPrice()==o.limitPrice()) {
97 iter->emplace_back(sequence_number++, o);
99 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
102 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
107 template<
class MsgType>
110 auto iter=
std::remove_if(
114 auto iter=
std::remove_if(
117 [&o](
auto const &v) {
118 return o.clientOrderID()==v.clientOrderID();
121 typename std::remove_reference<
decltype(v)>::type tmp(v.begin(), iter);
126 typename std::remove_reference<
decltype(
this->c)>::type tmp(
this->c.begin(), iter);
128 std::sort(
this->c.rbegin(),
this->c.rend(),
this->comp);
131 template<
class MsgType>
132 inline std::ostream &
138 [&os](
auto const &v) {
139 libisimud::to_stream<MsgType>(os, v);
145 template<
class MsgType>
148 return std::find_if_not(
151 [](
auto const &v) {
return v.empty();}
155 template<
class MsgType>
158 return this->c.front();
161 template<
class MsgType>
164 assert(sequence_number<std::numeric_limits<sequence_number_t>::max()-1);
165 if (
this->c.empty()) {
166 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
168 auto iter=std::lower_bound(
172 [](
auto const &l,
auto const &r) {
173 const auto lp=l.front().limitPrice();
174 return lp<r.limitPrice();
177 if (iter!=
this->c.end()) {
178 assert(iter->front().limitPrice()>=o.limitPrice());
179 if (iter->front().limitPrice()==o.limitPrice()) {
180 iter->emplace_back(sequence_number++, o);
182 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
185 this->emplace(1,
typename value_type::value_type{sequence_number++, o});
190 template<
class MsgType>
193 auto iter=
std::remove_if(
197 auto iter=
std::remove_if(
200 [&o](
auto const &v) {
201 return o.clientOrderID()==v.clientOrderID();
204 typename std::remove_reference<
decltype(v)>::type tmp(v.begin(), iter);
209 typename std::remove_reference<
decltype(
this->c)>::type tmp(
this->c.begin(), iter);
211 std::sort(
this->c.begin(),
this->c.end(),
this->comp);
214 template<
class MsgType>
215 inline std::ostream &
220 [&os](
auto const &v) {
221 libisimud::to_stream<MsgType>(os, v);
227 template<
class MsgType>
229 order_book<MsgType>::order_id_t::operator==(order_id_t
const &o)
noexcept(
true) {
230 return order_id_==o.order_id_;
233 template<
class MsgType>
234 inline typename order_book<MsgType>::order_id_t &
235 order_book<MsgType>::order_id_t::operator++()
noexcept(
true) {
236 auto tmp=libjmmcg::fromstring<
std::uint64_t>(order_id_.data(), order_id_.size());
238 [[maybe_unused]]
auto const quash_warning=libjmmcg::tostring(tmp, order_id_.data(), order_id_.size());
242 template<
class MsgType>
243 inline typename order_book<MsgType>::order_id_t
244 order_book<MsgType>::order_id_t::operator++(
int)
noexcept(
true) {
245 const auto tmp=*
this;
250 template<
class MsgType>
255 template<
class MsgType>
260 template<
class MsgType>
263 return all_open_orders_.empty();
266 template<
class MsgType>
269 for (
auto const &open_orders : all_open_orders_) {
270 auto const ask_empty=open_orders.second.open_ask_orders.empty();
271 auto const bid_empty=open_orders.second.open_bid_orders.empty();
272 if ((!ask_empty && !bid_empty) && (open_orders.second.best_bid().limitPrice()>=open_orders.second.best_ask().limitPrice())) {
279 template<
class MsgType>
282 auto iter=all_open_orders_.find(symbol);
283 if (iter!=all_open_orders_.end()) {
284 auto const ask_empty=iter->second.open_ask_orders.empty();
285 auto const bid_empty=iter->second.open_bid_orders.empty();
286 return (ask_empty || bid_empty) ?
false : iter->second.best_ask().limitPrice()-iter->second.best_bid().limitPrice();
292 template<
class MsgType>
295 using namespace libjmmcg;
297 if (sequence_number_>=
std::numeric_limits<sequence_number_t>::max()-1) {
302 switch (order.side()) {
304 all_open_orders_[order.instrumentID()].open_bid_orders.insert(order, sequence_number_);
305 assert(!all_open_orders_[order.instrumentID()].open_bid_orders.empty());
308 all_open_orders_[order.instrumentID()].open_ask_orders.insert(order, sequence_number_);
309 assert(!all_open_orders_[order.instrumentID()].open_ask_orders.empty());
319 template<
class MsgType>
322 using namespace libjmmcg;
324 switch (order.side()) {
326 all_open_orders_[order.instrumentID()].open_bid_orders.erase(order);
329 all_open_orders_[order.instrumentID()].open_ask_orders.erase(order);
337 sequence_number_=sequence_number_t{};
341 template<
class MsgType>
346 for (
auto &open_orders : all_open_orders_) {
347 auto &best_bid_orders=open_orders.second.open_bid_orders.top();
348 auto &best_ask_orders=open_orders.second.open_ask_orders.top();
349 while (!best_ask_orders.empty() && !best_bid_orders.empty()) {
350 auto &best_ask_order=best_ask_orders.front();
351 auto &best_bid_order=best_bid_orders.front();
352 assert(best_ask_order.instrumentID()==best_bid_order.instrumentID());
353 assert(is_crossed());
355 assert(best_bid_order.limitPrice()>=best_ask_order.limitPrice());
356 auto const traded_quantity=std::min(best_ask_order.orderQty(), best_bid_order.orderQty());
358 assert(traded_quantity>quantity_t{});
360 assert(best_ask_order.sequence_number_!=best_bid_order.sequence_number_);
361 auto const &order_to_trade_against=best_ask_order.sequence_number_<best_bid_order.sequence_number_ ? best_ask_order : best_bid_order;
364 order_to_trade_against.clientOrderID(),
365 msg_details_t::ExecType::Trade,
366 order_to_trade_against.limitPrice(),
367 best_ask_order.instrumentID(),
368 best_ask_order.side(),
370 order_to_trade_against.orderQty()-traded_quantity,
371 order_to_trade_against.find_MIC()
373 assert(best_bid_order.orderQty()>=traded_quantity);
374 best_bid_order.orderQty(best_bid_order.orderQty()-traded_quantity);
375 if (best_bid_order.orderQty()<=quantity_t{}) {
377 best_bid_orders.pop_front();
379 best_ask_order.orderQty(best_ask_order.orderQty()-traded_quantity);
380 if (best_ask_order.orderQty()<=quantity_t{}) {
382 best_ask_orders.pop_front();
385 if (best_ask_orders.empty()) {
386 open_orders.second.open_ask_orders.pop();
388 if (best_bid_orders.empty()) {
389 open_orders.second.open_bid_orders.pop();
394 sequence_number_=sequence_number_t{};
399 template<
class MsgType>
401 order_book<MsgType>::open_orders_t::best_bid()
const noexcept(
true) {
402 assert(!open_bid_orders.empty());
403 return open_bid_orders.top().front();
406 template<
class MsgType>
408 order_book<MsgType>::open_orders_t::best_ask()
const noexcept(
true) {
409 assert(!open_ask_orders.empty());
410 return open_ask_orders.top().front();
413 template<
class MsgType>
415 operator<<(
std::ostream &os,
order_book<MsgType>
const &ob) {
420 os<<
"=================\n"
422 if (ob.all_open_orders_.empty()) {
423 os<<
"------------\n";
425 for (
auto const &open_orders : ob.all_open_orders_) {
426 open_orders.second.open_ask_orders.to_stream(os);
427 os<<
"------------\n";
428 open_orders.second.open_bid_orders.to_stream(os);
432 "=================\n";