libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
mit_exchanges.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/FIX/v5.0sp2/fix.hpp"
27 #include "../exchanges/MIT/BIT/bit.hpp"
28 #include "../exchanges/MIT/BIT/bit_sim.hpp"
29 #include "../exchanges/MIT/JSE/jse.hpp"
30 #include "../exchanges/MIT/JSE/jse_sim.hpp"
31 #include "../exchanges/MIT/LSE/lse.hpp"
32 #include "../exchanges/MIT/LSE/lse_sim.hpp"
33 #include "../exchanges/MIT/OSLO/oslo.hpp"
34 #include "../exchanges/MIT/OSLO/oslo_sim.hpp"
35 #include "../exchanges/MIT/TRQ/trq.hpp"
36 #include "../exchanges/MIT/TRQ/trq_sim.hpp"
37 #include "../exchanges/conversions/fix_to_mit_conversions.hpp"
38 #include "../exchanges/conversions/mit_to_fix_conversions.hpp"
39 
40 #include "core/latency_timestamps.hpp"
41 
42 using namespace libjmmcg;
43 using namespace libisimud;
44 
45 using api_thread_traits=ppd::thread_params<ppd::platform_api>;
46 
47 const boost::asio::ip::address localhost(boost::asio::ip::address_v4::loopback());
48 const unsigned short client_port=12377u;
49 const boost::asio::ip::address primary_gw(boost::asio::ip::address_v4::loopback());
50 const unsigned short unused_primary_port=client_port+1;
51 const boost::asio::ip::address secondary_gw(boost::asio::ip::address_v4::loopback());
53 
54 typedef boost::mpl::list<
55  std::pair<exchanges::MIT::BIT::link_t<exchanges::FIX::v5_0sp2::MsgTypes>, exchanges::MIT::BIT::simulator_t>,
56  std::pair<exchanges::MIT::JSE::link_t<exchanges::FIX::v5_0sp2::MsgTypes>, exchanges::MIT::JSE::simulator_t>,
57  std::pair<exchanges::MIT::LSE::link_t<exchanges::FIX::v5_0sp2::MsgTypes>, exchanges::MIT::LSE::simulator_t>,
58  std::pair<exchanges::MIT::OSLO::link_t<exchanges::FIX::v5_0sp2::MsgTypes>, exchanges::MIT::OSLO::simulator_t>,
59  std::pair<exchanges::MIT::TRQ::link_t<exchanges::FIX::v5_0sp2::MsgTypes>, exchanges::MIT::TRQ::simulator_t>
60 > exchg_t_types;
61 
62 template<class exchg_t>
63 struct only_sim {
64  using link_t=typename exchg_t::first_type;
65  using simulator_t=typename exchg_t::second_type;
66  using conn_pol_t=typename link_t::exchg_link_t::conn_pol_t;
67  using connection_t=exchanges::common::connection<
68  typename simulator_t::msg_processor_t::msg_details_t,
69  conn_pol_t
70  >;
71  using ref_data_t=typename link_t::client_link_t::proc_rules_t::ref_data;
72 
73  static ref_data_t make_ref_data() noexcept(false) {
74  const std::string ref_data_file(
75  "133215;FTSE100;SET0;PT_T;TP_1;GB00BH4HKS39;;20060731;0;1;10000;42467000;1;;1;DE;VOD;VODAFONE GRP.;BH4HKS3;15225662730;GBX;1;Y;0023;VOVOD;VODAFONE GROUP PLC;0;;;15000;ORD USD0.20 20/21;;1;1;5;GB;;;FE00;1;;;;1;A;;;;;;\n"
76  "2926;FTSE100;SET1;PT_T;TP_12;GB0000595859;;20000419;0;1;3000;32438040;1;;1;DE;ARM;ARM HLDGS.;0059585;3861344694;GBX;1;Y;0023;ARARM;ARM HOLDINGS PLC;0;;;7500;ORD 0.05P;;1;1;5;GB;;;FS10;4;;;;2;B;;;;;;"
77  );
78  std::stringstream ss;
79  ss<<ref_data_file;
80  return ref_data_t(ss);
81  }
82 
83  const typename conn_pol_t::gateways_t gateways{
86  };
87  const ref_data_t ref_data{make_ref_data()};
88  const conn_pol_t conn_pol{
89  gateways,
94  },
97  }
98  };
99  no_latency_timestamps ts{0};
100  simulator_t svr{
101  primary_gw,
103  simulator_t::socket_t::socket_priority::low,
104  api_thread_traits::processor_mask_type(exchanges::common::thread_traits::exchange_simulator_thread.core),
105  exchanges::common::thread_traits::exchange_simulator_thread.priority,
106  typename simulator_t::proc_rules_t(),
107  ts,
108  "sim" LIBJMMCG_ENQUOTE(__LINE__)
109  };
110 };
111 
112 template<class exchg_t>
113 struct simulator_and_link : public only_sim<exchg_t> {
114  using base_t=only_sim<exchg_t>;
115  using link_t=typename base_t::link_t;
116 
117  no_latency_timestamps ts{0};
118  link_t link{
119  typename link_t::client_link_t::ctor_args{
120  localhost,
121  client_port,
122  typename link_t::client_link_t::proc_rules_t(this->ref_data)
123  },
124  this->conn_pol,
125  link_t::socket_t::socket_priority::high,
126  link_t::socket_t::socket_priority::low,
127  typename link_t::exchg_to_client_proc_rules_t(this->ref_data),
128  ts,
129  "link" LIBJMMCG_ENQUOTE(__LINE__)
130  };
131 };
132 
133 template<class exchg_t>
134 struct simulator_and_link_client_too : public simulator_and_link<exchg_t> {
135  exchanges::FIX::v5_0sp2::connection_t client{
139  )
140  ),
143  };
144 };
145 
146 BOOST_AUTO_TEST_SUITE(exchange_gateways)
147 
148 BOOST_AUTO_TEST_SUITE(client_initiated)
149 
150 /**
151  \test Verify Logon - no clients.
152  ==========================
153  Verify that the link can log on to the exchange, with no clients.
154 */
155 BOOST_AUTO_TEST_CASE_TEMPLATE(logon_no_clients, exchg_t, exchg_t_types) {
156  using fixture_t=simulator_and_link<exchg_t>;
157 
158  const fixture_t f;
159 
160  BOOST_CHECK(f.link.is_logged_on());
161 }
162 
163 /**
164  \test Verify that gateway can re-Logon.
165  =================================
166  Verify that the gateway can re-log on to the exchange, without any clients.
167 */
168 BOOST_AUTO_TEST_CASE_TEMPLATE(re_logon_no_clients, exchg_t, exchg_t_types) {
169  using fixture_t=only_sim<exchg_t>;
170 
171  const fixture_t f;
172  no_latency_timestamps ts{0};
173 
174  {
175  const typename fixture_t::link_t link{
176  typename fixture_t::link_t::client_link_t::ctor_args{
177  localhost,
178  client_port,
179  typename fixture_t::link_t::client_link_t::proc_rules_t(f.ref_data)
180  },
181  f.conn_pol,
182  fixture_t::link_t::socket_t::socket_priority::high,
183  fixture_t::link_t::socket_t::socket_priority::low,
184  typename fixture_t::link_t::exchg_to_client_proc_rules_t(f.ref_data),
185  ts,
186  "link" LIBJMMCG_ENQUOTE(__LINE__)
187  };
188  BOOST_CHECK(link.is_logged_on());
189  }
190  {
191  const typename fixture_t::link_t link{
192  typename fixture_t::link_t::client_link_t::ctor_args{
193  localhost,
194  client_port,
195  typename fixture_t::link_t::client_link_t::proc_rules_t(f.ref_data)
196  },
197  f.conn_pol,
198  fixture_t::link_t::socket_t::socket_priority::high,
199  fixture_t::link_t::socket_t::socket_priority::low,
200  typename fixture_t::link_t::exchg_to_client_proc_rules_t(f.ref_data),
201  ts,
202  "link" LIBJMMCG_ENQUOTE(__LINE__)
203  };
204  BOOST_CHECK(link.is_logged_on());
205  }
206 }
207 
208 /**
209  \test Verify Logon - with a client.
210  =============================
211  Verify that the link can log on to the exchange and remains logged on, with a client connected.
212 */
213 BOOST_AUTO_TEST_CASE_TEMPLATE(logon_with_a_client, exchg_t, exchg_t_types) {
214  using fixture_t=simulator_and_link<exchg_t>;
215 
216  const fixture_t f;
217 
218  BOOST_CHECK(f.link.is_logged_on());
219  {
220  const exchanges::FIX::v5_0sp2::connection_t client(
221  exchanges::FIX::v5_0sp2::connection_t::conn_pol_t(
222  typename exchanges::FIX::v5_0sp2::connection_t::conn_pol_t::gateways_t(
223  std::make_pair(localhost, client_port)
224  )
225  ),
226  exchanges::FIX::v5_0sp2::connection_t::socket_t::socket_priority::low,
227  exchanges::common::thread_traits::client_to_exchange_thread.core
228  );
229  BOOST_CHECK(f.link.is_logged_on());
230  }
231  BOOST_CHECK(f.link.is_logged_on());
232 }
233 
234 /**
235  \test Verify that clients can re-connect to logged-on gateway.
236  ========================================================
237  Verify that the gateway can re-log on to the exchange, with a connected client.
238 */
239 BOOST_AUTO_TEST_CASE_TEMPLATE(re_connect_client_with_logon, exchg_t, exchg_t_types) {
240  using fixture_t=simulator_and_link<exchg_t>;
241 
242  const fixture_t f;
243 
244  BOOST_CHECK(f.link.is_logged_on());
245  {
246  const exchanges::FIX::v5_0sp2::connection_t client(
247  exchanges::FIX::v5_0sp2::connection_t::conn_pol_t(
248  typename exchanges::FIX::v5_0sp2::connection_t::conn_pol_t::gateways_t(
249  std::make_pair(localhost, client_port)
250  )
251  ),
252  exchanges::FIX::v5_0sp2::connection_t::socket_t::socket_priority::low,
253  exchanges::common::thread_traits::client_to_exchange_thread.core
254  );
255  BOOST_CHECK(f.link.is_logged_on());
256  }
257  BOOST_CHECK(f.link.is_logged_on());
258  {
259  const exchanges::FIX::v5_0sp2::connection_t client(
260  exchanges::FIX::v5_0sp2::connection_t::conn_pol_t(
261  typename exchanges::FIX::v5_0sp2::connection_t::conn_pol_t::gateways_t(
262  std::make_pair(localhost, client_port)
263  )
264  ),
265  exchanges::FIX::v5_0sp2::connection_t::socket_t::socket_priority::low,
266  exchanges::common::thread_traits::client_to_exchange_thread.core
267  );
268  BOOST_CHECK(f.link.is_logged_on());
269  }
270  BOOST_CHECK(f.link.is_logged_on());
271 }
272 
273 /**
274  \test Verify Heartbeats - no clients.
275  ===============================
276  Verify that Heartbeats occur, without any clients.
277 */
278 BOOST_AUTO_TEST_CASE_TEMPLATE(heartbeats_no_clients, exchg_t, exchg_t_types) {
279  using fixture_t=simulator_and_link<exchg_t>;
280 
281  const fixture_t f;
282 
283  std::this_thread::sleep_for(std::chrono::seconds(fixture_t::simulator_t::svr_mgr_t::heartbeats_t::heartbeat_interval*(fixture_t::simulator_t::svr_mgr_t::heartbeats_t::max_missed_heartbeats+1)));
284  BOOST_CHECK(f.link.is_logged_on());
285 }
286 
287 /**
288  \test Verify Heartbeats - with client.
289  ================================
290  Verify that Heartbeats occur, with a connected client.
291 */
292 BOOST_AUTO_TEST_CASE_TEMPLATE(heartbeats_with_client, exchg_t, exchg_t_types) {
293  using fixture_t=simulator_and_link<exchg_t>;
294 
295  const fixture_t f;
296 
297  std::this_thread::sleep_for(std::chrono::seconds(fixture_t::simulator_t::svr_mgr_t::heartbeats_t::heartbeat_interval*(fixture_t::simulator_t::svr_mgr_t::heartbeats_t::max_missed_heartbeats+1)));
298  BOOST_CHECK(f.link.is_logged_on());
299 }
300 
301 /**
302  \test Response to an invalid NewOrder.
303  ================================
304  Verify that the response to an invalid NewOrder is a BusinessReject.
305 */
306 BOOST_AUTO_TEST_CASE_TEMPLATE(reject, exchg_t, exchg_t_types) {
307  using fixture_t=simulator_and_link_client_too<exchg_t>;
308 
309  fixture_t f;
310 
311  BOOST_CHECK(f.link.is_logged_on());
312 
313  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer fix_buffer={
314  "8=FIX.5.0\0019=154\00135=D\00134=10\00143=N\00149=VENDOR\00150=CUSTOME\00156=BROKER\00160=19980930-09:25:58\0011=XQCCFUND\00111=10\00121=1\00155=EK\00148=GB0000595859\00122=4\00154=1\00138=10000\00140=2\00144=76.750000\00159=0\00110=092\001"
315  };
316  exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &>(*fix_buffer.begin());
317  BOOST_CHECK_EQUAL(fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle::static_type);
318  BOOST_REQUIRE_NO_THROW(f.client.send(fix_msg));
319  BOOST_CHECK(f.link.is_logged_on());
320  exchanges::FIX::v5_0sp2::MsgTypes::BusinessMessageReject receive_fix_msg;
321  BOOST_REQUIRE_NO_THROW(f.client.receive(receive_fix_msg));
322  BOOST_CHECK(receive_fix_msg.is_valid());
323  auto const ref_seq_num=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::RefSeqNum>();
324  BOOST_CHECK_EQUAL(std::string(ref_seq_num.first, ref_seq_num.second), "2");
325  BOOST_CHECK(f.link.is_logged_on());
326 }
327 
328 /**
329  \test Response to an invalid OrderCancelRequest.
330  ==========================================
331  Verify that the response to an invalid OrderCancelRequest is a CancelRejected.
332 */
333 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_reject, exchg_t, exchg_t_types) {
334  using fixture_t=simulator_and_link_client_too<exchg_t>;
335 
336  fixture_t f;
337 
338  BOOST_CHECK(f.link.is_logged_on());
339 
340  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer fix_buffer={
341  "8=FIX.5.0\0019=141\00135=F\00111=10\00141=10\00148=GB00BH4HKS39\00149=VENDOR\00156=BROKER\00134=10\00152=20000426-12:05:06\00155=EK\00154=1\00160=19980930-09:25:58\00138=99\00140=1\00144=43.000000\00159=0\00110=012\001"
342  };
343  exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest const &fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest const &>(*fix_buffer.begin());
344  BOOST_CHECK_EQUAL(fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest::static_type);
345  BOOST_REQUIRE_NO_THROW(f.client.send(fix_msg));
346  BOOST_CHECK(f.link.is_logged_on());
347  exchanges::FIX::v5_0sp2::MsgTypes::CancelRejected receive_fix_msg;
348  BOOST_REQUIRE_NO_THROW(f.client.receive(receive_fix_msg));
349  BOOST_CHECK(receive_fix_msg.is_valid());
350  auto const client_order_id=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
351  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
352  auto const seqNum=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
353  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "2");
354  BOOST_CHECK(f.link.is_logged_on());
355 }
356 
357 /**
358  \test Response to a valid OrderCancelRequest.
359  =======================================
360  Verify that the response to a valid OrderCancelRequest is a cancelled order ExecutionReport.
361 */
362 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_accept, exchg_t, exchg_t_types) {
363  using fixture_t=simulator_and_link_client_too<exchg_t>;
364 
365  fixture_t f;
366 
367  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer order_fix_buffer={
368  "8=FIX.5.0\0019=167\00135=D\00134=10\00143=N\00149=VENDOR\00150=CUSTOME\00156=BROKER\00160=19980930-09:25:58\0011=XQCCFUND\00111=10\00121=1\00155=EK\00148=GB00BH4HKS39\00122=4\00154=1\00138=99\00140=2\00144=43.000000\00159=0\0011133=G\001100=MTAA\00110=117\001"
369  };
370  exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &order_fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &>(*order_fix_buffer.begin());
371  BOOST_CHECK_EQUAL(order_fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle::static_type);
372  BOOST_CHECK(order_fix_msg.is_valid());
373  BOOST_REQUIRE_NO_THROW(f.client.send(order_fix_msg));
374  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer cancel_fix_buffer={
375  "8=FIX.5.0\0019=157\00135=F\00111=10\00141=10\00148=GB00BH4HKS39\00149=VENDOR\00156=BROKER\00134=10\00152=20000426-12:05:06\00155=EK\00154=1\00160=19980930-09:25:58\00138=99\00140=2\00144=43.000000\00159=0\0011133=G\001100=MTAA\00110=083\001"
376  };
377  exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest const &cancel_fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest const &>(*cancel_fix_buffer.begin());
378  BOOST_CHECK_EQUAL(cancel_fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelRequest::static_type);
379  BOOST_CHECK(cancel_fix_msg.is_valid());
380  BOOST_REQUIRE_NO_THROW(f.client.send(cancel_fix_msg));
381  {
382  exchanges::FIX::v5_0sp2::MsgTypes::ExecutionReport order_new_fix_msg;
383  BOOST_REQUIRE_NO_THROW(f.client.receive(order_new_fix_msg));
384  BOOST_CHECK(order_new_fix_msg.is_valid());
385  auto const client_order_id=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
386  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
387  auto const seqNum=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
388  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "2");
389  auto const securityIDSource=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityIDSource>();
390  BOOST_CHECK_EQUAL(std::string(securityIDSource.first, securityIDSource.second), "4");
391  auto const securityID=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityID>();
392  BOOST_CHECK_EQUAL(std::string(securityID.first, securityID.second), "GB00BH4HKS39");
393  auto const execType=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::ExecType>();
394  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::ExecType>(*execType.first), exchanges::FIX::common::ExecType::New);
395  auto const price=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::Price>();
396  BOOST_CHECK_EQUAL(std::string(price.first, price.second), "0.000000");
397  auto const side=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::Side>();
398  BOOST_CHECK_EQUAL(std::string(side.first, side.second), "1");
399  auto const ordStatus=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::OrdStatus>();
400  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::OrdStatus>(*ordStatus.first), exchanges::FIX::common::OrdStatus::New);
401  auto const orderQty=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::OrderQty>();
402  BOOST_CHECK_EQUAL(std::string(orderQty.first, orderQty.second), "0");
403  auto const leavesQty=order_new_fix_msg.find<exchanges::FIX::common::FieldsFast::LeavesQty>();
404  BOOST_CHECK_EQUAL(std::string(leavesQty.first, leavesQty.second), "99");
405  BOOST_CHECK(f.link.is_logged_on());
406  }
407  exchanges::FIX::v5_0sp2::MsgTypes::ExecutionReport cancelled_fix_msg;
408  BOOST_REQUIRE_NO_THROW(f.client.receive(cancelled_fix_msg));
409  BOOST_CHECK(cancelled_fix_msg.is_valid());
410  auto const client_order_id=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
411  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
412  auto const seqNum=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
413  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "3");
414  auto const securityIDSource=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityIDSource>();
415  BOOST_CHECK_EQUAL(std::string(securityIDSource.first, securityIDSource.second), "4");
416  auto const securityID=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityID>();
417  BOOST_CHECK_EQUAL(std::string(securityID.first, securityID.second), "GB00BH4HKS39");
418  auto const execType=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::ExecType>();
419  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::ExecType>(*execType.first), exchanges::FIX::common::ExecType::Canceled);
420  auto const price=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::Price>();
421  BOOST_CHECK_EQUAL(std::string(price.first, price.second), "43.000000");
422  auto const side=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::Side>();
423  BOOST_CHECK_EQUAL(std::string(side.first, side.second), "1");
424  auto const ordStatus=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::OrdStatus>();
425  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::OrdStatus>(*ordStatus.first), exchanges::FIX::common::OrdStatus::Canceled);
426  auto const orderQty=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::OrderQty>();
427  BOOST_CHECK_EQUAL(std::string(orderQty.first, orderQty.second), "0");
428  auto const leavesQty=cancelled_fix_msg.find<exchanges::FIX::common::FieldsFast::LeavesQty>();
429  BOOST_CHECK_EQUAL(std::string(leavesQty.first, leavesQty.second), "99");
430  BOOST_CHECK(f.link.is_logged_on());
431 }
432 
433 /**
434  \test Response to an invalid OrderCancelReplaceRequest.
435  =================================================
436  Verify that the response to an invalid OrderCancelReplaceRequest is a cancelled order CancelRejected.
437 */
438 BOOST_AUTO_TEST_CASE_TEMPLATE(modify_reject, exchg_t, exchg_t_types) {
439  using fixture_t=simulator_and_link_client_too<exchg_t>;
440 
441  fixture_t f;
442 
443  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer fix_buffer={
444  "8=FIX.5.0\0019=141\00135=G\00111=10\00141=10\00148=GB00BH4HKS39\00149=VENDOR\00156=BROKER\00134=10\00152=20000426-12:05:06\00155=EK\00154=1\00160=19980930-09:25:58\00138=99\00140=1\00144=43.000000\00159=0\00110=102\001"
445  };
446  exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelReplace const &fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelReplace const &>(*fix_buffer.begin());
447  BOOST_CHECK_EQUAL(fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::OrderCancelReplace::static_type);
448  BOOST_CHECK(fix_msg.is_valid());
449  BOOST_REQUIRE_NO_THROW(f.client.send(fix_msg));
450  exchanges::FIX::v5_0sp2::MsgTypes::CancelRejected receive_fix_msg;
451  BOOST_REQUIRE_NO_THROW(f.client.receive(receive_fix_msg));
452  BOOST_CHECK(receive_fix_msg.is_valid());
453  auto const client_order_id=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
454  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
455  auto const seqNum=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
456  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "2");
457  BOOST_CHECK(f.link.is_logged_on());
458 }
459 
460 BOOST_AUTO_TEST_SUITE_END()
461 
462 BOOST_AUTO_TEST_SUITE(new_order)
463 
464 BOOST_AUTO_TEST_SUITE(buy)
465 
466 BOOST_AUTO_TEST_SUITE(day)
467 
468 /**
469  \test "Order handling" Test: Response to a BUY, DAY, MARKET NewOrder is a filled FIX message.
470  =======================================================================================
471  Verify that the response to a buy, day, market NewOrder is a filled FIX message.
472 */
473 BOOST_AUTO_TEST_CASE_TEMPLATE(market_fill, exchg_t, exchg_t_types) {
474  using fixture_t=simulator_and_link_client_too<exchg_t>;
475 
476  fixture_t f;
477 
478  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer fix_buffer={
479  "8=FIX.5.0\0019=151\00135=D\00134=10\00143=N\00149=VENDOR\00150=CUSTOME\00156=BROKER\00160=19980930-09:25:58\0011=XQCCFUND\00111=10\00121=1\00155=EK\00148=GB00BH4HKS39\00122=4\00154=1\00138=99\00140=1\00144=41.000000\00159=0\00110=133\001"
480  };
481  exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &>(*fix_buffer.begin());
482  BOOST_CHECK_EQUAL(fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle::static_type);
483  BOOST_CHECK(fix_msg.is_valid());
484  BOOST_REQUIRE_NO_THROW(f.client.send(fix_msg));
485  exchanges::FIX::v5_0sp2::MsgTypes::ExecutionReport receive_fix_msg;
486  BOOST_REQUIRE_NO_THROW(f.client.receive(receive_fix_msg));
487  BOOST_CHECK(receive_fix_msg.is_valid());
488  auto const client_order_id=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
489  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
490  auto const seqNum=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
491  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "2");
492  auto const securityIDSource=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityIDSource>();
493  BOOST_CHECK_EQUAL(std::string(securityIDSource.first, securityIDSource.second), "4");
494  auto const securityID=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityID>();
495  BOOST_CHECK_EQUAL(std::string(securityID.first, securityID.second), "GB00BH4HKS39");
496  auto const execType=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ExecType>();
497  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::ExecType>(*execType.first), exchanges::FIX::common::ExecType::New);
498  auto const price=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::Price>();
499  BOOST_CHECK_EQUAL(std::string(price.first, price.second), "41.000000");
500  auto const side=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::Side>();
501  BOOST_CHECK_EQUAL(std::string(side.first, side.second), "1");
502  auto const ordStatus=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::OrdStatus>();
503  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::OrdStatus>(*ordStatus.first), exchanges::FIX::common::OrdStatus::Filled);
504  auto const orderQty=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::OrderQty>();
505  BOOST_CHECK_EQUAL(std::string(orderQty.first, orderQty.second), "99");
506  auto const leavesQty=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::LeavesQty>();
507  BOOST_CHECK_EQUAL(std::string(leavesQty.first, leavesQty.second), "0");
508 }
509 
510 /**
511  \test "Order handling" Test: Response to a BUY, DAY, MARKET NewOrder is a filled FIX message.
512  =======================================================================================
513  Verify that the response to a buy, day, market NewOrder is a filled FIX message.
514 */
515 BOOST_AUTO_TEST_CASE_TEMPLATE(market_partial_fill, exchg_t, exchg_t_types) {
516  using fixture_t=simulator_and_link_client_too<exchg_t>;
517 
518  fixture_t f;
519 
520  ALIGN_TO_L1_CACHE const exchanges::FIX::common::underlying_fix_data_buffer fix_buffer={
521  "8=FIX.5.0\0019=152\00135=D\00134=10\00143=N\00149=VENDOR\00150=CUSTOME\00156=BROKER\00160=19980930-09:25:58\0011=XQCCFUND\00111=10\00121=1\00155=EK\00148=GB00BH4HKS39\00122=4\00154=1\00138=101\00140=1\00144=41.000000\00159=0\00110=166\001"
522  };
523  exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &fix_msg=reinterpret_cast<exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle const &>(*fix_buffer.begin());
524  BOOST_CHECK_EQUAL(fix_msg.type(), exchanges::FIX::v5_0sp2::MsgTypes::NewOrderSingle::static_type);
525  BOOST_CHECK(fix_msg.is_valid());
526  BOOST_REQUIRE_NO_THROW(f.client.send(fix_msg));
527  exchanges::FIX::v5_0sp2::MsgTypes::ExecutionReport receive_fix_msg;
528  BOOST_REQUIRE_NO_THROW(f.client.receive(receive_fix_msg));
529  BOOST_CHECK(receive_fix_msg.is_valid());
530  auto const client_order_id=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ClOrdID>();
531  BOOST_CHECK_EQUAL(std::string(client_order_id.first, client_order_id.second).c_str(), "10");
532  auto const seqNum=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::MsgSeqNum>();
533  BOOST_CHECK_EQUAL(std::string(seqNum.first, seqNum.second), "2");
534  auto const securityIDSource=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityIDSource>();
535  BOOST_CHECK_EQUAL(std::string(securityIDSource.first, securityIDSource.second), "4");
536  auto const securityID=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::SecurityID>();
537  BOOST_CHECK_EQUAL(std::string(securityID.first, securityID.second), "GB00BH4HKS39");
538  auto const execType=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::ExecType>();
539  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::ExecType>(*execType.first), exchanges::FIX::common::ExecType::New);
540  auto const price=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::Price>();
541  BOOST_CHECK_EQUAL(std::string(price.first, price.second), "42.000000");
542  auto const side=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::Side>();
543  BOOST_CHECK_EQUAL(std::string(side.first, side.second), "1");
544  auto const ordStatus=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::OrdStatus>();
545  BOOST_CHECK_EQUAL(static_cast<exchanges::FIX::common::OrdStatus>(*ordStatus.first), exchanges::FIX::common::OrdStatus::Partially_filled);
546  auto const orderQty=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::OrderQty>();
547  BOOST_CHECK_EQUAL(std::string(orderQty.first, orderQty.second), "100");
548  auto const leavesQty=receive_fix_msg.find<exchanges::FIX::common::FieldsFast::LeavesQty>();
549  BOOST_CHECK_EQUAL(std::string(leavesQty.first, leavesQty.second), "1");
550 }
551 
552 BOOST_AUTO_TEST_SUITE_END()
553 
554 BOOST_AUTO_TEST_SUITE_END()
555 
556 BOOST_AUTO_TEST_SUITE_END()
557 
558 BOOST_AUTO_TEST_SUITE_END()