libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
mit_simulators.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/MIT/BIT/bit.hpp"
27 #include "../exchanges/MIT/BIT/bit_sim.hpp"
28 #include "../exchanges/MIT/JSE/jse.hpp"
29 #include "../exchanges/MIT/JSE/jse_sim.hpp"
30 #include "../exchanges/MIT/LSE/lse.hpp"
31 #include "../exchanges/MIT/LSE/lse_sim.hpp"
32 #include "../exchanges/MIT/OSLO/oslo.hpp"
33 #include "../exchanges/MIT/OSLO/oslo_sim.hpp"
34 #include "../exchanges/MIT/TRQ/trq.hpp"
35 #include "../exchanges/MIT/TRQ/trq_sim.hpp"
36 
37 using namespace libjmmcg;
38 using namespace libisimud;
39 
40 using api_thread_traits=ppd::thread_params<ppd::platform_api>;
41 
42 const boost::asio::ip::address localhost(boost::asio::ip::address_v4::loopback());
43 const boost::asio::ip::address primary_gw(boost::asio::ip::address_v4::loopback());
44 const unsigned short unused_primary_port=12347u;
45 const boost::asio::ip::address secondary_gw(boost::asio::ip::address_v4::loopback());
47 const exchanges::MIT::common::ClientOrderID_t clientOrderId1{"00000000000000test1"};
48 
49 typedef boost::mpl::list<
50  std::pair<exchanges::MIT::BIT::connection_t, exchanges::MIT::BIT::simulator_t>,
51  std::pair<exchanges::MIT::JSE::connection_t, exchanges::MIT::JSE::simulator_t>,
52  std::pair<exchanges::MIT::LSE::connection_t, exchanges::MIT::LSE::simulator_t>,
53  std::pair<exchanges::MIT::OSLO::connection_t, exchanges::MIT::OSLO::simulator_t>,
54  std::pair<exchanges::MIT::TRQ::connection_t, exchanges::MIT::TRQ::simulator_t>
55 > exchg_t_types;
56 
57 template<class exchg_t>
58 struct conn_args {
59  using connection_t=typename exchg_t::first_type;
60  using simulator_t=typename exchg_t::second_type;
61  using conn_pol_t=typename connection_t::conn_pol_t;
62 
63  typename conn_pol_t::gateways_t gateways{
66  };
67  const conn_pol_t conn_pol{
68  gateways,
73  },
76  }
77  };
78 };
79 
80 template<class exchg_t>
81 struct conn_args_n_sim : public conn_args<exchg_t> {
82  using base_t=conn_args<exchg_t>;
83  using simulator_t=typename base_t::simulator_t;
84 
85  typename simulator_t::proc_rules_t proc_rules;
86  no_latency_timestamps ts{0};
87  simulator_t svr{
88  primary_gw,
90  simulator_t::socket_t::socket_priority::high,
91  api_thread_traits::processor_mask_type(exchanges::common::thread_traits::exchange_simulator_thread.core),
92  exchanges::common::thread_traits::exchange_simulator_thread.priority,
93  proc_rules,
94  ts,
95  "sim" LIBJMMCG_ENQUOTE(__LINE__)
96  };
97 };
98 
99 template<class exchg_t>
100 struct conn_args_sim_n_link : public conn_args_n_sim<exchg_t> {
101  using base_t=conn_args_n_sim<exchg_t>;
102  using connection_t=typename base_t::connection_t;
103  using link_t=typename exchg_t::first_type;
104 
105  link_t link{
106  this->conn_pol,
107  link_t::skt_mgr_t::socket_t::socket_priority::low,
108  exchanges::common::thread_traits::client_to_exchange_thread.core,
109  };
110 };
111 
112 template<class exchg_t>
114  using base_t=conn_args_sim_n_link<exchg_t>;
115  using connection_t=typename base_t::connection_t;
116  using simulator_t=typename base_t::simulator_t;
117 
119  const typename connection_t::msg_details_t::LogonRequest msg(
120  typename connection_t::msg_details_t::LogonRequest::logon_args_t::UserName_t(this->conn_pol.logon_args.username),
121  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(this->conn_pol.logon_args.password),
122  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(this->conn_pol.logon_args.new_password)
123  );
124  BOOST_REQUIRE_NO_THROW(this->link.send(msg));
125  typename connection_t::msg_details_t::LogonReply reply;
126  BOOST_REQUIRE_NO_THROW(this->link.receive(reply));
127  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
128  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::LogonReply));
129  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogonReply));
130  BOOST_CHECK_EQUAL(reply.rejectCode(), connection_t::msg_details_t::LogonReply::logon_success);
131  }
133  const typename connection_t::msg_details_t::LogoutRequest msg(exchanges::MIT::common::Reason_t{"fubar"});
134  BOOST_REQUIRE_NO_THROW(this->link.send(msg));
135  typename connection_t::msg_details_t::Logout reply;
136  BOOST_REQUIRE_NO_THROW(this->link.receive(reply));
137  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
138  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::Logout));
139  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogoutRequest));
140  BOOST_CHECK_EQUAL(reply.reason(), this->conn_pol.logoff_args.reason);
141  }
142 };
143 
144 BOOST_AUTO_TEST_SUITE(exchange_gateways)
145 
146 BOOST_AUTO_TEST_SUITE(links)
147 
148 /**
149  \test Section 4.4: "Connectivity Policy" of [1] Test: both gateways unavailable.
150  ==========================================================================
151  Verify that more than 2*3*5 seconds passes if both gateways are unavailable.
152  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
153 */
154 BOOST_AUTO_TEST_CASE_TEMPLATE(both_gateways_unavailable, exchg_t, exchg_t_types) {
155  using fixture_t=conn_args<exchg_t>;
156  fixture_t f;
157 
158  auto const &begin=std::chrono::system_clock::now();
159  BOOST_CHECK_THROW(
160  typename exchg_t::first_type link(
161  f.conn_pol,
162  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
163  exchanges::common::thread_traits::client_to_exchange_thread.core
164  ),
165  std::exception
166  );
167  auto const &end=std::chrono::system_clock::now();
168  BOOST_CHECK_GE(std::chrono::duration_cast<std::chrono::seconds>(end-begin).count(), (fixture_t::conn_pol_t::max_attempts*fixture_t::conn_pol_t::min_timeout*2).count());
169 }
170 
171 /**
172  \test Section 4.4: "Connectivity Policy" of [1] Test: primary gateway available.
173  ==========================================================================
174  Verify that less than 5 seconds passes if just the primary gateway is available.
175  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
176 */
177 BOOST_AUTO_TEST_CASE_TEMPLATE(primary_gateway_available, exchg_t, exchg_t_types) {
178  using fixture_t=conn_args_n_sim<exchg_t>;
179  fixture_t f;
180 
181  auto const &begin=std::chrono::system_clock::now();
182  BOOST_REQUIRE_NO_THROW(
183  typename exchg_t::first_type link(
184  f.conn_pol,
185  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
186  exchanges::common::thread_traits::client_to_exchange_thread.core
187  )
188  );
189  auto const &end=std::chrono::system_clock::now();
190  BOOST_CHECK_LT(std::chrono::duration_cast<std::chrono::seconds>(end-begin).count(), fixture_t::conn_pol_t::min_timeout.count());
191 }
192 
193 /**
194  \test Re-connect to the available primary gateway.
195  ============================================
196  Verify that less than 5 seconds passes if just the primary gateway is available for the re-connections.
197  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
198 */
199 BOOST_AUTO_TEST_CASE_TEMPLATE(re_connnect, exchg_t, exchg_t_types) {
200  using fixture_t=conn_args_n_sim<exchg_t>;
201  fixture_t f;
202 
203  BOOST_REQUIRE_NO_THROW(
204  typename exchg_t::first_type link(
205  f.conn_pol,
206  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
207  exchanges::common::thread_traits::client_to_exchange_thread.core
208  )
209  );
210  auto const &begin=std::chrono::system_clock::now();
211  BOOST_REQUIRE_NO_THROW(
212  typename exchg_t::first_type link(
213  f.conn_pol,
214  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
215  exchanges::common::thread_traits::client_to_exchange_thread.core
216  )
217  );
218  auto const &end=std::chrono::system_clock::now();
219  BOOST_CHECK_LT(std::chrono::duration_cast<std::chrono::seconds>(end-begin).count(), fixture_t::conn_pol_t::min_timeout.count());
220 }
221 
222 /**
223  \test Section 4.4: "Connectivity Policy" of [1] Test: primary gateway unavailable.
224  ============================================================================
225  Verify that more than 3*5 seconds passes if just the primary gateway is unavailable, and the secondary available.
226  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
227 */
228 BOOST_AUTO_TEST_CASE_TEMPLATE(secondary_gateway_available, exchg_t, exchg_t_types) {
229  using fixture_t=conn_args<exchg_t>;
230  fixture_t f;
231 
232  typename fixture_t::simulator_t::proc_rules_t proc_rules;
233  no_latency_timestamps ts{0};
234  typename fixture_t::simulator_t svr(
235  boost::asio::ip::address(),
237  fixture_t::simulator_t::socket_t::socket_priority::high,
238  api_thread_traits::processor_mask_type(exchanges::common::thread_traits::exchange_simulator_thread.core),
239  exchanges::common::thread_traits::exchange_simulator_thread.priority,
240  proc_rules,
241  ts,
242  "sim" LIBJMMCG_ENQUOTE(__LINE__)
243  );
244 
245  auto const &begin=std::chrono::system_clock::now();
246  BOOST_REQUIRE_NO_THROW(
247  typename exchg_t::first_type link(
248  f.conn_pol,
249  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
250  exchanges::common::thread_traits::client_to_exchange_thread.core
251  )
252  );
253  auto const &end=std::chrono::system_clock::now();
254  BOOST_CHECK_GE(std::chrono::duration_cast<std::chrono::seconds>(end-begin).count(), (fixture_t::conn_pol_t::max_attempts*fixture_t::conn_pol_t::min_timeout).count());
255 }
256 
257 BOOST_AUTO_TEST_SUITE_END()
258 
259 BOOST_AUTO_TEST_SUITE(admin)
260 
261 /**
262  \test Section 5.1: "Establishing a connection" of [1] Test: LogonRequest response.
263  ============================================================================
264  Verify that the response to a LogonRequest is a LogonReply.
265  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
266 */
267 BOOST_AUTO_TEST_CASE_TEMPLATE(logon, exchg_t, exchg_t_types) {
268  using fixture_t=conn_args_sim_n_link<exchg_t>;
269  using connection_t=typename fixture_t::connection_t;
270  fixture_t f;
271 
272  const typename connection_t::msg_details_t::LogonRequest msg(
273  typename connection_t::msg_details_t::LogonRequest::logon_args_t::UserName_t(f.conn_pol.logon_args.username),
274  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.password),
275  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.new_password)
276  );
277  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
278  typename connection_t::msg_details_t::LogonReply reply;
279  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
280  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
281  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::LogonReply));
282  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogonReply));
283  BOOST_CHECK_EQUAL(reply.rejectCode(), connection_t::msg_details_t::LogonReply::logon_success);
284 }
285 
286 /**
287  \test Section 5.2.2: "Heartbeats" of [1] Test: Client Heartbeat.
288  ==========================================================
289  Verify that the response to a Heartbeat is nothing.
290  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
291 */
292 BOOST_AUTO_TEST_CASE_TEMPLATE(client_heartbeat, exchg_t, exchg_t_types) {
293  using fixture_t=conn_args_sim_n_link<exchg_t>;
294  using connection_t=typename fixture_t::connection_t;
295  fixture_t f;
296 
297  const typename connection_t::msg_details_t::ClientHeartbeat msg;
298  BOOST_CHECK_NO_THROW(f.link.send(msg));
299 }
300 
301 /**
302  \test Section 5.2.2: "Heartbeats" of [1] Test: Server Heartbeat.
303  ==========================================================
304  Verify that the simulator sends a heartbeat after the appropriate interval.
305  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
306 */
307 BOOST_AUTO_TEST_CASE_TEMPLATE(server_heartbeat, exchg_t, exchg_t_types) {
308  using fixture_t=conn_args_n_sim<exchg_t>;
309  using connection_t=typename fixture_t::connection_t;
310  fixture_t f;
311 
312  const auto start=std::chrono::high_resolution_clock::now();
313  typename exchg_t::first_type link(
314  f.conn_pol,
315  exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low,
316  exchanges::common::thread_traits::client_to_exchange_thread.core
317  );
318  typename connection_t::msg_details_t::ClientHeartbeat msg;
319  BOOST_REQUIRE_NO_THROW(link.receive(msg));
320  const auto got_hb=std::chrono::high_resolution_clock::now();
321  BOOST_CHECK_EQUAL(msg.start_of_message, 2);
322  BOOST_CHECK_EQUAL(msg.length(), sizeof(typename connection_t::msg_details_t::ClientHeartbeat));
323  BOOST_CHECK_EQUAL(msg.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::Heartbeat));
324  BOOST_CHECK_CLOSE(
325  static_cast<float>(std::chrono::duration_cast<std::chrono::milliseconds>(got_hb - start).count()),
326  static_cast<float>(
327  std::chrono::duration_cast<std::chrono::milliseconds>(
328  fixture_t::simulator_t::svr_mgr_t::heartbeats_t::heartbeat_interval
329  ).count()
330  ),
331  0.5
332  );
333 }
334 
335 /**
336  \test Section 5.3: "Terminating a connection" of [1] Test: LogoutRequest.
337  ===================================================================
338  Verify that the response to a LogoutRequest is a Logout.
339  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
340 */
341 BOOST_AUTO_TEST_CASE_TEMPLATE(logout, exchg_t, exchg_t_types) {
342  using fixture_t=conn_args_sim_n_link<exchg_t>;
343  using connection_t=typename fixture_t::connection_t;
344  fixture_t f;
345 
346  const typename connection_t::msg_details_t::LogoutRequest msg(exchanges::MIT::common::Reason_t{"fubar"});
347  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
348  typename connection_t::msg_details_t::Logout reply;
349  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
350  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
351  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::Logout));
352  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogoutRequest));
353  BOOST_CHECK_EQUAL(reply.reason(), f.conn_pol.logoff_args.reason);
354 }
355 
356 /**
357  \test Section 5.1: "Establishing a connection" of [1] Test: LogonRequest & LogoutRequest response.
358  ============================================================================================
359  Verify the behaviour of a LogonRequest followed by a and LogoutRequest.
360  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
361 */
362 BOOST_AUTO_TEST_CASE_TEMPLATE(logon_logout, exchg_t, exchg_t_types) {
363  using fixture_t=conn_args_sim_n_link<exchg_t>;
364  using connection_t=typename fixture_t::connection_t;
365  fixture_t f;
366 
367  const typename connection_t::msg_details_t::LogonRequest logon_msg(
368  typename connection_t::msg_details_t::LogonRequest::logon_args_t::UserName_t(f.conn_pol.logon_args.username),
369  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.password),
370  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.new_password)
371  );
372  BOOST_REQUIRE_NO_THROW(f.link.send(logon_msg));
373  typename connection_t::msg_details_t::LogonReply logon_reply;
374  BOOST_REQUIRE_NO_THROW(f.link.receive(logon_reply));
375  BOOST_CHECK_EQUAL(logon_reply.start_of_message, 2);
376  BOOST_CHECK_EQUAL(logon_reply.length(), sizeof(typename connection_t::msg_details_t::LogonReply));
377  BOOST_CHECK_EQUAL(logon_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogonReply));
378  BOOST_CHECK_EQUAL(logon_reply.rejectCode(), connection_t::msg_details_t::LogonReply::logon_success);
379  const typename connection_t::msg_details_t::LogoutRequest logout_msg(exchanges::MIT::common::Reason_t{"fubar"});
380  BOOST_REQUIRE_NO_THROW(f.link.send(logout_msg));
381  typename connection_t::msg_details_t::Logout logout_reply;
382  BOOST_REQUIRE_NO_THROW(f.link.receive(logout_reply));
383  BOOST_CHECK_EQUAL(logout_reply.start_of_message, 2);
384  BOOST_CHECK_EQUAL(logout_reply.length(), sizeof(typename connection_t::msg_details_t::Logout));
385  BOOST_CHECK_EQUAL(logout_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogoutRequest));
386  BOOST_CHECK_EQUAL(logout_reply.reason(), f.conn_pol.logoff_args.reason);
387 }
388 
389 /**
390  \test Section 5.1: "Establishing a connection" of [1] Test: Re-LogonRequest & LogoutRequest response.
391  ===============================================================================================
392  Verify the behaviour of a LogonRequest followed by a and LogoutRequest, repeated.
393  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
394 */
395 /* TODO - doesn't pass as not fixed....
396 BOOST_AUTO_TEST_CASE_TEMPLATE(re_logon_logout, exchg_t, exchg_t_types) {
397  using fixture_t=conn_args_n_sim<exchg_t>;
398  using connection_t=typename fixture_t::connection_t;
399  fixture_t f;
400 
401  {
402  typename exchg_t::first_type link(f.conn_pol, exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low);
403  const typename connection_t::msg_details_t::LogonRequest logon_msg(
404  typename connection_t::msg_details_t::LogonRequest::logon_args_t::UserName_t(f.conn_pol.logon_args.username),
405  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.password),
406  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.new_password)
407  );
408  BOOST_REQUIRE_NO_THROW(link.send(logon_msg));
409  typename connection_t::msg_details_t::LogonReply logon_reply;
410  BOOST_REQUIRE_NO_THROW(link.receive(logon_reply));
411  BOOST_CHECK_EQUAL(logon_reply.start_of_message, 2);
412  BOOST_CHECK_EQUAL(logon_reply.length(), sizeof(typename connection_t::msg_details_t::LogonReply));
413  BOOST_CHECK_EQUAL(logon_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogonReply));
414  BOOST_CHECK_EQUAL(logon_reply.rejectCode(), connection_t::msg_details_t::LogonReply::logon_success);
415  const typename connection_t::msg_details_t::LogoutRequest logout_msg(exchanges::MIT::common::Reason_t{"fubar"});
416  BOOST_REQUIRE_NO_THROW(link.send(logout_msg));
417  typename connection_t::msg_details_t::Logout logout_reply;
418  BOOST_REQUIRE_NO_THROW(link.receive(logout_reply));
419  BOOST_CHECK_EQUAL(logout_reply.start_of_message, 2);
420  BOOST_CHECK_EQUAL(logout_reply.length(), sizeof(typename connection_t::msg_details_t::Logout));
421  BOOST_CHECK_EQUAL(logout_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogoutRequest));
422  BOOST_CHECK_EQUAL(logout_reply.reason(), f.conn_pol.logoff_args.reason);
423  }
424  {
425  typename exchg_t::first_type link(f.conn_pol, exchg_t::first_type::skt_mgr_t::socket_t::socket_priority::low);
426  const typename connection_t::msg_details_t::LogonRequest logon_msg(
427  typename connection_t::msg_details_t::LogonRequest::logon_args_t::UserName_t(f.conn_pol.logon_args.username),
428  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.password),
429  typename connection_t::msg_details_t::LogonRequest::logon_args_t::Password_t(f.conn_pol.logon_args.new_password)
430  );
431  BOOST_REQUIRE_NO_THROW(link.send(logon_msg));
432  typename connection_t::msg_details_t::LogonReply logon_reply;
433  BOOST_REQUIRE_NO_THROW(link.receive(logon_reply));
434  BOOST_CHECK_EQUAL(logon_reply.start_of_message, 2);
435  BOOST_CHECK_EQUAL(logon_reply.length(), sizeof(typename connection_t::msg_details_t::LogonReply));
436  BOOST_CHECK_EQUAL(logon_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogonReply));
437  BOOST_CHECK_EQUAL(logon_reply.rejectCode(), connection_t::msg_details_t::LogonReply::logon_success);
438  const typename connection_t::msg_details_t::LogoutRequest logout_msg(exchanges::MIT::common::Reason_t{"fubar"});
439  BOOST_REQUIRE_NO_THROW(link.send(logout_msg));
440  typename connection_t::msg_details_t::Logout logout_reply;
441  BOOST_REQUIRE_NO_THROW(link.receive(logout_reply));
442  BOOST_CHECK_EQUAL(logout_reply.start_of_message, 2);
443  BOOST_CHECK_EQUAL(logout_reply.length(), sizeof(typename connection_t::msg_details_t::Logout));
444  BOOST_CHECK_EQUAL(logout_reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::AdminMsgType::LogoutRequest));
445  BOOST_CHECK_EQUAL(logout_reply.reason(), f.conn_pol.logoff_args.reason);
446  }
447 }
448 */
449 BOOST_AUTO_TEST_SUITE_END()
450 
451 BOOST_AUTO_TEST_SUITE(client_initiated)
452 
453 /**
454  \test Section 9.1 "Order handling" of [1] Test: Response to an invalid NewOrder.
455  ==========================================================================
456  Verify that the response to an invalid NewOrder is a Reject.
457  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
458 */
459 BOOST_AUTO_TEST_CASE_TEMPLATE(reject, exchg_t, exchg_t_types) {
460  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
461  using connection_t=typename fixture_t::connection_t;
462  fixture_t f;
463 
464  const typename connection_t::msg_details_t::NewOrder_t msg(
465  0,
466  clientOrderId1,
467  exchg_t::first_type::msg_details_t::OrderType::Market,
468  exchanges::MIT::common::TIF::Day,
469  exchg_t::first_type::msg_details_t::Side::Buy,
470  exchg_t::second_type::proc_rules_t::invalidInstrumentID,
471  exchg_t::second_type::proc_rules_t::quantity_limit-1,
472  exchg_t::second_type::proc_rules_t::scaled_price
473  );
474  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
475  typename connection_t::msg_details_t::BusinessReject reply;
476  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
477  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
478  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::BusinessReject));
479  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::BusinessMessageReject));
480  BOOST_CHECK_EQUAL(reply.clientOrderID().begin(), msg.clientOrderID().begin());
481  BOOST_CHECK_EQUAL(reply.rejectCode(), connection_t::msg_details_t::BusinessReject::unknown_instrument);
482 }
483 
484 /**
485  \test Section 9.1 "Order handling" of [1] Test: Response to an invalid OrderCancelRequest.
486  ====================================================================================
487  Verify that the response to an invalid OrderCancelRequest is a OrderCancelReject.
488  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
489 */
490 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_reject, exchg_t, exchg_t_types) {
491  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
492  using connection_t=typename fixture_t::connection_t;
493  fixture_t f;
494 
495  const typename connection_t::msg_details_t::OrderCancelRequest msg(
496  clientOrderId1,
497  clientOrderId1,
498  exchg_t::second_type::proc_rules_t::invalidInstrumentID,
499  exchg_t::first_type::msg_details_t::Side::Buy
500  );
501  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
502  typename connection_t::msg_details_t::OrderCancelReject reply;
503  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
504  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
505  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::OrderCancelReject));
506  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::OrderCancelReject));
507  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.originalClientOrderID());
508 }
509 
510 /**
511  \test Section 9.1 "Order handling" of [1] Test: Response to a valid OrderCancelRequest.
512  =================================================================================
513  Verify that the response to a valid OrderCancelRequest is a cancelled order ExecutionReport.
514  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
515 */
516 BOOST_AUTO_TEST_CASE_TEMPLATE(cancel_accept, exchg_t, exchg_t_types) {
517  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
518  using connection_t=typename fixture_t::connection_t;
519  fixture_t f;
520 
521  const typename connection_t::msg_details_t::NewOrder_t msg(
522  0,
523  clientOrderId1,
524  exchg_t::first_type::msg_details_t::OrderType::Limit,
525  exchanges::MIT::common::TIF::Day,
526  exchg_t::first_type::msg_details_t::Side::Buy,
527  exchg_t::second_type::proc_rules_t::instrumentID,
528  exchg_t::second_type::proc_rules_t::quantity_limit-1,
529  exchg_t::second_type::proc_rules_t::scaled_price+1
530  );
531  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
532  const typename connection_t::msg_details_t::OrderCancelRequest msg1(
533  clientOrderId1,
534  clientOrderId1,
535  exchg_t::second_type::proc_rules_t::invalidInstrumentID,
536  exchg_t::first_type::msg_details_t::Side::Buy
537  );
538  BOOST_REQUIRE_NO_THROW(f.link.send(msg1));
539  typename connection_t::msg_details_t::ExecutionReport reply;
540  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
541  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
542  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
543  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
544  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
545  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::New);
546  BOOST_CHECK_EQUAL(reply.executedPrice(), 0);
547  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
548  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
549  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::New);
550  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
551  BOOST_CHECK_EQUAL(reply.leavesQty(), msg.orderQty());
552  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
553  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
554  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
555  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
556  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
557  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::Cancelled);
558  BOOST_CHECK_EQUAL(reply.executedPrice(), msg.limitPrice());
559  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
560  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
561  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
562  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
563  BOOST_CHECK_EQUAL(reply.leavesQty(), msg.orderQty());
564 }
565 
566 /**
567  \test Section 9.1 "Order handling" of [1] Test: Response to an invalid OrderCancelReplaceRequest.
568  ===========================================================================================
569  Verify that the response to an invalid OrderCancelReplaceRequest is a cancelled order OrderCancelReject.
570  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
571 */
572 BOOST_AUTO_TEST_CASE_TEMPLATE(modify_reject, exchg_t, exchg_t_types) {
573  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
574  using connection_t=typename fixture_t::connection_t;
575  fixture_t f;
576 
577  const typename connection_t::msg_details_t::OrderCancelReplaceRequest msg(
578  clientOrderId1,
579  clientOrderId1,
580  exchg_t::second_type::proc_rules_t::instrumentID,
581  exchg_t::second_type::proc_rules_t::quantity_limit,
582  exchg_t::second_type::proc_rules_t::scaled_price,
583  exchanges::MIT::common::TIF::Day,
584  exchg_t::first_type::msg_details_t::Side::Sell
585  );
586  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
587  typename connection_t::msg_details_t::OrderCancelReject reply;
588  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
589  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
590  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::OrderCancelReject));
591  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::OrderCancelReject));
592  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.originalClientOrderID());
593 }
594 
595 /**
596  \test Section 9.1 "Order handling" of [1] Test: Response to a valid OrderCancelReplaceRequest.
597  ========================================================================================
598  Verify that the response to a valid OrderCancelReplaceRequest is a cancelled order ExecutionReport.
599  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
600 */
601 BOOST_AUTO_TEST_CASE_TEMPLATE(modify_accept, exchg_t, exchg_t_types) {
602  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
603  using connection_t=typename fixture_t::connection_t;
604  fixture_t f;
605 
606  const typename connection_t::msg_details_t::NewOrder_t msg(
607  0,
608  clientOrderId1,
609  exchg_t::first_type::msg_details_t::OrderType::Limit,
610  exchanges::MIT::common::TIF::Day,
611  exchg_t::first_type::msg_details_t::Side::Buy,
612  exchg_t::second_type::proc_rules_t::instrumentID,
613  exchg_t::second_type::proc_rules_t::quantity_limit-1,
614  exchg_t::second_type::proc_rules_t::scaled_price+1
615  );
616  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
617  const typename connection_t::msg_details_t::OrderCancelReplaceRequest msg1(
618  clientOrderId1,
619  clientOrderId1,
620  msg.instrumentID(),
621  exchg_t::second_type::proc_rules_t::quantity_limit,
622  msg.limitPrice()+2,
623  msg.tif(),
624  exchg_t::first_type::msg_details_t::Side::Sell
625  );
626  BOOST_REQUIRE_NO_THROW(f.link.send(msg1));
627  typename connection_t::msg_details_t::ExecutionReport reply;
628  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
629  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
630  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
631  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
632  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
633  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::New);
634  BOOST_CHECK_EQUAL(reply.executedPrice(), 0);
635  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
636  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
637  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::New);
638  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
639  BOOST_CHECK_EQUAL(reply.leavesQty(), msg.orderQty());
640  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
641  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
642  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
643  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
644  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
645  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::Replaced);
646  BOOST_CHECK_EQUAL(reply.executedPrice(), msg1.limitPrice());
647  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
648  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Sell);
649  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
650  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
651  BOOST_CHECK_EQUAL(reply.leavesQty(), msg1.orderQty());
652 }
653 
654 BOOST_AUTO_TEST_SUITE(new_order)
655 
656 BOOST_AUTO_TEST_SUITE(buy)
657 
658 BOOST_AUTO_TEST_SUITE(day)
659 
660 BOOST_AUTO_TEST_SUITE(market)
661 
662 /**
663  \test Section 9.1 "Order handling" of [1] Test: Response to a BUY, DAY, MARKET NewOrder is a filled ExecutionReport.
664  ==============================================================================================================
665  Verify that the response to a buy, day, market NewOrder is a filled ExecutionReport.
666  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
667 */
668 BOOST_AUTO_TEST_CASE_TEMPLATE(new_order, exchg_t, exchg_t_types) {
669  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
670  using connection_t=typename fixture_t::connection_t;
671  fixture_t f;
672 
673  const typename connection_t::msg_details_t::NewOrder_t msg(
674  0,
675  clientOrderId1,
676  exchg_t::first_type::msg_details_t::OrderType::Market,
677  exchanges::MIT::common::TIF::Day,
678  exchg_t::first_type::msg_details_t::Side::Buy,
679  exchg_t::second_type::proc_rules_t::instrumentID,
680  exchg_t::second_type::proc_rules_t::quantity_limit-1,
681  exchg_t::second_type::proc_rules_t::scaled_price
682  );
683  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
684  typename connection_t::msg_details_t::ExecutionReport reply;
685  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
686  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
687  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
688  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
689  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
690  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::New);
691  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
692  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
693  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Filled);
694  BOOST_CHECK_EQUAL(reply.executedQty(), msg.orderQty());
695  BOOST_CHECK_EQUAL(reply.leavesQty(), 0);
696  BOOST_CHECK_EQUAL(reply.executedPrice(), msg.limitPrice());
697 }
698 
699 /**
700  \test Section 9.1 "Order handling" of [1] Test: Response to a BUY, DAY, MARKET NewOrder is a partially-filled ExecutionReport.
701  ==============================================================================================================
702  Verify that the response to a suitably large, buy, day, market NewOrder is a partially-filled ExecutionReport.
703  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
704 */
705 BOOST_AUTO_TEST_CASE_TEMPLATE(partial_fill, exchg_t, exchg_t_types) {
706  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
707  using connection_t=typename fixture_t::connection_t;
708  fixture_t f;
709 
710  const typename connection_t::msg_details_t::NewOrder_t msg(
711  0,
712  clientOrderId1,
713  exchg_t::first_type::msg_details_t::OrderType::Market,
714  exchanges::MIT::common::TIF::Day,
715  exchg_t::first_type::msg_details_t::Side::Buy,
716  exchg_t::second_type::proc_rules_t::instrumentID,
717  exchg_t::second_type::proc_rules_t::quantity_limit+1,
718  exchg_t::second_type::proc_rules_t::scaled_price
719  );
720  BOOST_REQUIRE_NO_THROW(f.link.send(msg));
721  typename connection_t::msg_details_t::ExecutionReport reply;
722  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
723  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
724  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
725  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
726  BOOST_CHECK_EQUAL(reply.clientOrderID(), msg.clientOrderID());
727  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::New);
728  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
729  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
730  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Partiallyfilled);
731  BOOST_CHECK_EQUAL(reply.executedQty(), exchg_t::second_type::proc_rules_t::quantity_limit);
732  BOOST_CHECK_EQUAL(reply.leavesQty(), msg.orderQty()-exchg_t::second_type::proc_rules_t::quantity_limit);
733  BOOST_CHECK_EQUAL(reply.executedPrice(), msg.limitPrice());
734 }
735 
736 /**
737  \test Section 9.1 "Order handling" of [1] Test: Response to a OrderCancelRequest is a cancelled ExecutionReport.
738  ==============================================================================================================
739  Verify that the response to a OrderCancelRequest of the remaining quantity of a suitably large, buy, day, market NewOrder is a cancelled ExecutionReport.
740  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
741 */
742 BOOST_AUTO_TEST_CASE_TEMPLATE(partial_fill_cancel, exchg_t, exchg_t_types) {
743  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
744  using connection_t=typename fixture_t::connection_t;
745  fixture_t f;
746 
747  const typename connection_t::msg_details_t::NewOrder_t new_order(
748  0,
749  clientOrderId1,
750  exchg_t::first_type::msg_details_t::OrderType::Market,
751  exchanges::MIT::common::TIF::Day,
752  exchg_t::first_type::msg_details_t::Side::Buy,
753  exchg_t::second_type::proc_rules_t::instrumentID,
754  exchg_t::second_type::proc_rules_t::quantity_limit+1,
755  exchg_t::second_type::proc_rules_t::scaled_price
756  );
757  BOOST_REQUIRE_NO_THROW(f.link.send(new_order));
758  typename connection_t::msg_details_t::ExecutionReport partial_fill;
759  BOOST_REQUIRE_NO_THROW(f.link.receive(partial_fill));
760  const typename connection_t::msg_details_t::OrderCancelRequest cancel(
761  clientOrderId1,
762  clientOrderId1,
763  exchg_t::second_type::proc_rules_t::instrumentID,
764  exchg_t::first_type::msg_details_t::Side::Buy
765  );
766  BOOST_REQUIRE_NO_THROW(f.link.send(cancel));
767  typename connection_t::msg_details_t::ExecutionReport reply;
768  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
769  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
770  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
771  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
772  BOOST_CHECK_EQUAL(reply.clientOrderID(), new_order.clientOrderID());
773  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::Cancelled);
774  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
775  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
776  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
777  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
778  BOOST_CHECK_EQUAL(reply.leavesQty(), new_order.orderQty()-exchg_t::second_type::proc_rules_t::quantity_limit);
779  BOOST_CHECK_EQUAL(reply.executedPrice(), new_order.limitPrice());
780 }
781 
782 /**
783  \test Section 9.1 "Order handling" of [1] Test: Response to a OrderCancelReplaceRequest is a replaced ExecutionReport.
784  ==============================================================================================================
785  Verify that the response to a OrderCancelReplaceRequest of the remaining quantity of a suitably large, buy, day, market NewOrder is a replaced ExecutionReport.
786  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
787 */
788 BOOST_AUTO_TEST_CASE_TEMPLATE(partial_fill_replace, exchg_t, exchg_t_types) {
789  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
790  using connection_t=typename fixture_t::connection_t;
791  fixture_t f;
792 
793  const typename connection_t::msg_details_t::NewOrder_t new_order(
794  0,
795  clientOrderId1,
796  exchg_t::first_type::msg_details_t::OrderType::Market,
797  exchanges::MIT::common::TIF::Day,
798  exchg_t::first_type::msg_details_t::Side::Buy,
799  exchg_t::second_type::proc_rules_t::instrumentID,
800  exchg_t::second_type::proc_rules_t::quantity_limit+1,
801  exchg_t::second_type::proc_rules_t::scaled_price
802  );
803  BOOST_REQUIRE_NO_THROW(f.link.send(new_order));
804  typename connection_t::msg_details_t::ExecutionReport partial_fill;
805  BOOST_REQUIRE_NO_THROW(f.link.receive(partial_fill));
806  const typename connection_t::msg_details_t::OrderCancelReplaceRequest replace(
807  clientOrderId1,
808  clientOrderId1,
809  exchg_t::second_type::proc_rules_t::instrumentID,
810  partial_fill.leavesQty()+1,
811  exchg_t::second_type::proc_rules_t::scaled_price*2,
812  exchanges::MIT::common::TIF::Day,
813  exchg_t::first_type::msg_details_t::Side::Sell
814  );
815  BOOST_REQUIRE_NO_THROW(f.link.send(replace));
816  typename connection_t::msg_details_t::ExecutionReport reply;
817  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
818  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
819  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
820  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
821  BOOST_CHECK_EQUAL(reply.clientOrderID(), new_order.clientOrderID());
822  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::Replaced);
823  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
824  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Sell);
825  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
826  BOOST_CHECK_EQUAL(reply.executedQty(), 0);
827  BOOST_CHECK_EQUAL(reply.leavesQty(), partial_fill.leavesQty()+1);
828  BOOST_CHECK_EQUAL(reply.executedPrice(), new_order.limitPrice()*2);
829 }
830 
831 BOOST_AUTO_TEST_SUITE_END()
832 
833 BOOST_AUTO_TEST_SUITE(limit)
834 
835 /**
836  \test Section 9.1 "Order handling" of [1] Test: Response to a BUY, DAY, LIMIT NewOrder is a filled ExecutionReport.
837  ==============================================================================================================
838  Verify that the response to a buy, day, limit NewOrder is a filled ExecutionReport.
839  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
840 */
841 BOOST_AUTO_TEST_CASE_TEMPLATE(new_order, exchg_t, exchg_t_types) {
842  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
843  using connection_t=typename fixture_t::connection_t;
844  fixture_t f;
845 
846  const typename connection_t::msg_details_t::NewOrder_t new_order(
847  0,
848  clientOrderId1,
849  exchg_t::first_type::msg_details_t::OrderType::Limit,
850  exchanges::MIT::common::TIF::Day,
851  exchg_t::first_type::msg_details_t::Side::Buy,
852  exchg_t::second_type::proc_rules_t::instrumentID,
853  exchg_t::second_type::proc_rules_t::quantity_limit-1,
854  exchg_t::second_type::proc_rules_t::scaled_price-1
855  );
856  BOOST_REQUIRE_NO_THROW(f.link.send(new_order));
857  typename connection_t::msg_details_t::ExecutionReport reply;
858  BOOST_REQUIRE_NO_THROW(f.link.receive(reply));
859  BOOST_CHECK_EQUAL(reply.start_of_message, 2);
860  BOOST_CHECK_EQUAL(reply.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
861  BOOST_CHECK_EQUAL(reply.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
862  BOOST_CHECK_EQUAL(reply.clientOrderID(), new_order.clientOrderID());
863  BOOST_CHECK_EQUAL(reply.execType(), exchanges::MIT::common::ExecType::New);
864  BOOST_CHECK_EQUAL(reply.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
865  BOOST_CHECK_EQUAL(reply.side(), exchg_t::first_type::msg_details_t::Side::Buy);
866  BOOST_CHECK_EQUAL(reply.orderStatus(), exchanges::MIT::common::OrderStatus::Filled);
867  BOOST_CHECK_EQUAL(reply.executedQty(), new_order.orderQty());
868  BOOST_CHECK_EQUAL(reply.leavesQty(), 0);
869  BOOST_CHECK_EQUAL(reply.executedPrice(), new_order.limitPrice());
870 }
871 
872 /**
873  \test Section 9.1 "Order handling" of [1] Test: Response to a suitable BUY, DAY, LIMIT NewOrder followed by an OrderCancelRequest is a cancelled ExecutionReport.
874  ===========================================================================================================================================================
875  Verify that the response to a buy, day, limit NewOrder that is open on the exchange then cancelled is a cancelled ExecutionReport.
876  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
877 */
878 BOOST_AUTO_TEST_CASE_TEMPLATE(open_cancelled, exchg_t, exchg_t_types) {
879  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
880  using connection_t=typename fixture_t::connection_t;
881  fixture_t f;
882 
883  const typename connection_t::msg_details_t::NewOrder_t new_order(
884  0,
885  clientOrderId1,
886  exchg_t::first_type::msg_details_t::OrderType::Limit,
887  exchanges::MIT::common::TIF::Day,
888  exchg_t::first_type::msg_details_t::Side::Buy,
889  exchg_t::second_type::proc_rules_t::instrumentID,
890  exchg_t::second_type::proc_rules_t::quantity_limit-1,
891  fixture_t::simulator_t::proc_rules_t::scaled_price+1
892  );
893  BOOST_REQUIRE_NO_THROW(f.link.send(new_order));
894  const typename connection_t::msg_details_t::OrderCancelRequest cancel(
895  clientOrderId1,
896  clientOrderId1,
897  exchg_t::second_type::proc_rules_t::instrumentID,
898  exchg_t::first_type::msg_details_t::Side::Buy
899  );
900  BOOST_REQUIRE_NO_THROW(f.link.send(cancel));
901  typename connection_t::msg_details_t::ExecutionReport cancelled;
902  BOOST_REQUIRE_NO_THROW(f.link.receive(cancelled));
903  BOOST_CHECK_EQUAL(cancelled.start_of_message, 2);
904  BOOST_CHECK_EQUAL(cancelled.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
905  BOOST_CHECK_EQUAL(cancelled.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
906  BOOST_CHECK_EQUAL(cancelled.clientOrderID(), new_order.clientOrderID());
907  BOOST_CHECK_EQUAL(cancelled.execType(), exchanges::MIT::common::ExecType::New);
908  BOOST_CHECK_EQUAL(cancelled.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
909  BOOST_CHECK_EQUAL(cancelled.side(), exchg_t::first_type::msg_details_t::Side::Buy);
910  BOOST_CHECK_EQUAL(cancelled.orderStatus(), exchanges::MIT::common::OrderStatus::New);
911  BOOST_CHECK_EQUAL(cancelled.executedQty(), 0);
912  BOOST_CHECK_EQUAL(cancelled.leavesQty(), new_order.orderQty());
913  BOOST_CHECK_EQUAL(cancelled.executedPrice(), 0);
914  BOOST_REQUIRE_NO_THROW(f.link.receive(cancelled));
915  BOOST_CHECK_EQUAL(cancelled.start_of_message, 2);
916  BOOST_CHECK_EQUAL(cancelled.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
917  BOOST_CHECK_EQUAL(cancelled.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
918  BOOST_CHECK_EQUAL(cancelled.clientOrderID(), new_order.clientOrderID());
919  BOOST_CHECK_EQUAL(cancelled.execType(), exchanges::MIT::common::ExecType::Cancelled);
920  BOOST_CHECK_EQUAL(cancelled.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
921  BOOST_CHECK_EQUAL(cancelled.side(), exchg_t::first_type::msg_details_t::Side::Buy);
922  BOOST_CHECK_EQUAL(cancelled.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
923  BOOST_CHECK_EQUAL(cancelled.executedQty(), 0);
924  BOOST_CHECK_EQUAL(cancelled.leavesQty(), new_order.orderQty());
925  BOOST_CHECK_EQUAL(cancelled.executedPrice(), new_order.limitPrice());
926 }
927 
928 /**
929  \test Section 9.1 "Order handling" of [1] Test: Response to a suitable BUY, DAY, LIMIT NewOrder followed by an OrderCancelReplaceRequest is a cancelled ExecutionReport.
930  ==================================================================================================================================================================
931  Verify that the response to a buy, day, limit NewOrder that is open on the exchange then modified is a cancelled ExecutionReport.
932  [1] "MIT203 - MILLENNIUM EXCHANGE Native Trading Gateway"
933 */
934 BOOST_AUTO_TEST_CASE_TEMPLATE(open_modified, exchg_t, exchg_t_types) {
935  using fixture_t=conn_args_sim_n_link_logon_logoff<exchg_t>;
936  using connection_t=typename fixture_t::connection_t;
937  fixture_t f;
938 
939  const typename connection_t::msg_details_t::NewOrder_t new_order(
940  0,
941  clientOrderId1,
942  exchg_t::first_type::msg_details_t::OrderType::Limit,
943  exchanges::MIT::common::TIF::Day,
944  exchg_t::first_type::msg_details_t::Side::Buy,
945  exchg_t::second_type::proc_rules_t::instrumentID,
946  exchg_t::second_type::proc_rules_t::quantity_limit-1,
947  fixture_t::simulator_t::proc_rules_t::scaled_price+1
948  );
949  BOOST_REQUIRE_NO_THROW(f.link.send(new_order));
950  const typename connection_t::msg_details_t::OrderCancelReplaceRequest replace(
951  clientOrderId1,
952  clientOrderId1,
953  new_order.instrumentID(),
954  exchg_t::second_type::proc_rules_t::quantity_limit,
955  new_order.limitPrice()+2,
956  new_order.tif(),
957  exchg_t::first_type::msg_details_t::Side::Sell
958  );
959  BOOST_REQUIRE_NO_THROW(f.link.send(replace));
960  typename connection_t::msg_details_t::ExecutionReport cancelled;
961  BOOST_REQUIRE_NO_THROW(f.link.receive(cancelled));
962  BOOST_CHECK_EQUAL(cancelled.start_of_message, 2);
963  BOOST_CHECK_EQUAL(cancelled.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
964  BOOST_CHECK_EQUAL(cancelled.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
965  BOOST_CHECK_EQUAL(cancelled.clientOrderID(), new_order.clientOrderID());
966  BOOST_CHECK_EQUAL(cancelled.execType(), exchanges::MIT::common::ExecType::New);
967  BOOST_CHECK_EQUAL(cancelled.executedPrice(), 0);
968  BOOST_CHECK_EQUAL(cancelled.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
969  BOOST_CHECK_EQUAL(cancelled.side(), exchg_t::first_type::msg_details_t::Side::Buy);
970  BOOST_CHECK_EQUAL(cancelled.orderStatus(), exchanges::MIT::common::OrderStatus::New);
971  BOOST_CHECK_EQUAL(cancelled.executedQty(), 0);
972  BOOST_CHECK_EQUAL(cancelled.leavesQty(), new_order.orderQty());
973  BOOST_REQUIRE_NO_THROW(f.link.receive(cancelled));
974  BOOST_CHECK_EQUAL(cancelled.start_of_message, 2);
975  BOOST_CHECK_EQUAL(cancelled.length(), sizeof(typename connection_t::msg_details_t::ExecutionReport));
976  BOOST_CHECK_EQUAL(cancelled.type(), static_cast<exchanges::MIT::common::MsgType_t>(exchanges::MIT::common::ServerMsgType::ExecutionReport));
977  BOOST_CHECK_EQUAL(cancelled.clientOrderID(), new_order.clientOrderID());
978  BOOST_CHECK_EQUAL(cancelled.execType(), exchanges::MIT::common::ExecType::Replaced);
979  BOOST_CHECK_EQUAL(cancelled.executedPrice(), replace.limitPrice());
980  BOOST_CHECK_EQUAL(cancelled.instrumentID(), exchg_t::second_type::proc_rules_t::instrumentID);
981  BOOST_CHECK_EQUAL(cancelled.side(), exchg_t::first_type::msg_details_t::Side::Sell);
982  BOOST_CHECK_EQUAL(cancelled.orderStatus(), exchanges::MIT::common::OrderStatus::Cancelled);
983  BOOST_CHECK_EQUAL(cancelled.executedQty(), 0);
984  BOOST_CHECK_EQUAL(cancelled.leavesQty(), replace.orderQty());
985 }
986 
987 BOOST_AUTO_TEST_SUITE_END()
988 
989 BOOST_AUTO_TEST_SUITE_END()
990 
991 BOOST_AUTO_TEST_SUITE_END()
992 
993 BOOST_AUTO_TEST_SUITE_END()
994 
995 BOOST_AUTO_TEST_SUITE_END()
996 
997 BOOST_AUTO_TEST_SUITE_END()