libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
order_book.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 ** Copyright © 2015 by J.M.McGuiness, isimud@hussar.me.uk
3 **
4 ** This library is free software; you can redistribute it and/or
5 ** modify it under the terms of the GNU Lesser General Public
6 ** License as published by the Free Software Foundation; either
7 ** version 2.1 of the License, or (at your option) any later version.
8 **
9 ** This library is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ** Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public
15 ** License along with this library; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 
19 #include "stdafx.h"
20 
21 #define BOOST_TEST_MODULE isimud_tests
22 #include <boost/test/included/unit_test.hpp>
23 
24 #include <boost/mpl/list.hpp>
25 
26 #include "../exchanges/order_book/order_book.hpp"
27 
28 #include "../exchanges/FIX/v5.0sp2/fix.hpp"
29 #include "../exchanges/MIT/BIT/bit.hpp"
30 /* TODO Not bothering to get the rest of these working until I need it..,
31 #include "../exchanges/MIT/JSE/jse.hpp"
32 #include "../exchanges/MIT/LSE/lse.hpp"
33 #include "../exchanges/MIT/OSLO/oslo.hpp"
34 #include "../exchanges/MIT/TRQ/trq.hpp"
35 #include "../exchanges/BATSBOE/EU/v1/batsboe.hpp"
36 #include "../exchanges/BATSBOE/EU/v2/batsboe.hpp"
37 #include "../exchanges/BATSBOE/US/v1/batsboe.hpp"
38 #include "../exchanges/BATSBOE/US/v2/batsboe.hpp"
39 */
40 
41 using namespace libjmmcg;
42 using namespace libisimud;
43 
44 using ob_t_types=boost::mpl::list<
45  order_book<exchanges::FIX::v5_0sp2::MsgTypes>/* TODO Not bothering to get the rest of these working until I need it..,
46  order_book<exchanges::MIT::BIT::MsgTypes>,
47  order_book<exchanges::MIT::JSE::MsgTypes>,
48  order_book<exchanges::MIT::LSE::MsgTypes>,
49  order_book<exchanges::MIT::OSLO::MsgTypes>,
50  order_book<exchanges::MIT::TRQ::MsgTypes>,
51  order_book<exchanges::BATSBOE::v1::EU::MsgTypes>,
52  order_book<exchanges::BATSBOE::v2::EU::MsgTypes>,
53  order_book<exchanges::BATSBOE::v1::US::MsgTypes>,
54  order_book<exchanges::BATSBOE::v2::US::MsgTypes>*/
55 >;
56 
57 BOOST_AUTO_TEST_SUITE(order_book_basic)
58 
59 /**
60  \test Ctor
61  ============================
62  Verify it can be simply created.
63 */
64 BOOST_AUTO_TEST_CASE_TEMPLATE(ctor, ob_t, ob_t_types) {
65  BOOST_CHECK_NO_THROW(ob_t{});
66 }
67 
68 /**
69  \test Initially it has no orders.
70  ============================
71 */
72 BOOST_AUTO_TEST_CASE_TEMPLATE(initially_no_orders, ob_t, ob_t_types) {
73  using symbol_t=typename ob_t::symbol_t;
74 
75  ob_t ob;
76  BOOST_CHECK(ob.empty());
77  BOOST_CHECK(!ob.is_crossed());
78  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 0);
79  BOOST_CHECK(ob.match().empty());
80 }
81 
82 /**
83  \test Can print default ctor'd order_book.
84  ============================
85 */
86 BOOST_AUTO_TEST_CASE_TEMPLATE(stream_out_default_ctor, ob_t, ob_t_types) {
87  ob_t ob;
88  std::stringstream ss;
89  ss<<ob;
90  BOOST_CHECK(!ss.str().empty());
91 }
92 
93 /**
94  \test Place an order - must not be empty.
95  =============================
96 */
97 BOOST_AUTO_TEST_CASE_TEMPLATE(place_order_not_empty, ob_t, ob_t_types) {
98  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
99  using OrderType=typename ob_t::msg_details_t::OrderType;
100  using TIF=typename ob_t::msg_details_t::TIF;
101  using side=typename ob_t::side_t;
102  using symbol_t=typename ob_t::symbol_t;
103  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
104  using Price_t=typename ob_t::msg_details_t::Price_t;
105  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
106 
107  ob_t ob;
108  typename ob_t::order_t o(SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON);
109  BOOST_CHECK_NO_THROW(ob.place(o));
110  BOOST_CHECK(!ob.empty());
111  BOOST_CHECK(!ob.is_crossed());
112  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 0);
113  BOOST_CHECK(ob.match().empty());
114  std::stringstream ss;
115  ss<<ob;
116  BOOST_CHECK(!ss.str().empty());
117  char const output[]="=================\nASK\n110: 5\n------------\nBID\n=================\n";
118  BOOST_CHECK_EQUAL(ss.str(), output);
119 }
120 
121 /**
122  \test Place a sell & a buy order, uncrossed.
123 * =============================
124 */
125 BOOST_AUTO_TEST_CASE_TEMPLATE(place_a_sell_and_a_buy_orders, ob_t, ob_t_types) {
126  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
127  using OrderType=typename ob_t::msg_details_t::OrderType;
128  using TIF=typename ob_t::msg_details_t::TIF;
129  using side=typename ob_t::side_t;
130  using symbol_t=typename ob_t::symbol_t;
131  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
132  using Price_t=typename ob_t::msg_details_t::Price_t;
133  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
134 
135  ob_t ob;
136  typename ob_t::order_t o_s(SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON);
137  BOOST_CHECK_NO_THROW(ob.place(o_s));
138  typename ob_t::order_t o_b{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
139  BOOST_CHECK_NO_THROW(ob.place(o_b));
140  BOOST_CHECK(!ob.empty());
141  BOOST_CHECK(!ob.is_crossed());
142  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 20);
143  BOOST_CHECK(ob.match().empty());
144  std::stringstream ss;
145  ss<<ob;
146  BOOST_CHECK(!ss.str().empty());
147  char const output[]="=================\nASK\n110: 5\n------------\n90: 10\nBID\n=================\n";
148  BOOST_CHECK_EQUAL(ss.str(), output);
149 }
150 
151 /**
152  \test Place a sell then a buy order, then another sell, uncrossed.
153 * =============================
154 */
155 BOOST_AUTO_TEST_CASE_TEMPLATE(place_two_sells_and_a_buy_orders, ob_t, ob_t_types) {
156  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
157  using OrderType=typename ob_t::msg_details_t::OrderType;
158  using TIF=typename ob_t::msg_details_t::TIF;
159  using side=typename ob_t::side_t;
160  using symbol_t=typename ob_t::symbol_t;
161  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
162  using Price_t=typename ob_t::msg_details_t::Price_t;
163  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
164 
165  ob_t ob;
166  typename ob_t::order_t o_s1(SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON);
167  BOOST_CHECK_NO_THROW(ob.place(o_s1));
168  typename ob_t::order_t o_b{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
169  BOOST_CHECK_NO_THROW(ob.place(o_b));
170  typename ob_t::order_t o_s2{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
171  BOOST_CHECK_NO_THROW(ob.place(o_s2));
172  BOOST_CHECK(!ob.empty());
173  BOOST_CHECK(!ob.is_crossed());
174  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 20);
175  BOOST_CHECK(ob.match().empty());
176  std::stringstream ss;
177  ss<<ob;
178  BOOST_CHECK(!ss.str().empty());
179  char const output[]="=================\nASK\n110: 5 10\n------------\n90: 10\nBID\n=================\n";
180  BOOST_CHECK_EQUAL(ss.str(), output);
181 }
182 
183 /**
184  \test Place more orders, uncrossed.
185 * =============================
186 */
187 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders, ob_t, ob_t_types) {
188  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
189  using OrderType=typename ob_t::msg_details_t::OrderType;
190  using TIF=typename ob_t::msg_details_t::TIF;
191  using side=typename ob_t::side_t;
192  using symbol_t=typename ob_t::symbol_t;
193  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
194  using Price_t=typename ob_t::msg_details_t::Price_t;
195  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
196 
197  ob_t ob;
198  typename ob_t::order_t o_s[]={
199  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
200  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
201  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
202  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
203  };
204  typename ob_t::order_t o_b[]={
205  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
206  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
207  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
208  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
209  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
210  };
211  for (auto const &o : o_s) {
212  BOOST_CHECK_NO_THROW(ob.place(o));
213  }
214  for (auto const &o : o_b) {
215  BOOST_CHECK_NO_THROW(ob.place(o));
216  }
217  BOOST_CHECK(!ob.empty());
218  BOOST_CHECK(!ob.is_crossed());
219  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 5);
220  BOOST_CHECK(ob.match().empty());
221  std::stringstream ss;
222  ss<<ob;
223  BOOST_CHECK(!ss.str().empty());
224  char const output[]="=================\nASK\n110: 5 10\n105: 3 7\n------------\n100: 4 6\n90: 10 2 3\nBID\n=================\n";
225  BOOST_CHECK_EQUAL(ss.str(), output);
226 }
227 
228 /**
229  \test Place more orders, then an aggressive one to cross the exchange.
230 * =============================
231 */
232 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_cross, ob_t, ob_t_types) {
233  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
234  using OrderType=typename ob_t::msg_details_t::OrderType;
235  using TIF=typename ob_t::msg_details_t::TIF;
236  using side=typename ob_t::side_t;
237  using symbol_t=typename ob_t::symbol_t;
238  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
239  using Price_t=typename ob_t::msg_details_t::Price_t;
240  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
241 
242  ob_t ob;
243  typename ob_t::order_t o_s[]={
244  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
245  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
246  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
247  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
248  };
249  typename ob_t::order_t o_b[]={
250  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
251  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
252  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
253  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
254  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
255  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
256  };
257  for (auto const &o : o_s) {
258  BOOST_CHECK_NO_THROW(ob.place(o));
259  }
260  for (auto const &o : o_b) {
261  BOOST_CHECK_NO_THROW(ob.place(o));
262  }
263  BOOST_CHECK(!ob.empty());
264  BOOST_CHECK(ob.is_crossed());
265  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 0);
266  std::stringstream ss;
267  ss<<ob;
268  BOOST_CHECK(!ss.str().empty());
269  char const output[]="=================\nASK\n110: 5 10\n105: 3 7\n------------\n105: 4\n100: 4 6\n90: 10 2 3\nBID\n=================\n";
270  BOOST_CHECK_EQUAL(ss.str(), output);
271 }
272 
273 /**
274  \test Place more orders, then an aggressive buy one to cross the exchange, then match for any executions.
275 * =============================
276 */
277 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_buy_crosses_then_match, ob_t, ob_t_types) {
278  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
279  using OrderType=typename ob_t::msg_details_t::OrderType;
280  using TIF=typename ob_t::msg_details_t::TIF;
281  using side=typename ob_t::side_t;
282  using symbol_t=typename ob_t::symbol_t;
283  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
284  using Price_t=typename ob_t::msg_details_t::Price_t;
285  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
286 
287  ob_t ob;
288  typename ob_t::order_t o_s[]={
289  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
290  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
291  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
292  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
293  };
294  typename ob_t::order_t o_b[]={
295  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
296  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
297  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
298  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
299  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
300  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive buy.
301  };
302  for (auto const &o : o_s) {
303  BOOST_CHECK_NO_THROW(ob.place(o));
304  }
305  for (auto const &o : o_b) {
306  BOOST_CHECK_NO_THROW(ob.place(o));
307  }
308  BOOST_CHECK(ob.is_crossed());
309  auto const &executions=ob.match();
310  BOOST_CHECK(!ob.is_crossed());
311  BOOST_CHECK(!executions.empty());
312  BOOST_REQUIRE_EQUAL(executions.size(), 2);
313  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 105);
314  BOOST_CHECK_EQUAL(executions[0].orderQty(), 3);
315  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 105);
316  BOOST_CHECK_EQUAL(executions[1].orderQty(), 1);
317  std::stringstream ss;
318  ss<<ob;
319  BOOST_CHECK(!ss.str().empty());
320  char const output[]="=================\nASK\n110: 5 10\n105: 6\n------------\n100: 4 6\n90: 10 2 3\nBID\n=================\n";
321  BOOST_CHECK_EQUAL(ss.str(), output);
322 }
323 
324 /**
325  \test Place more orders, then an aggressive sell one to cross the exchange, then match for any executions.
326 * =============================
327 */
328 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_sell_crosses_then_match, ob_t, ob_t_types) {
329  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
330  using OrderType=typename ob_t::msg_details_t::OrderType;
331  using TIF=typename ob_t::msg_details_t::TIF;
332  using side=typename ob_t::side_t;
333  using symbol_t=typename ob_t::symbol_t;
334  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
335  using Price_t=typename ob_t::msg_details_t::Price_t;
336  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
337 
338  ob_t ob;
339  typename ob_t::order_t o_s[]={
340  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
341  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
342  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
343  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
344  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive sell.
345  };
346  typename ob_t::order_t o_b[]={
347  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
348  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
349  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
350  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
351  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
352  };
353  for (auto const &o : o_s) {
354  BOOST_CHECK_NO_THROW(ob.place(o));
355  }
356  for (auto const &o : o_b) {
357  BOOST_CHECK_NO_THROW(ob.place(o));
358  }
359  BOOST_CHECK(ob.is_crossed());
360  auto const &executions=ob.match();
361  BOOST_CHECK(!ob.is_crossed());
362  BOOST_CHECK(!executions.empty());
363  BOOST_REQUIRE_EQUAL(executions.size(), 2);
364  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 100);
365  BOOST_CHECK_EQUAL(executions[0].orderQty(), 4);
366  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 100);
367  BOOST_CHECK_EQUAL(executions[1].orderQty(), 3);
368  std::stringstream ss;
369  ss<<ob;
370  BOOST_CHECK(!ss.str().empty());
371  char const output[]="=================\nASK\n110: 5 10\n105: 3 7\n------------\n100: 3\n90: 10 2 3\nBID\n=================\n";
372  BOOST_CHECK_EQUAL(ss.str(), output);
373 }
374 
375 /**
376  \test Place more orders, then an aggressive buy one to cross the exchange, then match for any executions, removing some exactly.
377 * =============================
378 */
379 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_buy_crosses_then_match_exact, ob_t, ob_t_types) {
380  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
381  using OrderType=typename ob_t::msg_details_t::OrderType;
382  using TIF=typename ob_t::msg_details_t::TIF;
383  using side=typename ob_t::side_t;
384  using symbol_t=typename ob_t::symbol_t;
385  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
386  using Price_t=typename ob_t::msg_details_t::Price_t;
387  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
388 
389  ob_t ob;
390  typename ob_t::order_t o_s[]={
391  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
392  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
393  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
394  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
395  };
396  typename ob_t::order_t o_b[]={
397  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
398  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
399  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
400  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
401  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
402  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive buy.
403  };
404  for (auto const &o : o_s) {
405  BOOST_CHECK_NO_THROW(ob.place(o));
406  }
407  for (auto const &o : o_b) {
408  BOOST_CHECK_NO_THROW(ob.place(o));
409  }
410  BOOST_CHECK(ob.is_crossed());
411  auto const &executions=ob.match();
412  BOOST_CHECK(!ob.is_crossed());
413  BOOST_CHECK(!executions.empty());
414  BOOST_REQUIRE_EQUAL(executions.size(), 2);
415  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 105);
416  BOOST_CHECK_EQUAL(executions[0].orderQty(), 3);
417  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 105);
418  BOOST_CHECK_EQUAL(executions[1].orderQty(), 7);
419  std::stringstream ss;
420  ss<<ob;
421  BOOST_CHECK(!ss.str().empty());
422  char const output[]="=================\nASK\n110: 5 10\n------------\n100: 4 6\n90: 10 2 3\nBID\n=================\n";
423  BOOST_CHECK_EQUAL(ss.str(), output);
424 }
425 
426 /**
427  \test Place more orders, then an aggressive sell one to cross the exchange, then match for any executions, removing some exactly.
428 * =============================
429 */
430 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_sell_crosses_then_match_exact, ob_t, ob_t_types) {
431  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
432  using OrderType=typename ob_t::msg_details_t::OrderType;
433  using TIF=typename ob_t::msg_details_t::TIF;
434  using side=typename ob_t::side_t;
435  using symbol_t=typename ob_t::symbol_t;
436  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
437  using Price_t=typename ob_t::msg_details_t::Price_t;
438  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
439 
440  ob_t ob;
441  typename ob_t::order_t o_s[]={
442  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
443  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
444  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
445  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
446  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive sell.
447  };
448  typename ob_t::order_t o_b[]={
449  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
450  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
451  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
452  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
453  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
454  };
455  for (auto const &o : o_s) {
456  BOOST_CHECK_NO_THROW(ob.place(o));
457  }
458  for (auto const &o : o_b) {
459  BOOST_CHECK_NO_THROW(ob.place(o));
460  }
461  BOOST_CHECK(ob.is_crossed());
462  auto const &executions=ob.match();
463  BOOST_CHECK(!ob.is_crossed());
464  BOOST_CHECK(!executions.empty());
465  BOOST_REQUIRE_EQUAL(executions.size(), 2);
466  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 100);
467  BOOST_CHECK_EQUAL(executions[0].orderQty(), 4);
468  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 100);
469  BOOST_CHECK_EQUAL(executions[1].orderQty(), 6);
470  std::stringstream ss;
471  ss<<ob;
472  BOOST_CHECK(!ss.str().empty());
473  char const output[]="=================\nASK\n110: 5 10\n105: 3 7\n------------\n90: 10 2 3\nBID\n=================\n";
474  BOOST_CHECK_EQUAL(ss.str(), output);
475 }
476 
477 /**
478  \test Place more orders, then an aggressive buy then an aggressive sell, both crossing the exchange, then match for any executions.
479 * =============================
480 */
481 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_buy_and_sell_crosses_then_match, ob_t, ob_t_types) {
482  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
483  using OrderType=typename ob_t::msg_details_t::OrderType;
484  using TIF=typename ob_t::msg_details_t::TIF;
485  using side=typename ob_t::side_t;
486  using symbol_t=typename ob_t::symbol_t;
487  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
488  using Price_t=typename ob_t::msg_details_t::Price_t;
489  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
490 
491  ob_t ob;
492  typename ob_t::order_t o_s[]={
493  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
494  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
495  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
496  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
497  };
498  typename ob_t::order_t o_b[]={
499  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
500  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
501  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
502  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
503  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
504  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive buy.
505  };
506  for (auto const &o : o_s) {
507  BOOST_CHECK_NO_THROW(ob.place(o));
508  }
509  for (auto const &o : o_b) {
510  BOOST_CHECK_NO_THROW(ob.place(o));
511  }
512  BOOST_CHECK_NO_THROW(ob.match());
513  typename ob_t::order_t aggressive_sell{SeqNum_t{10}, ClientOrderID_t{"10"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{23}, Price_t{80}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
514  ob.place(aggressive_sell);
515  BOOST_CHECK(ob.is_crossed());
516  auto const &executions=ob.match();
517  BOOST_CHECK(!ob.is_crossed());
518  BOOST_CHECK(!executions.empty());
519  BOOST_REQUIRE_EQUAL(executions.size(), 5);
520  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 100);
521  BOOST_CHECK_EQUAL(executions[0].orderQty(), 4);
522  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 100);
523  BOOST_CHECK_EQUAL(executions[1].orderQty(), 6);
524  BOOST_CHECK_EQUAL(executions[2].limitPrice(), 90);
525  BOOST_CHECK_EQUAL(executions[2].orderQty(), 10);
526  BOOST_CHECK_EQUAL(executions[3].limitPrice(), 90);
527  BOOST_CHECK_EQUAL(executions[3].orderQty(), 2);
528  BOOST_CHECK_EQUAL(executions[4].limitPrice(), 90);
529  BOOST_CHECK_EQUAL(executions[4].orderQty(), 1);
530  std::stringstream ss;
531  ss<<ob;
532  BOOST_CHECK(!ss.str().empty());
533  char const output[]="=================\nASK\n110: 5 10\n105: 6\n------------\n90: 2\nBID\n=================\n";
534  BOOST_CHECK_EQUAL(ss.str(), output);
535 }
536 
537 /**
538  \test Place more orders, then an aggressive buy then an aggressive sell then an aggressive buy, all crossing the exchange, then match for any executions.
539 * =============================
540 */
541 BOOST_AUTO_TEST_CASE_TEMPLATE(place_more_orders_then_buy_sell_and_buy_crosses_then_match, ob_t, ob_t_types) {
542  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
543  using OrderType=typename ob_t::msg_details_t::OrderType;
544  using TIF=typename ob_t::msg_details_t::TIF;
545  using side=typename ob_t::side_t;
546  using symbol_t=typename ob_t::symbol_t;
547  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
548  using Price_t=typename ob_t::msg_details_t::Price_t;
549  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
550 
551  ob_t ob;
552  typename ob_t::order_t o_s[]={
553  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
554  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
555  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
556  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{7}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
557  };
558  typename ob_t::order_t o_b[]={
559  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
560  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
561  typename ob_t::order_t{SeqNum_t{6}, ClientOrderID_t{"6"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
562  typename ob_t::order_t{SeqNum_t{7}, ClientOrderID_t{"7"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
563  typename ob_t::order_t{SeqNum_t{8}, ClientOrderID_t{"8"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
564  typename ob_t::order_t{SeqNum_t{9}, ClientOrderID_t{"9"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON} // Aggressive buy.
565  };
566  for (auto const &o : o_s) {
567  BOOST_CHECK_NO_THROW(ob.place(o));
568  }
569  for (auto const &o : o_b) {
570  BOOST_CHECK_NO_THROW(ob.place(o));
571  }
572  BOOST_CHECK_NO_THROW(ob.match());
573  typename ob_t::order_t aggressive_sell{SeqNum_t{10}, ClientOrderID_t{"10"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{23}, Price_t{80}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
574  ob.place(aggressive_sell);
575  BOOST_CHECK_NO_THROW(ob.match());
576  typename ob_t::order_t aggressive_buy{SeqNum_t{11}, ClientOrderID_t{"11"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{8}, Price_t{107}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
577  ob.place(aggressive_buy);
578  BOOST_CHECK(ob.is_crossed());
579  auto const &executions=ob.match();
580  BOOST_CHECK(!ob.is_crossed());
581  BOOST_CHECK(!executions.empty());
582  BOOST_REQUIRE_EQUAL(executions.size(), 1);
583  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 105);
584  BOOST_CHECK_EQUAL(executions[0].orderQty(), 6);
585  std::stringstream ss;
586  ss<<ob;
587  BOOST_CHECK(!ss.str().empty());
588  char const output[]="=================\nASK\n110: 5 10\n------------\n107: 2\n90: 2\nBID\n=================\n";
589  BOOST_CHECK_EQUAL(ss.str(), output);
590 }
591 
592 /**
593  \test Place more orders, then cancel one of them.
594 * =============================
595 */
596 BOOST_AUTO_TEST_CASE_TEMPLATE(place_orders_then_cancel_one, ob_t, ob_t_types) {
597  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
598  using OrderType=typename ob_t::msg_details_t::OrderType;
599  using TIF=typename ob_t::msg_details_t::TIF;
600  using side=typename ob_t::side_t;
601  using symbol_t=typename ob_t::symbol_t;
602  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
603  using Price_t=typename ob_t::msg_details_t::Price_t;
604  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
605 
606  ob_t ob;
607  typename ob_t::order_t o_s[]={
608  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
609  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
610  };
611  typename ob_t::order_t o_b[]={
612  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
613  typename ob_t::order_t{SeqNum_t{5}, ClientOrderID_t{"5"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
614  };
615  for (auto const &o : o_s) {
616  BOOST_CHECK_NO_THROW(ob.place(o));
617  }
618  for (auto const &o : o_b) {
619  BOOST_CHECK_NO_THROW(ob.place(o));
620  }
621  BOOST_CHECK(!ob.empty());
622  BOOST_CHECK(!ob.is_crossed());
623  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 5);
624  BOOST_CHECK(ob.match().empty());
625  BOOST_CHECK_NO_THROW(ob.cancel(o_s[1]));
626  BOOST_CHECK(!ob.empty());
627  BOOST_CHECK(!ob.is_crossed());
628  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 10);
629  BOOST_CHECK(ob.match().empty());
630  std::stringstream ss;
631  ss<<ob;
632  BOOST_CHECK(!ss.str().empty());
633 }
634 
635 /**
636  \test Place more orders, then cancel one of them then place an aggressive buy and match.
637 * =============================
638 */
639 BOOST_AUTO_TEST_CASE_TEMPLATE(place_orders_then_cancel_one_buy_match, ob_t, ob_t_types) {
640  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
641  using OrderType=typename ob_t::msg_details_t::OrderType;
642  using TIF=typename ob_t::msg_details_t::TIF;
643  using side=typename ob_t::side_t;
644  using symbol_t=typename ob_t::symbol_t;
645  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
646  using Price_t=typename ob_t::msg_details_t::Price_t;
647  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
648 
649  ob_t ob;
650  typename ob_t::order_t o_s[]={
651  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
652  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
653  };
654  typename ob_t::order_t o_b[]={
655  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
656  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
657  };
658  for (auto const &o : o_s) {
659  BOOST_CHECK_NO_THROW(ob.place(o));
660  }
661  for (auto const &o : o_b) {
662  BOOST_CHECK_NO_THROW(ob.place(o));
663  }
664  BOOST_CHECK_NO_THROW(ob.cancel(o_s[1]));
665  typename ob_t::order_t aggressive_sell{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{23}, Price_t{80}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON};
666  ob.place(aggressive_sell);
667  auto const &executions=ob.match();
668  BOOST_CHECK(!ob.empty());
669  BOOST_CHECK(!ob.is_crossed());
670  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 0);
671  BOOST_CHECK(ob.match().empty());
672  BOOST_REQUIRE_EQUAL(executions.size(), 2);
673  BOOST_CHECK_EQUAL(executions[0].limitPrice(), 100);
674  BOOST_CHECK_EQUAL(executions[0].orderQty(), 4);
675  BOOST_CHECK_EQUAL(executions[1].limitPrice(), 90);
676  BOOST_CHECK_EQUAL(executions[1].orderQty(), 10);
677  std::stringstream ss;
678  ss<<ob;
679  BOOST_CHECK(!ss.str().empty());
680 }
681 
682 /**
683  \test Place more orders, then cancel an unknown symbol then place an aggressive buy and match.
684 * =============================
685 */
686 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_unknown_symbol, ob_t, ob_t_types) {
687  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
688  using OrderType=typename ob_t::msg_details_t::OrderType;
689  using TIF=typename ob_t::msg_details_t::TIF;
690  using side=typename ob_t::side_t;
691  using symbol_t=typename ob_t::symbol_t;
692  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
693  using Price_t=typename ob_t::msg_details_t::Price_t;
694  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
695 
696  ob_t ob;
697  typename ob_t::order_t o_s[]={
698  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
699  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
700  };
701  typename ob_t::order_t o_b[]={
702  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
703  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
704  };
705  for (auto const &o : o_s) {
706  BOOST_CHECK_NO_THROW(ob.place(o));
707  }
708  for (auto const &o : o_b) {
709  BOOST_CHECK_NO_THROW(ob.place(o));
710  }
711  BOOST_CHECK_NO_THROW(ob.cancel(typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"ABC"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
712  BOOST_CHECK(!ob.empty());
713  BOOST_CHECK(!ob.is_crossed());
714  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 5);
715  BOOST_CHECK(ob.match().empty());
716  std::stringstream ss;
717  ss<<ob;
718  BOOST_CHECK(!ss.str().empty());
719 }
720 
721 /**
722  \test Place more orders, then cancel one of them then readd it.
723 * =============================
724 */
725 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_read_symbol, ob_t, ob_t_types) {
726  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
727  using OrderType=typename ob_t::msg_details_t::OrderType;
728  using TIF=typename ob_t::msg_details_t::TIF;
729  using side=typename ob_t::side_t;
730  using symbol_t=typename ob_t::symbol_t;
731  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
732  using Price_t=typename ob_t::msg_details_t::Price_t;
733  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
734 
735  ob_t ob;
736  typename ob_t::order_t o_s[]={
737  typename ob_t::order_t{SeqNum_t{0}, ClientOrderID_t{"0"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{110}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
738  typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
739  typename ob_t::order_t{SeqNum_t{2}, ClientOrderID_t{"2"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{6}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
740  };
741  typename ob_t::order_t o_b[]={
742  typename ob_t::order_t{SeqNum_t{3}, ClientOrderID_t{"3"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{90}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
743  typename ob_t::order_t{SeqNum_t{4}, ClientOrderID_t{"4"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{4}, Price_t{100}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
744  };
745  for (auto const &o : o_s) {
746  BOOST_CHECK_NO_THROW(ob.place(o));
747  }
748  for (auto const &o : o_b) {
749  BOOST_CHECK_NO_THROW(ob.place(o));
750  }
751  BOOST_CHECK_NO_THROW(ob.cancel(typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
752  BOOST_CHECK_NO_THROW(ob.place(typename ob_t::order_t{SeqNum_t{1}, ClientOrderID_t{"1"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{105}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
753  BOOST_CHECK(!ob.empty());
754  BOOST_CHECK(!ob.is_crossed());
755  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 5);
756  BOOST_CHECK(ob.match().empty());
757  std::stringstream ss;
758  ss<<ob;
759  BOOST_CHECK(!ss.str().empty());
760 }
761 
762 /**
763  \test Place some orders, then cancel some of them then check the executions.
764 * =============================
765 */
766 BOOST_AUTO_TEST_CASE_TEMPLATE(process_market_data_example, ob_t, ob_t_types) {
767  using SeqNum_t=typename ob_t::msg_details_t::SeqNum_t;
768  using OrderType=typename ob_t::msg_details_t::OrderType;
769  using TIF=typename ob_t::msg_details_t::TIF;
770  using side=typename ob_t::side_t;
771  using symbol_t=typename ob_t::symbol_t;
772  using ClientOrderID_t=typename ob_t::msg_details_t::ClientOrderID_t;
773  using Price_t=typename ob_t::msg_details_t::Price_t;
774  using Quantity_t=typename ob_t::msg_details_t::Quantity_t;
775 
776  ob_t ob;
777  typename ob_t::order_t o1[]={
778  typename ob_t::order_t{SeqNum_t{100000}, ClientOrderID_t{"100000"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{1}, Price_t{1075}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
779  typename ob_t::order_t{SeqNum_t{100001}, ClientOrderID_t{"100001"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{9}, Price_t{1000}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
780  typename ob_t::order_t{SeqNum_t{100002}, ClientOrderID_t{"100002"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{30}, Price_t{975}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
781  typename ob_t::order_t{SeqNum_t{100003}, ClientOrderID_t{"100003"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{1050}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
782  typename ob_t::order_t{SeqNum_t{100004}, ClientOrderID_t{"100004"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{950}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
783  typename ob_t::order_t{SeqNum_t{100005}, ClientOrderID_t{"100005"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{1025}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
784  typename ob_t::order_t{SeqNum_t{100006}, ClientOrderID_t{"100006"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{1}, Price_t{1000}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
785  };
786  for (auto const &o : o1) {
787  BOOST_CHECK_NO_THROW(ob.place(o));
788  }
789  BOOST_CHECK_NO_THROW(ob.cancel(typename ob_t::order_t{SeqNum_t{100004}, ClientOrderID_t{"100004"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{10}, Price_t{950}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
790  typename ob_t::order_t o2[]={
791  typename ob_t::order_t{SeqNum_t{100007}, ClientOrderID_t{"100007"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{5}, Price_t{1025}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON},
792  typename ob_t::order_t{SeqNum_t{100008}, ClientOrderID_t{"100008"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{1050}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}
793  };
794  for (auto const &o : o2) {
795  BOOST_CHECK_NO_THROW(ob.place(o));
796  }
797  BOOST_CHECK_NO_THROW(ob.cancel(typename ob_t::order_t{SeqNum_t{100008}, ClientOrderID_t{"100008"}, OrderType::Limit, TIF::Day, side::Buy, symbol_t{"XYZ"}, Quantity_t{3}, Price_t{1050}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
798  BOOST_CHECK_NO_THROW(ob.cancel(typename ob_t::order_t{SeqNum_t{100005}, ClientOrderID_t{"100005"}, OrderType::Limit, TIF::Day, side::Sell, symbol_t{"XYZ"}, Quantity_t{2}, Price_t{102}, exchanges::common::mic_codes::ISO_10383_MIC_Codes::ISO_10383_UNITED_KINGDOM_XLON}));
799  BOOST_CHECK(!ob.empty());
800  BOOST_CHECK(!ob.is_crossed());
801  BOOST_CHECK_EQUAL(ob.agreed_spread(symbol_t{"XYZ"}), 75);
802  BOOST_CHECK(ob.match().empty());
803  std::stringstream ss;
804  ss<<ob;
805  BOOST_CHECK(!ss.str().empty());
806 }
807 
808 BOOST_AUTO_TEST_SUITE_END()