JayBeams  0.1
Another project to have fun coding.
ut_order_book.cpp
Go to the documentation of this file.
2 
3 #include <boost/test/unit_test.hpp>
4 
5 namespace jb {
6 namespace itch5 {
7 namespace testing {
8 
9 /**
10  * Test order book trivial members.
11  */
12 template <typename book_type>
13 void test_order_book_trivial(book_type& tested) {
14  using jb::itch5::price4_t;
15 
16  auto actual = tested.best_bid();
17  BOOST_CHECK_EQUAL(actual.first, price4_t(0));
18  BOOST_CHECK_EQUAL(actual.second, 0);
19  actual = tested.worst_bid();
20  BOOST_CHECK_EQUAL(actual.first, price4_t(0));
21  BOOST_CHECK_EQUAL(actual.second, 0);
22  actual = tested.best_offer();
23  BOOST_CHECK_EQUAL(actual.first, price4_t(200000UL * 10000));
24  BOOST_CHECK_EQUAL(actual.second, 0);
25  actual = tested.worst_offer();
26  BOOST_CHECK_EQUAL(actual.first, price4_t(200000UL * 10000));
27  BOOST_CHECK_EQUAL(actual.second, 0);
28  // book_depth should be 0
29  BOOST_CHECK_EQUAL(tested.get_book_depth(), 0);
30 }
31 
32 /**
33  * Test order book buy side order handling.
34  */
35 template <typename book_type>
36 void test_order_book_buy_order_handling(book_type& tested) {
37  using jb::itch5::price4_t;
38 
40 
41  // Add a new order ...
42  auto r = tested.handle_add_order(BUY, price4_t(100000), 100);
43  // ... the offer should not change ...
44  auto actual = tested.best_offer();
45  BOOST_CHECK_EQUAL(actual.first, price4_t(200000UL * 10000));
46  BOOST_CHECK_EQUAL(actual.second, 0);
47  actual = tested.worst_offer();
48  BOOST_CHECK_EQUAL(actual.first, price4_t(200000UL * 10000));
49  BOOST_CHECK_EQUAL(actual.second, 0);
50  // .. but the bid should ...
51  actual = tested.best_bid();
52  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
53  BOOST_CHECK_EQUAL(actual.second, 100);
54  actual = tested.worst_bid();
55  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
56  BOOST_CHECK_EQUAL(actual.second, 100);
57  // handler should return true... it is an inside change
58  BOOST_CHECK_EQUAL(r, true);
59  // .. and the book_depth should be incremented
60  BOOST_CHECK_EQUAL(tested.get_book_depth(), 1);
61 
62  // ... adding below the best bid has no effect ...
63  r = tested.handle_add_order(BUY, price4_t(99900), 300);
64  actual = tested.best_bid();
65  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
66  BOOST_CHECK_EQUAL(actual.second, 100);
67  actual = tested.worst_bid();
68  BOOST_CHECK_EQUAL(actual.first, price4_t(99900));
69  BOOST_CHECK_EQUAL(actual.second, 300);
70  // handler should return false
71  BOOST_CHECK_EQUAL(r, false);
72  // .. and the book_depth should be incremented
73  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
74 
75  // ... update at the bid increases the qty ...
76  r = tested.handle_add_order(BUY, price4_t(100000), 400);
77  actual = tested.best_bid();
78  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
79  BOOST_CHECK_EQUAL(actual.second, 500);
80  // handler should return true... it is an inside change
81  BOOST_CHECK_EQUAL(r, true);
82  // .. and the book_depth should not be incremented
83  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
84 
85  // ... a better price changes both price and qty ...
86  r = tested.handle_add_order(BUY, price4_t(100100), 200);
87  actual = tested.best_bid();
88  BOOST_CHECK_EQUAL(actual.first, price4_t(100100));
89  BOOST_CHECK_EQUAL(actual.second, 200);
90  // handler should return true... it is an inside change
91  BOOST_CHECK_EQUAL(r, true);
92  // .. and the book_depth should be incremented
93  BOOST_CHECK_EQUAL(tested.get_book_depth(), 3);
94 
95  // ... decrease below the bid has no effect ...
96  r = tested.handle_order_reduced(BUY, price4_t(100000), 400);
97  actual = tested.best_bid();
98  BOOST_CHECK_EQUAL(actual.first, price4_t(100100));
99  BOOST_CHECK_EQUAL(actual.second, 200);
100  // handler should return false
101  BOOST_CHECK_EQUAL(r, false);
102  // .. and the book_depth should not be decremented
103  BOOST_CHECK_EQUAL(tested.get_book_depth(), 3);
104 
105  // ... even when it is over the existing quantity ...
106  r = tested.handle_order_reduced(BUY, price4_t(100000), 200);
107  actual = tested.best_bid();
108  BOOST_CHECK_EQUAL(actual.first, price4_t(100100));
109  BOOST_CHECK_EQUAL(actual.second, 200);
110  // handler should return false
111  BOOST_CHECK_EQUAL(r, false);
112  // .. and the book_depth should be decremented
113  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
114 
115  // ... deleting the best bid uncovers the best price ...
116  r = tested.handle_order_reduced(BUY, price4_t(100100), 200);
117  actual = tested.best_bid();
118  BOOST_CHECK_EQUAL(actual.first, price4_t(99900));
119  BOOST_CHECK_EQUAL(actual.second, 300);
120  // handler should return true... it is an inside change
121  BOOST_CHECK_EQUAL(r, true);
122  // .. and the book_depth should be decremented
123  BOOST_CHECK_EQUAL(tested.get_book_depth(), 1);
124 
125  // ... deleting the remaining price takes the book depth to 0
126  r = tested.handle_order_reduced(BUY, price4_t(99900), 300);
127  actual = tested.best_bid();
128  BOOST_CHECK_EQUAL(actual.first, price4_t(0));
129  BOOST_CHECK_EQUAL(actual.second, 0);
130  // handler should return true... it is an inside change
131  BOOST_CHECK_EQUAL(r, true);
132  // .. and the book_depth should be decremented
133  BOOST_CHECK_EQUAL(tested.get_book_depth(), 0);
134 }
135 
136 /**
137  * Test order book sell side order handling.
138  */
139 template <typename book_type>
140 void test_order_book_sell_order_handling(book_type& tested) {
141  using jb::itch5::price4_t;
142 
144 
145  // Add a new order ...
146  auto r = tested.handle_add_order(SELL, price4_t(100000), 100);
147  // ... the offer should not change ...
148  auto actual = tested.best_bid();
149  BOOST_CHECK_EQUAL(actual.first, price4_t(0));
150  BOOST_CHECK_EQUAL(actual.second, 0);
151  actual = tested.worst_bid();
152  BOOST_CHECK_EQUAL(actual.first, price4_t(0));
153  BOOST_CHECK_EQUAL(actual.second, 0);
154  // .. but the offer should ...
155  actual = tested.best_offer();
156  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
157  BOOST_CHECK_EQUAL(actual.second, 100);
158  actual = tested.worst_offer();
159  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
160  BOOST_CHECK_EQUAL(actual.second, 100);
161  // handler should return true... it is an inside change
162  BOOST_CHECK_EQUAL(r, true);
163  // .. and the book_depth should be incremented
164  BOOST_CHECK_EQUAL(tested.get_book_depth(), 1);
165 
166  // ... adding above the best offer has no effect ...
167  r = tested.handle_add_order(SELL, price4_t(100100), 300);
168  actual = tested.best_offer();
169  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
170  BOOST_CHECK_EQUAL(actual.second, 100);
171  // ... the worst offer should change though ...
172  actual = tested.worst_offer();
173  BOOST_CHECK_EQUAL(actual.first, price4_t(100100));
174  BOOST_CHECK_EQUAL(actual.second, 300);
175  // handler should return false
176  BOOST_CHECK_EQUAL(r, false);
177  // .. and the book_depth should be incremented
178  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
179 
180  // ... update at the offer increases the qty ...
181  r = tested.handle_add_order(SELL, price4_t(100000), 400);
182  actual = tested.best_offer();
183  BOOST_CHECK_EQUAL(actual.first, price4_t(100000));
184  BOOST_CHECK_EQUAL(actual.second, 500);
185  // handler should return true... it is an inside change
186  BOOST_CHECK_EQUAL(r, true);
187  // .. and the book_depth should not change
188  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
189 
190  // ... a better price changes both price and qty ...
191  r = tested.handle_add_order(SELL, price4_t(99900), 200);
192  actual = tested.best_offer();
193  BOOST_CHECK_EQUAL(actual.first, price4_t(99900));
194  BOOST_CHECK_EQUAL(actual.second, 200);
195  // handler should return true... it is an inside change
196  BOOST_CHECK_EQUAL(r, true);
197  // .. and the book_depth should be incremented
198  BOOST_CHECK_EQUAL(tested.get_book_depth(), 3);
199 
200  // ... decrease above the offer has no effect ...
201  r = tested.handle_order_reduced(SELL, price4_t(100000), 400);
202  actual = tested.best_offer();
203  BOOST_CHECK_EQUAL(actual.first, price4_t(99900));
204  BOOST_CHECK_EQUAL(actual.second, 200);
205  // handler should return false
206  BOOST_CHECK_EQUAL(r, false);
207  // .. and the book_depth should not change
208  BOOST_CHECK_EQUAL(tested.get_book_depth(), 3);
209 
210  // ... even when it is over the existing quantity ...
211  r = tested.handle_order_reduced(SELL, price4_t(100000), 200);
212  actual = tested.best_offer();
213  BOOST_CHECK_EQUAL(actual.first, price4_t(99900));
214  BOOST_CHECK_EQUAL(actual.second, 200);
215  // handler should return false
216  BOOST_CHECK_EQUAL(r, false);
217  // .. and the book_depth should be incremented
218  BOOST_CHECK_EQUAL(tested.get_book_depth(), 2);
219 
220  // ... deleting the best offer uncovers the best price ...
221  r = tested.handle_order_reduced(SELL, price4_t(99900), 200);
222  actual = tested.best_offer();
223  BOOST_CHECK_EQUAL(actual.first, price4_t(100100));
224  BOOST_CHECK_EQUAL(actual.second, 300);
225  // handler should return true... it is an inside change
226  BOOST_CHECK_EQUAL(r, true);
227  // .. and the book_depth should be incremented
228  BOOST_CHECK_EQUAL(tested.get_book_depth(), 1);
229 
230  // ... deleting the remaining price takes the book depth to 0
231  r = tested.handle_order_reduced(SELL, price4_t(100100), 300);
232  actual = tested.best_offer();
233  BOOST_CHECK_EQUAL(actual.first, price4_t(200000UL * 10000));
234  BOOST_CHECK_EQUAL(actual.second, 0);
235  // handler should return true
236  BOOST_CHECK_EQUAL(r, true);
237  // .. and the book_depth should be decremented
238  BOOST_CHECK_EQUAL(tested.get_book_depth(), 0);
239 }
240 
241 /**
242  * Test order book error conditions.
243  */
244 template <typename book_type>
245 void test_order_book_errors(book_type& tested) {
246  using jb::itch5::price4_t;
247 
250 
251  // Add two orders to the book ...
252  (void)tested.handle_add_order(BUY, price4_t(100000), 100);
253  (void)tested.handle_add_order(BUY, price4_t(110000), 200);
254 
255  // ... check the best bid ...
256  auto actual = tested.best_bid();
257  BOOST_CHECK_EQUAL(actual.first, price4_t(110000));
258  BOOST_CHECK_EQUAL(actual.second, 200);
259 
260  // ... remove the first order, once should work, the second time
261  // should fail ...
262  tested.handle_order_reduced(BUY, price4_t(100000), 100);
263  BOOST_CHECK_THROW(
264  tested.handle_order_reduced(BUY, price4_t(100000), 100), std::exception);
265 
266  // ... check the best bid ...
267  actual = tested.best_bid();
268  BOOST_CHECK_EQUAL(actual.first, price4_t(110000));
269  BOOST_CHECK_EQUAL(actual.second, 200);
270 
271  // Add two orders to the book ...
272  (void)tested.handle_add_order(SELL, price4_t(120000), 100);
273  (void)tested.handle_add_order(SELL, price4_t(110000), 200);
274 
275  // ... check the best offer ...
276  actual = tested.best_offer();
277  BOOST_CHECK_EQUAL(actual.first, price4_t(110000));
278  BOOST_CHECK_EQUAL(actual.second, 200);
279 
280  // ... remove the first order, once should work, the second time
281  // should fail ...
282  tested.handle_order_reduced(SELL, price4_t(120000), 100);
283  BOOST_CHECK_THROW(
284  tested.handle_order_reduced(SELL, price4_t(120000), 100), std::exception);
285 
286  // ... check the best offer ...
287  actual = tested.best_offer();
288  BOOST_CHECK_EQUAL(actual.first, price4_t(110000));
289  BOOST_CHECK_EQUAL(actual.second, 200);
290 }
291 
292 } // namespace testing
293 } // namespace itch5
294 } // namespace testing
295 
296 /**
297  * @test Verify that jb::itch5::order_book<jb::itch5::map_price> works as
298  * expected.
299  */
300 BOOST_AUTO_TEST_CASE(order_book_trivial) {
301  using namespace jb::itch5;
302 
303  using map_book_type = order_book<map_based_order_book>;
305  map_book_type map_tested(map_cfg);
307 
308  using array_book_type = order_book<array_based_order_book>;
310  array_book_type array_tested(array_cfg);
311  testing::test_order_book_trivial(array_tested);
312 }
313 
314 /**
315  * @test Verify that buy side of order_book<book_type>
316  * works as expected.
317  */
318 BOOST_AUTO_TEST_CASE(order_book_buy) {
319  using namespace jb::itch5;
320 
321  using map_book_type = order_book<map_based_order_book>;
323  map_book_type map_tested(map_cfg);
325 
326  using array_book_type = order_book<array_based_order_book>;
327  // uses default max_size
329  array_book_type array_tested(array_cfg);
331 
332  // defines max_size to 3000
333  array_book_type sh_array_tested(
336 }
337 
338 /**
339  * @test Verity that the sell side of
340  * jb::itch5::order_book<jb::itch5::map_price> works as expected.
341  */
342 BOOST_AUTO_TEST_CASE(order_book_sell) {
343  using namespace jb::itch5;
344  using map_book_type = order_book<map_based_order_book>;
345 
347  map_book_type map_tested(map_cfg);
349 
350  using array_book_type = order_book<array_based_order_book>;
351  // uses default max_size
353  array_book_type array_tested(array_cfg);
355 
356  // defines max_size to 3000
357  array_book_type sh_array_tested(
360 }
361 
362 /**
363  * @test Verify that order_book handles errors as expected.
364  */
365 BOOST_AUTO_TEST_CASE(order_book_errors) {
366  using namespace jb::itch5;
367  using map_book_type = order_book<map_based_order_book>;
368 
370  map_book_type map_tested(map_cfg);
372 
373  using array_book_type = order_book<array_based_order_book>;
375  array_book_type array_tested(array_cfg);
376  testing::test_order_book_errors(array_tested);
377 }
Contains classes and functions to parse NASDAQ ITCH-5.0 messages, more information about ITCH-5...
void test_order_book_errors(book_type &tested)
Test order book error conditions.
void test_order_book_buy_order_handling(book_type &tested)
Test order book buy side order handling.
buy_sell_indicator_t const SELL(u 'S')
void test_order_book_trivial(book_type &tested)
Test order book trivial members.
Configure an array_based_order_book config object.
buy_sell_indicator_t const BUY(u 'B')
Configure an map_based_order_book config object.
price_field< std::uint32_t, 10000 > price4_t
Convenience definition for Price(4) fields.
BOOST_AUTO_TEST_CASE(order_book_trivial)
void test_order_book_sell_order_handling(book_type &tested)
Test order book sell side order handling.
Maintain the ITCH-5.0 order book for a single security.
Definition: order_book.hpp:57
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7