OnixS C++ ICE Binary Order Entry Handler 1.1.1
API Documentation
Loading...
Searching...
No Matches
TradingClient.cpp
Go to the documentation of this file.
1/*
2* Copyright Onix Solutions Limited [OnixS]. All rights reserved.
3*
4* This software owned by Onix Solutions Limited [OnixS] and is protected by copyright law
5* and international copyright treaties.
6*
7* Access to and use of the software is governed by the terms of the applicable OnixS Software
8* Services Agreement (the Agreement) and Customer end user license agreements granting
9* a non-assignable, non-transferable and non-exclusive license to use the software
10* for it's own data processing purposes under the terms defined in the Agreement.
11*
12* Except as otherwise granted within the terms of the Agreement, copying or reproduction of any part
13* of this source code or associated reference material to any other location for further reproduction
14* or redistribution, and any amendments to this copyright notice, are expressly prohibited.
15*
16* Any reproduction or redistribution for sale or hiring of the Software not in accordance with
17* the terms of the Agreement is a violation of copyright law.
18*/
20
21#include <Settings/Defaults.h>
22#include <Common/Tools.h>
23#include <Common/Helpers.h>
24#include "Utils.h"
25
26#include "TradingClient.h"
27
28namespace Samples {
29
30using namespace ONIXS_ICEBOE_NAMESPACE;
32using namespace CUI;
33
34namespace {
35
36void checkSettingSanity(const Settings& settings)
37{
38 const auto traderId = settings.get("TraderId");
39 const auto traderPwd = settings.get("TraderPwd");
40 const auto clientId = settings.get<Int32>("ClientId");
41 const auto userId = settings.get("UserId");
42 const auto userPwd = settings.get("Password");
43 const auto host = settings.get("Host");
44 const auto port = settings.get<Port>("Port");
45 const auto onBehalfOfSubId = settings.get("OnBehalfOfSubId");
46 const auto onBehalfOfLocationId = settings.get("OnBehalfOfLocationId");
47 const auto onBehalfOfCompId = settings.get("OnBehalfOfCompId");
48 const auto clearingFirm = settings.get<Int32>("ClearingFirm");
49 const auto clearingAccount = settings.get("ClearingAccount");
50 const auto mifidId = settings.get<Int64>("MifidId");
51 const auto keepAliveInterval = settings.get<UInt16>("KeepAliveInterval");
52 const auto investmentDecision = settings.get<Int64>("InvestmentDecision");
53 const auto executionDecision = settings.get<Int64>("ExecutionDecision");
54
56 traderId
57 ,traderPwd
58 ,clientId
59 ,userId
60 ,userPwd
61 ,host
62 ,port
63 ,onBehalfOfSubId
64 ,onBehalfOfLocationId
65 ,onBehalfOfCompId
66 ,clearingFirm
67 ,clearingAccount
68 ,mifidId
69 ,keepAliveInterval
70 ,investmentDecision
71 ,executionDecision
72 );
73}
74
75SessionSettings fillSessionSettings(const Settings& settings)
76{
77 checkSettingSanity(settings);
78
79 SessionSettings sessionSettings;
80
81 sessionSettings
82 .licenseStore("../../license")
83 .userId(settings.get("UserId"))
84 .clientId(settings.get<Int32>("ClientId"))
85 .rawData(settings.get("Password"))
86 .reconnectAttempts(100)
87 .reconnectInterval(1)
88 .keepAliveInterval(settings.get<UInt16>("KeepAliveInterval"))
89 .useTLS(settings.get<Port>("Port") == Default::TlsPort)
90 ;
91
92 return sessionSettings;
93}
94
95auto initSecurityDefinitionRequest(const Settings&)
96{
98 return request;
99}
100
101auto initNewOrder(const Settings& settings)
102{
103 NewOrderRequestMsg request;
104
105 request->
106 originatorUserId(settings.get("TraderId"))
107 .onBehalfOfSubId(settings.get("OnBehalfOfSubId"))
108 .onBehalfOfLocationId(settings.get("OnBehalfOfLocationId"))
109 .onBehalfOfCompId(settings.get("OnBehalfOfCompId"))
110 .clearingFirm(settings.get<Int32>("ClearingFirm"))
111 .clearingAccount(settings.get("ClearingAccount"))
112 .mifidId(settings.get<Int64NULL>("MifidId"))
113 .manualOrderIndicator(BooleanEnum::True)
114 .custOrderHandlingInst(CustOrderHandlingInstEnum::Y)
115 .memo("NewOrderRequest")
116 .selfMatchPreventionInstruction(SelfMatchPreventionInstructionEnum::CancelTakingOrder);
117
118 if(settings.isSet("SelfMatchPreventionId"))
119 request->selfMatchPreventionId(settings.get<Int64>("SelfMatchPreventionId"));
120
121 return request;
122}
123
124auto initOrderCancelRequest(const Settings& settings)
125{
126 CancelRequestMsg request;
127
128 request->originatorUserId(settings.get("TraderId"));
129
130 return request;
131}
132
133auto initOrderReplaceRequest(const Settings& settings)
134{
136
137 request->
138 originatorUserId(settings.get("TraderId"))
139 .onBehalfOfSubId(settings.get("OnBehalfOfSubId"))
140 .onBehalfOfLocationId(settings.get("OnBehalfOfLocationId"))
141 .onBehalfOfCompId(settings.get("OnBehalfOfCompId"))
142 .clearingFirm(settings.get<Int32>("ClearingFirm"))
143 .clearingAccount(settings.get("ClearingAccount"))
144 .mifidId(settings.get<Int64NULL>("MifidId"))
145 .manualOrderIndicator(BooleanEnum::True)
146 .memo("CancelReplaceRequest")
147 .selfMatchPreventionInstruction(SelfMatchPreventionInstructionEnum::CancelTakingOrder);
148
149 if(settings.isSet("SelfMatchPreventionId"))
150 request->selfMatchPreventionId(settings.get<Int64>("SelfMatchPreventionId"));
151
152 return request;
153}
154
155auto initNewOrderCrossRequest(const Settings& settings)
156{
158
159 const auto onBehalfOfSubId = settings.get("OnBehalfOfSubId");
160 const auto onBehalfOfLocationId = settings.get("OnBehalfOfLocationId");
161 const auto onBehalfOfCompId = settings.get("OnBehalfOfCompId");
162 const auto clearingFirm = settings.get<Int32>("ClearingFirm");
163 const auto clearingAccount = settings.get("ClearingAccount");
164 const auto mifidId = settings.get<Int64NULL>("MifidId");
165
166 request->originatorUserId(settings.get("TraderId"));
167 request->crossType(CrossTypeEnum::IOC);
168
169 auto sides = request->sides(2);
170
171 sides[0]
172 .onBehalfOfSubId(onBehalfOfSubId)
173 .onBehalfOfLocationId(onBehalfOfLocationId)
174 .onBehalfOfCompId(onBehalfOfCompId)
175 .clearingFirm(clearingFirm)
176 .clearingAccount(clearingAccount)
177 .mifidId(mifidId)
178 .manualOrderIndicator(BooleanEnum::True)
179 .memo("NewOrderCrossRequest[0]")
180 .custOrderHandlingInst(CustOrderHandlingInstEnum::Y)
181 .selfMatchPreventionInstruction(SelfMatchPreventionInstructionEnum::CancelTakingOrder);
182
183 sides[1]
184 .onBehalfOfSubId(onBehalfOfSubId)
185 .onBehalfOfLocationId(onBehalfOfLocationId)
186 .onBehalfOfCompId(onBehalfOfCompId)
187 .clearingFirm(clearingFirm)
188 .clearingAccount(clearingAccount)
189 .mifidId(mifidId)
190 .manualOrderIndicator(BooleanEnum::True)
191 .memo("NewOrderCrossRequest[1]")
192 .custOrderHandlingInst(CustOrderHandlingInstEnum::Y)
193 .selfMatchPreventionInstruction(SelfMatchPreventionInstructionEnum::CancelTakingOrder);
194
195 if(settings.isSet("SelfMatchPreventionId"))
196 {
197 const auto id = settings.get<Int64>("SelfMatchPreventionId");
198 sides[0].selfMatchPreventionId(id);
199 sides[1].selfMatchPreventionId(id);
200 }
201
202 return request;
203}
204
205auto initOrderMassCancelRequest(const Settings& settings)
206{
208
209 request->originatorUserId(settings.get("TraderId"));
210 request->massCancelRequestType(MassCancelRequestTypeEnum::CancelAllForTrader);
211
212 return request;
213}
214
215auto initQuoteRequest(const Settings& settings)
216{
217 QuoteRequestMsg request;
218
219 request->
220 originatorUserId(settings.get("TraderId"))
221 .onBehalfOfSubId(settings.get("OnBehalfOfSubId"))
222 .onBehalfOfLocationId(settings.get("OnBehalfOfLocationId"))
223 .onBehalfOfCompId(settings.get("OnBehalfOfCompId"))
224 .clearingFirm(settings.get<Int32>("ClearingFirm"))
225 .clearingAccount(settings.get("ClearingAccount"));
226
227 return request;
228}
229
230auto initQuoteCancelRequest(const Settings& settings)
231{
232 QuoteCancelRequestMsg request;
233
234 request->originatorUserId(settings.get("TraderId"));
235 request->quoteCancelType(QuoteCancelTypeEnum::CancelByUnderlyingMarket);
236 request->quoteEntries(1);
237
238 return request;
239}
240
241auto initMassQuoteRequest(const Settings& settings)
242{
243 MassQuoteRequestMsg request;
244
245 request->
246 mifidId(settings.get<Int64NULL>("MifidId"))
247 .selfMatchPreventionInstruction(SelfMatchPreventionInstructionEnum::CancelTakingOrder)
248 .riskProtectionReset(BooleanEnum::True)
249 .directElectronicAccess(BooleanEnum::True)
250 .originatorUserId(settings.get("TraderId"))
251 ;
252
253 if(settings.isSet("SelfMatchPreventionId"))
254 request->selfMatchPreventionId(settings.get<Int64>("SelfMatchPreventionId"));
255
256 request->quoteSets(MassQuoteRequestMaxEntriesCount);
257 return request;
258}
259
260
261auto queryString(const char* name, const std::string& defaultValue)
262{
263 Screen::out("Enter ", name, " (default=", defaultValue, "): ");
264 return Screen::getInput(defaultValue);
265}
266
267auto queryTimestamp(const char* name, Timestamp defaultValue)
268{
269 Screen::out("Enter ", name, " (default=", toStr(defaultValue, TimestampFormat::YYYYMMDD), "): ");
270 const auto userInput = Screen::getInput<std::string>();
271
272 if(userInput.empty())
273 return defaultValue;
274
276}
277
278template <typename OptionalType>
279auto queryOptionalTimestamp(const char* name, OptionalType defaultValue = {})
280{
281 Screen::out("Enter ", name, ", optional, (default=", defaultValue ? toStr(*defaultValue, TimestampFormat::YYYYMMDD) : toStr(nullOpt), "): ");
282 const auto userInput = Screen::getInput<std::string>();
283
284 if(userInput.empty())
285 return defaultValue;
286
287 if(userInput == toStr(nullOpt))
288 return OptionalType{};
289
290 return OptionalType{Timestamp::fromStr(userInput, TimestampFormat::YYYYMMDD)};
291}
292
293template <typename T>
294auto queryNumeric(const char* name, T defaultValue, typename std::enable_if<std::is_integral<T>::value, void*>::type = nullptr)
295{
296 Screen::out("Enter ", name, " (default=", toStr(defaultValue), "): ");
297 return Screen::getInput<T>(defaultValue);
298}
299
300template <typename OptionalType>
301auto queryOptionalNumeric(const char* name, typename std::enable_if<isOptional<OptionalType>::value && std::is_integral<typename OptionalType::HeldType>::value, void*>::type = nullptr)
302{
303 Screen::out("Enter ", name, ", optional, (default=", toStr(nullOpt), "): ");
304
305 const auto userInput = Screen::getInput(toStr(nullOpt));
306
307 if(userInput.empty() || userInput == toStr(nullOpt))
308 return OptionalType{};
309
310 return OptionalType{parseUserInput<typename OptionalType::HeldType>(userInput)};
311}
312
313auto queryDecimal(const char* name, Decimal9 defaultValue)
314{
315 Screen::out("Enter ", name, " (default=", toStr(Decimal{defaultValue, -9}), "): ");
316 const auto userInput = Screen::getInput<std::string>();
317
318 if(userInput.empty())
319 return defaultValue;
320
321 return toPriceMantissa(parseUserInput<double>(userInput));
322}
323
324template <typename OptionalType>
325auto queryOptionalDecimal(const char* name, OptionalType defaultValue = {}, typename std::enable_if<isOptional<OptionalType>::value, void*>::type=nullptr)
326{
327 Screen::out("Enter ", name, ", optional, (default=", toStr(defaultValue), "): ");
328
329 const auto userInput = Screen::getInput(toStr(defaultValue));
330
331 if(userInput.empty())
332 return defaultValue;
333
334 if(userInput == toStr(nullOpt))
335 return OptionalType{};
336
337 return OptionalType{toPriceMantissa(parseUserInput<double>(userInput))};
338}
339
340template<typename Type, size_t Size>
341auto queryEnum(const char* name, const Type (&allowedValues)[Size], Type defaultValue, typename std::enable_if<isScopedEnum<Type>::value, void*>::type=nullptr)
342{
343 const std::set<Type> val{std::begin(allowedValues), std::end(allowedValues)};
344 Screen::out("Enter ", name, " [", join(val.begin(), val.end(), ','), "] (default=", toStr(defaultValue), "):");
345
346 const auto userInput = Screen::getInput<std::string>();
347
348 if(userInput.empty())
349 return defaultValue;
350
351 const auto value = parseUserInput<Type>(userInput);
352
353 if(val.find(value) == val.end())
354 throw std::invalid_argument("Invalid user input: '" + toStr(value) + "'");
355
356 return value;
357}
358
359template<typename OptionalType, size_t Size>
360auto queryOptionalEnum(const char* name, const typename OptionalType::HeldType (&allowedValues)[Size], OptionalType defaultValue = {}, typename std::enable_if<isOptional<OptionalType>::value && isScopedEnum<typename OptionalType::HeldType>::value, void*>::type=nullptr)
361{
362 const std::set<typename OptionalType::HeldType> val{std::begin(allowedValues), std::end(allowedValues)};
363 Screen::out("Enter ", name, " [", join(val.begin(), val.end(), ','), "], optional, (default=", toStr(nullOpt), "):");
364
365 const auto userInput = Screen::getInput<std::string>();
366
367 if(userInput.empty())
368 return defaultValue;
369
370 if(userInput == toStr(nullOpt))
371 return OptionalType{};
372
373 const auto value = parseUserInput<typename OptionalType::HeldType>(userInput);
374
375 return OptionalType{value};
376}
377
378template<size_t Size>
379auto querySide(const SideEnum (&allowedValues)[Size], SideEnum defaultValue = Default::Side)
380{
381 return queryEnum("Side", allowedValues, defaultValue);
382}
383
384template<typename OptionalType, size_t Size>
385auto querySideOptional(const SideEnum (&allowedValues)[Size])
386{
387 return queryOptionalEnum<OptionalType>("Side", allowedValues);
388}
389
390template<size_t Size>
391auto queryOrderType(const OrderTypeEnum (&allowedValues)[Size], OrderTypeEnum defaultValue = OrderTypeEnum::Limit)
392{
393 return queryEnum("OrderType", allowedValues, defaultValue);
394}
395
396template<typename OptionalType, size_t Size>
397auto queryOrderTypeOptional(const typename OptionalType::HeldType (&allowedValues)[Size])
398{
399 return queryOptionalEnum<OptionalType, Size>("OrderType", allowedValues);
400}
401
402template<size_t Size>
403auto queryTimeInForce(const TimeInForceEnum (&allowedValues)[Size], TimeInForceEnum defaultValue = TimeInForceEnum::Day)
404{
405 return queryEnum("TimeInForce", allowedValues, defaultValue);
406}
407
408template<typename OptionalType, size_t Size>
409auto queryTimeInForceOptional(const TimeInForceEnum (&allowedValues)[Size])
410{
411 return queryOptionalEnum<OptionalType, Size>("TimeInForce", allowedValues);
412}
413
414template<size_t Size>
415auto querySecurityRequestType(const SecurityRequestTypeEnum (&allowedValues)[Size], SecurityRequestTypeEnum defaultValue = SecurityRequestTypeEnum::RequestListofOptions)
416{
417 return queryEnum("SecurityRequestType", allowedValues, defaultValue);
418}
419
420template<typename OptionalType, size_t Size>
421auto queryPriceTypeOptional(const typename OptionalType::HeldType (&allowedValues)[Size])
422{
423 return queryOptionalEnum<OptionalType, Size>("PriceType", allowedValues);
424}
425
426template<typename OptionalType, size_t Size>
427auto queryBenchmarkPriceTypeOptional(const typename OptionalType::HeldType (&allowedValues)[Size])
428{
429 return queryOptionalEnum<OptionalType, Size>("BenchmarkPriceType", allowedValues);
430}
431
432template<typename OptionalType, size_t Size>
433auto queryExecInstOptional(const typename OptionalType::HeldType (&allowedValues)[Size], OptionalType defaultValue)
434{
435 return queryOptionalEnum<OptionalType, Size>("ExecInst", allowedValues, defaultValue);
436}
437
438template<typename OptionalType, size_t Size>
439auto queryBooleanOptional(const char* name, const BooleanEnum (&allowedValues)[Size])
440{
441 return queryOptionalEnum<OptionalType>(name, allowedValues);
442}
443
444template<size_t Size>
445auto queryCustOrderHandlingInst(const CustOrderHandlingInstEnum (&allowedValues)[Size], CustOrderHandlingInstEnum defaultValue = CustOrderHandlingInstEnum::Y)
446{
447 return queryEnum("CustOrderHandlingInst", allowedValues, defaultValue);
448}
449
450struct QuoteIdGenerator
451{
452 static Int64 id()
453 {
455 }
456};
457
458}
459
460void TradingClient::checkConnected(const SessionPtr& sn, const char* kind)
461{
462 const bool connected = sn && sn->state() == SessionStateId::Established;
463
464 if(!connected)
465 throw std::runtime_error("A " + std::string(kind) + " session must be in the [Established] state");
466}
467
469 : settings_(settings)
470 , sessionSettings_(fillSessionSettings(settings_))
471 , newOrderRequest_(initNewOrder(settings))
472 , securityDefinitionRequest_(initSecurityDefinitionRequest(settings))
473 , cancelRequest_(initOrderCancelRequest(settings))
474 , replaceRequest_(initOrderReplaceRequest(settings))
475 , newOrderCrossRequest_(initNewOrderCrossRequest(settings))
476 , orderMassCancelRequest_(initOrderMassCancelRequest(settings))
477 , quoteRequest_(initQuoteRequest(settings))
478 , quoteCancelRequest_(initQuoteCancelRequest(settings))
479 , massQuoteRequest_(initMassQuoteRequest(settings))
480{
481}
482
483OptionalRef<Order> TradingClient::findByOrderId(OrderId orderId)
484{
485 auto ord = orderBook_.find(orderId);
486
487 if (!ord)
488 CUI::Screen::warning("No order with id=", orderId, " is found");
489
490 return ord;
491}
492
494{
495 auto settings = sessionSettings_;
496
497 if(!busSession_)
498 busSession_.reset(new Session(SessionType::BUS, settings, this));
499
500 busSession_->connect(settings_.get("Host"), settings_.get<Port>("Port"));
501}
502
504{
505 checkConnected(busSession_, "BUS");
506
507 const auto userId = settings_.get("UserId");
508
510 request->clientId(sessionSettings_.clientId());
511 request->users(1)[0].userId(userId);
512
513 bgwCredentials_ = {};
514 TradingClient::send(busSession_, request);
515}
516
518{
519 checkConnected(busSession_, "BUS");
520
521 const auto marketTypeId = queryNumeric("MarketTypeId", Default::MarketTypeId);
522 const auto requestType = querySecurityRequestType(
523 {SecurityRequestTypeEnum::RequestListofOptions,
524 SecurityRequestTypeEnum::RequestListofStrategies,
525 SecurityRequestTypeEnum::RequestListofFutures,
526 SecurityRequestTypeEnum::RequestListOfProducts
527 });
528
530 request->marketTypeId(marketTypeId);
531 request->securityReqId(static_cast<Int32>(IdGenerator::newId() & 0xFFFFFFFFull));
532 request->securityRequestType(requestType);
533
534 instruments_.clear();
535 send(busSession_, request);
536}
537
539{
540 std::vector<Messaging::SbeMessage> messages;
541
542 for (auto element : instruments_)
543 messages.push_back(Messaging::SbeMessage{element->data(), static_cast<Messaging::SbeMessage::EncodedLength>(element->size())});
544
545 std::reverse(messages.begin(), messages.end());
546
547 ListViewer::outputItems(messages, [](auto msg)
548 {
549 std::string res;
550
551 if(!ONIXS_ICEBOE_MESSAGING_NAMESPACE::processTypified(msg, [&](const auto msg) { toStr(res, msg); }))
552 res = "[]";
553
554 return res;
555 }, 10);
556}
557
559{
560 const auto symbol = queryNumeric("Symbol", Default::Symbol);
561
562 std::vector<Messaging::SecurityDefinitionReport> messages;
563
564 for (auto element : instruments_)
565 {
566 const Messaging::SecurityDefinitionReport msg{element->data(), static_cast<Messaging::SbeMessage::EncodedLength>(element->size())};
567
568 if(msg.symbol() == symbol)
569 messages.push_back(msg);
570 }
571
572 ListViewer::outputItems(messages, [](auto msg){return toStr(msg);}, 10);
573}
574
576{
577 if(!bgwCredentials_)
578 throw std::runtime_error("BGW credentials must be obtained first");
579
580 auto settings = sessionSettings_;
581
582 if(!bgwSession_)
583 bgwSession_.reset(new Session(SessionType::BGW, settings, this));
584
585 bgwSession_->connect(bgwCredentials_.host(), bgwCredentials_.port(), bgwCredentials_.ipSessionToken());
586}
587
589{
590 checkConnected(bgwSession_, "BGW");
591
593 request->originatorUserId(settings_.get("TraderId"));
594 request->rawData(settings_.get("TraderPwd"));
595 request->directElectronicAccess(BooleanEnum::True);
596 request->tradingCapacity(TradingCapacityEnum::DEAL);
597 request->liquidityProvision(BooleanEnum::True);
598 request->commodityDerivIndicator(BooleanEnum::False);
599 request->investmentDecision(settings_.get<Int64>("InvestmentDecision"));
600 request->executionDecision(settings_.get<Int64>("ExecutionDecision"));
601
602 TradingClient::send(bgwSession_, request);
603}
604
606{
607 checkConnected(bgwSession_, "BGW");
608
610 request->originatorUserId(settings_.get("TraderId"));
611
612 TradingClient::send(bgwSession_, request);
613}
614
616{
617 checkConnected(bgwSession_, "BGW");
618
619 const auto order = orderBook_.store(newOrder());
620 Screen::info(order.toString());
621
622 newOrderRequest_->price(order.price_.raw())
623 .orderQty(order.orderQty_)
624 .symbol(order.securityId_)
625 .clOrdId(order.cIOrdId_)
626 .stopPx(order.stopPx_.raw())
627 .ordType(order.ordType_)
628 .timeInForce(order.timeInForce_)
629 .side(order.side_)
630 .maxShow(order.maxShow_.raw())
631 .execInst(order.execInst_.raw())
632 ;
633
634 if (order.timeInForce_ == TimeInForceEnum::GTD && order.expireDate_)
635 newOrderRequest_->expireDate(*order.expireDate_);
636 else
637 newOrderRequest_->expireDate(nullOpt);
638
639 const auto custOrderHandlingInst =
640 queryCustOrderHandlingInst({
641 CustOrderHandlingInstEnum::C
642 ,CustOrderHandlingInstEnum::D
643 ,CustOrderHandlingInstEnum::G
644 ,CustOrderHandlingInstEnum::H
645 ,CustOrderHandlingInstEnum::W
646 ,CustOrderHandlingInstEnum::Y
647 });
648
649 newOrderRequest_->custOrderHandlingInst(custOrderHandlingInst);
650
651 const auto selfMatchPreventionInstruction =
652 queryOptionalEnum<decltype(std::declval<const NewOrderRequest&>().selfMatchPreventionInstruction())>(
653 "SelfMatchPreventionInstruction",
654 {
655 SelfMatchPreventionInstructionEnum::CancelRestingOrder
656 ,SelfMatchPreventionInstructionEnum::CancelTakingOrder
657 ,SelfMatchPreventionInstructionEnum::CancelBothOrders
658 });
659
660 newOrderRequest_->selfMatchPreventionInstruction(selfMatchPreventionInstruction.raw());
661
662 TradingClient::send(bgwSession_, newOrderRequest_);
663}
664
666{
667 checkConnected(bgwSession_, "BGW");
668
669 const auto transactDetails = queryString("TransactDetails", "***");
670
671 const auto priceType =
672 queryPriceTypeOptional<decltype(std::declval<const NewOrderCrossRequest&>().priceType())>({
673 PriceTypeEnum::PerContract,
674 PriceTypeEnum::FixedCabinetTradePrice,
675 PriceTypeEnum::FixedRate,
676 PriceTypeEnum::NPV,
677 PriceTypeEnum::RateDifferential,
678 PriceTypeEnum::NPVDifferential});
679
680 const auto benchmarkPriceType =
681 queryBenchmarkPriceTypeOptional<decltype(std::declval<const NewOrderCrossRequest&>().benchMarkPriceType())>({
682 BenchmarkPriceTypeEnum::FixedAmount});
683
684 const auto bmPrice =
685 queryOptionalDecimal<decltype(std::declval<const NewOrderCrossRequest&>().benchmarkPrice())>("BenchmarkPrice");
686
687 const auto crossType = queryEnum("CrossType", {CrossTypeEnum::AON, CrossTypeEnum::IOC}, CrossTypeEnum::AON);
688
689 const auto custOrderHandlingInst =
690 queryCustOrderHandlingInst({
691 CustOrderHandlingInstEnum::C
692 ,CustOrderHandlingInstEnum::D
693 ,CustOrderHandlingInstEnum::G
694 ,CustOrderHandlingInstEnum::H
695 ,CustOrderHandlingInstEnum::W
696 ,CustOrderHandlingInstEnum::Y
697 });
698
699 newOrderCrossRequest_->priceType(priceType.raw());
700 newOrderCrossRequest_->benchMarkPriceType(benchmarkPriceType.raw());
701 newOrderCrossRequest_->benchmarkPrice(bmPrice.raw());
702 newOrderCrossRequest_->transactDetails(toStrRef(transactDetails));
703 newOrderCrossRequest_->crossType(crossType);
704
705 auto crossOrder = orderBook_.store(newOrderCross());
706
707 Screen::info(crossOrder.toString());
708
709 const auto& buySideOrder = *crossOrder.buySideOrder_;
710 const auto& sellSideOrder = *crossOrder.sellSideOrder_;
711
712 auto sides = newOrderCrossRequest_->sides();
713 assert(sides.size() == 2);
714
715 newOrderCrossRequest_->crossId(crossOrder.id());
716
717 newOrderCrossRequest_->price(buySideOrder.price_.raw())
718 .orderQty(buySideOrder.orderQty_)
719 .symbol(buySideOrder.securityId_)
720 .ordType(buySideOrder.ordType_)
721 .timeInForce(buySideOrder.timeInForce_);
722
723 sides[0].side(buySideOrder.side_);
724 sides[0].clOrdId(buySideOrder.cIOrdId_);
725 sides[0].custOrderHandlingInst(custOrderHandlingInst);
726
727 sides[1].side(sellSideOrder.side_);
728 sides[1].clOrdId(sellSideOrder.cIOrdId_);
729 sides[1].custOrderHandlingInst(custOrderHandlingInst);
730
731 newOrderCrossRequest_->transactTime(UtcWatch::now());
732
733 TradingClient::send(bgwSession_, newOrderCrossRequest_);
734}
735
737{
738 checkConnected(bgwSession_, "BGW");
739
740 orderMassCancelRequest_->clOrdId(IdGenerator::newId());
741
742 const auto requestType = queryEnum(
743 "RequestType", {MassCancelRequestTypeEnum::CancelAllForTrader, MassCancelRequestTypeEnum::CancelForTradingSession}, MassCancelRequestTypeEnum::CancelAllForTrader);
744
745 const auto ordType = queryOrderTypeOptional<decltype(std::declval<const OrderMassCancelRequest&>().ordType())>(
746 {OrderTypeEnum::Limit});
747
748 const auto side = querySideOptional<decltype(std::declval<const OrderMassCancelRequest&>().side())>(
749 {SideEnum::Buy, SideEnum::Sell});
750
751 const auto symbol = queryOptionalNumeric<decltype(std::declval<const OrderMassCancelRequest&>().symbol())>("Symbol");
752
753 const auto marketTypeId = queryOptionalNumeric<decltype(std::declval<const OrderMassCancelRequest&>().marketTypeId())>("MarketTypeId");
754
755 const auto price = queryOptionalDecimal<decltype(std::declval<const OrderMassCancelRequest&>().price())>("Price");
756
757 const auto timeInForce = queryTimeInForceOptional<decltype(std::declval<const OrderMassCancelRequest&>().timeInForce())>({TimeInForceEnum::Day});
758
759 const auto onBehalfOfSubId = queryString("OnBehalfOfSubId", "");
760
761 orderMassCancelRequest_->massCancelRequestType(requestType);
762 orderMassCancelRequest_->ordType(ordType.raw());
763 orderMassCancelRequest_->side(side.raw());
764 orderMassCancelRequest_->symbol(symbol.raw());
765 orderMassCancelRequest_->marketTypeId(marketTypeId.raw());
766 orderMassCancelRequest_->price(price.raw());
767 orderMassCancelRequest_->timeInForce(timeInForce.raw());
768 orderMassCancelRequest_->onBehalfOfSubId(toStrRef(onBehalfOfSubId));
769
770 TradingClient::send(bgwSession_, orderMassCancelRequest_);
771}
772
774{
775 checkConnected(bgwSession_, "BGW");
776
777 const auto qti = queryDecimal("Quantity", Default::QuantityMantissa);
778 const auto side = querySide({SideEnum::Buy, SideEnum::Sell});
779 const auto symbol = queryNumeric("Symbol", Default::Symbol);
780
781 quoteRequest_
782 ->rfqReqId(IdGenerator::newId())
783 .orderQty(qti)
784 .side(side)
785 .symbol(symbol);
786
787 TradingClient::send(bgwSession_, quoteRequest_);
788}
789
790Int32 TradingClient::getQuoteSetId(Int32 underlyingSymbol)
791{
792 for(auto&& pair : quoteSetId_)
793 {
794 if(pair.second == underlyingSymbol)
795 return pair.first;
796 }
797
798 quoteSetId_.emplace_back(static_cast<Int32>(quoteSetId_.size() + 1), underlyingSymbol);
799 return quoteSetId_.back().first;
800}
801
803{
804 checkConnected(bgwSession_, "BGW");
805
806 massQuoteRequest_->quoteId(QuoteIdGenerator::id());
807
808 const auto riskProtectionReset =
809 queryBooleanOptional<decltype(std::declval<const MassQuoteRequest&>().riskProtectionReset())>(
810 "RiskProtectionReset", {BooleanEnum::False, BooleanEnum::True});
811
812 massQuoteRequest_->riskProtectionReset(riskProtectionReset.raw());
813
814 const auto quotes = massQuoteRequest_->quoteSets();
815
816 for(auto&& quote : quotes)
817 {
818 const auto underlyingSymbol = queryNumeric("Underlying Symbol", Default::UnderlyingSymbol);
819
820 quote
821 .quoteEntryId(static_cast<Int32>(IdGenerator::newId()))
822 .underlyingSymbol(underlyingSymbol)
823 .quoteSetId(getQuoteSetId(underlyingSymbol))
824 .symbol(queryNumeric("Symbol", Default::Symbol))
825 .bidPx(queryDecimal("Bid Price", Default::PriceMantissa))
826 .bidSz(queryDecimal("Bid Size", Default::QuantityMantissa))
827 .offerPx(queryDecimal("Offer Price", Default::PriceMantissa))
828 .offerSz(queryDecimal("Offer Size", Default::QuantityMantissa))
829 ;
830 }
831
832 TradingClient::send(bgwSession_, massQuoteRequest_);
833}
834
836{
837 checkConnected(bgwSession_, "BGW");
838
839 quoteCancelRequest_->quoteId(QuoteIdGenerator::id());
840 assert(quoteCancelRequest_->quoteEntries().size() == 1);
841
842 const auto quoteCancelType = queryEnum("QuoteCancelType",
843 { QuoteCancelTypeEnum::CancelAll, QuoteCancelTypeEnum::CancelByProductID, QuoteCancelTypeEnum::CancelByUnderlyingMarket},
844 QuoteCancelTypeEnum::CancelByUnderlyingMarket);
845
846 quoteCancelRequest_->quoteCancelType(quoteCancelType);
847
848 auto entry = quoteCancelRequest_->quoteEntries()[0];
849
850 using OptSymbol = decltype(std::declval<const QuoteCancelRequest::QuoteEntry&>().underlyingSymbol());
851 const auto underlyingSymbol = queryOptionalNumeric<OptSymbol>("UnderlyingSymbol");
852
853 using OptSecId = decltype(std::declval<const QuoteCancelRequest::QuoteEntry&>().underlyingSecurityId());
854 const auto secId = queryOptionalNumeric<OptSecId>("SecurityId");
855
856 using OptProduct = decltype(std::declval<const QuoteCancelRequest::QuoteEntry&>().underlyingProduct());
857 const auto product = queryOptionalNumeric<OptProduct>("Product");
858
859 entry.underlyingSymbol(underlyingSymbol.raw());
860 entry.underlyingSecurityId(secId.raw());
861 entry.underlyingProduct(product.raw());
862
863 TradingClient::send(bgwSession_, quoteCancelRequest_);
864}
865
867{
868 checkConnected(bgwSession_, "BGW");
869
870 constexpr size_t CreateStrategyMaxLegsCount = 5;
871
875
876 msg->marketTypeId(queryNumeric("MarketTypeId", Default::MarketTypeId));
877 msg->securityReqId(static_cast<Int32>(IdGenerator::newId() & 0xFFFFFFFFull));
878 msg->securityRequestType(SecurityRequestTypeEnum::CreateStrategy);
879 msg->securityType(SecurityTypeEnum::MLEG);
880
881 using OptionalDate = decltype(std::declval<const SecurityDefinitionRequest_CreateStrategy&>().startDate());
882 const auto startDate = queryOptionalTimestamp<OptionalDate>("StartDate");
883 const auto endDate = queryOptionalTimestamp<OptionalDate>("EndDate");
884
885 if(startDate)
886 msg->startDate(*startDate);
887 else
888 msg->startDate(nullOpt);
889
890 if(endDate)
891 msg->endDate(*endDate);
892 else
893 msg->endDate(nullOpt);
894
895 const auto legsCount = queryNumeric("Number of Legs", UInt32{2});
896
897 assert(legsCount <= CreateStrategyMaxLegsCount);
898
899 assert(std::distance(std::begin(Default::Symbols), std::end(Default::Symbols)) >= legsCount);
900 auto defaultSymbol = std::begin(Default::Symbols);
901
902 auto legs = msg->legs(legsCount);
903
904 for(auto&& leg : legs)
905 {
906 leg.legSecurityType(SecurityTypeEnum::OPT);
907
908 leg.legSymbol(queryNumeric("Symbol", *defaultSymbol));
909
910 const auto side = querySide({SideEnum::Buy, SideEnum::Sell});
911 leg.legSide(side);
912
913 using OptDenominator = decltype(std::declval<const std::decay<decltype(leg)>::type>().legRatioQtyDenominator());
914 const auto denominator = queryOptionalNumeric<OptDenominator>("LegRatioQtyDenominator");
915
916 using OptNuminator = decltype(std::declval<const std::decay<decltype(leg)>::type>().legRatioQtyNumerator());
917 const auto numerator = queryOptionalNumeric<OptNuminator>("LegRatioQtyNumerator");
918
919 leg.legRatioQtyDenominator(denominator.raw());
920 leg.legRatioQtyNumerator(numerator.raw());
921
922 ++defaultSymbol;
923 }
924
925 TradingClient::send(bgwSession_, msg);
926}
927
929{
930 checkConnected(bgwSession_, "BGW");
931
933 msg->securityRequestType(SecurityRequestTypeEnum::CreateFlexOption);
934 msg->securityReqId(static_cast<Int32>(IdGenerator::newId()));
935
936 const auto marketTypeId = queryNumeric("MarketTypeId", Default::MarketTypeId);
937 const auto type = queryEnum("SecurityType", {SecurityTypeEnum::OPT, SecurityTypeEnum::FUT, SecurityTypeEnum::MLEG}, SecurityTypeEnum::OPT);
938
939 using OptionalDate = decltype(std::declval<const SecurityDefinitionRequest_CreateFlex&>().maturityDate());
940 const auto maturityDate = queryOptionalTimestamp<OptionalDate>("MaturityDate");
941
942 using OptionalProductId = decltype(std::declval<const SecurityDefinitionRequest_CreateFlex&>().productId());
943 const auto productId = queryOptionalNumeric<OptionalProductId>("ProductId");
944
945 using OptionalSymbol = decltype(std::declval<const SecurityDefinitionRequest_CreateFlex&>().symbol());
946 const auto symbol = queryOptionalNumeric<OptionalSymbol>("Symbol");
947
948 using OptionalPrice = decltype(std::declval<const SecurityDefinitionRequest_CreateFlex&>().strikePrice());
949 const auto price = queryOptionalDecimal<OptionalPrice>("StrikePrice");
950
951 msg->securityType(type);
952 msg->marketTypeId(marketTypeId);
953 msg->productId(productId.raw());
954 msg->symbol(symbol.raw());
955 msg->strikePrice(price.raw());
956
957 if(maturityDate)
958 msg->maturityDate(*maturityDate);
959 else
960 msg->maturityDate(nullOpt);
961
962 TradingClient::send(bgwSession_, msg);
963}
964
965CrossOrderPtr TradingClient::newOrderCross()
966{
967 auto crossOrder = std::make_shared<CrossOrder>();
968
969 Order& buySideOrder = *crossOrder->buySideOrder_;
970 Order& sellSideOrder = *crossOrder->sellSideOrder_;
971
972 const auto symbol = queryNumeric("Symbol", Default::Symbol);
973 buySideOrder.securityId_ = symbol;
974 sellSideOrder.securityId_ = symbol;
975
976 const auto ordType = queryOrderType({OrderTypeEnum::Market, OrderTypeEnum::Limit}, OrderTypeEnum::Limit);
977
978 buySideOrder.ordType_ = ordType;
979 sellSideOrder.ordType_ = ordType;
980
981 if (ordType == OrderTypeEnum::Limit)
982 {
983 const auto price = queryDecimal("Price", 64570000);
984 buySideOrder.price_ = price;
985 sellSideOrder.price_ = price;
986 }
987
988 const auto qti = queryDecimal("Quantity", Default::QuantityMantissa);
989 buySideOrder.orderQty_ = qti;
990 buySideOrder.leavesQty_ = buySideOrder.orderQty_;
991 sellSideOrder.orderQty_ = qti;
992 sellSideOrder.leavesQty_ = sellSideOrder.orderQty_;
993
994 buySideOrder.timeInForce_ = TimeInForceEnum::FAK;
995 sellSideOrder.timeInForce_ = TimeInForceEnum::FAK;
996
997 buySideOrder.side_ = SideEnum::Buy;
998 sellSideOrder.side_ = SideEnum::Sell;
999
1000 return crossOrder;
1001}
1002
1003OrderPtr TradingClient::newOrder(const Order* base)
1004{
1005 OrderPtr result = std::make_shared<Order>();
1006 auto& order = *result;
1007
1008 order.securityId_ = queryNumeric("Symbol", base ? base->securityId_ : Default::Symbol);
1009
1010 order.ordType_ = queryOrderType(
1011 {OrderTypeEnum::Market, OrderTypeEnum::Limit, OrderTypeEnum::Stop, OrderTypeEnum::StopLimit},
1012 base ? base->ordType_ : OrderTypeEnum::Limit);
1013
1014 if (order.ordType_ == OrderTypeEnum::Limit || order.ordType_ == OrderTypeEnum::StopLimit)
1015 order.price_ = queryDecimal("Price", Default::PriceMantissa);
1016
1017 if (order.ordType_ == OrderTypeEnum::StopLimit || order.ordType_ == OrderTypeEnum::Stop)
1018 order.stopPx_ = queryDecimal("StopPx", Default::PriceMantissa);
1019
1020 order.orderQty_ = queryDecimal("Quantity", Default::QuantityMantissa);
1021 order.leavesQty_ = order.orderQty_;
1022
1023 order.timeInForce_ = queryTimeInForce(
1024 {TimeInForceEnum::Day, TimeInForceEnum::GTC, TimeInForceEnum::FAK, TimeInForceEnum::FOK, TimeInForceEnum::GTD},
1025 base ? base->timeInForce_ : TimeInForceEnum::Day );
1026
1027 if (order.timeInForce_ == TimeInForceEnum::GTD)
1028 order.expireDate_ = queryTimestamp("ExpireDate", (base && base->expireDate_) ? *base->expireDate_ : Default::Timestamp);
1029
1030 order.side_ = querySide({SideEnum::Buy, SideEnum::Sell}, base ? base->side_ : SideEnum::Buy);
1031
1032 order.execInst_ = queryExecInstOptional({ExecInstEnum::AON}, base ? base->execInst_ : Order::ExecInstOptional{nullOpt});
1033
1034 const auto maxShow =
1035 queryOptionalDecimal("MaxShow", base ? base->maxShow_ : Order::QtiOptional{nullOpt});
1036
1037 if(maxShow != nullOpt)
1038 {
1039 if(*maxShow > order.orderQty_)
1040 throw std::logic_error("Invalid `MaxShow` for order");
1041
1042 order.maxShow_ = *maxShow;
1043 }
1044
1045 return result;
1046}
1047
1049{
1050 ListViewer::outputItems(orderBook_.getEntries(), print, 10);
1051}
1052
1053bool activeOrder(const Order& order) noexcept
1054{
1055 return order.orderStatus_ == ExecTypeEnum::New || order.orderStatus_ == ExecTypeEnum::PartialFill || order.orderStatus_ == ExecTypeEnum::Replaced;
1056}
1057
1059{
1060 ListViewer::outputItems(orderBook_.getEntries(activeOrder), print, 10);
1061}
1062
1064{
1065 checkConnected(bgwSession_, "BGW");
1066
1067 const auto ordersInBook = orderBook_.getEntries(activeOrder);
1068
1069 if (ordersInBook.empty())
1070 {
1071 Screen::warning("No active orders found");
1072 return;
1073 }
1074
1075 ListViewer::outputItems(ordersInBook, print);
1076
1077 Screen::out("Enter the index of the order to be canceled");
1078
1079 const auto orderIndex = Screen::getInput<size_t>();
1080 const Order& order = *ordersInBook.at(orderIndex - 1);
1081
1082 cancelRequest_->
1083 clOrdId(IdGenerator::newId())
1084 .origClOrdId(order.cIOrdId_)
1085 .symbol(order.securityId_)
1086 .side(order.side_)
1087 ;
1088
1089 TradingClient::send(bgwSession_, cancelRequest_);
1090}
1091
1093{
1094 checkConnected(bgwSession_, "BGW");
1095
1096 const auto ordersInBook = orderBook_.getEntries(activeOrder);
1097
1098 if (ordersInBook.empty())
1099 {
1100 Screen::warning("No active orders found");
1101 return;
1102 }
1103
1104 ListViewer::outputItems(ordersInBook, print);
1105
1106 Screen::out("Enter the index of the order to be replaced");
1107
1108 const auto orderIndex = Screen::getInput<size_t>();
1109 const auto order = ordersInBook.at(orderIndex - 1);
1110
1111 auto replaceOrder = orderBook_.store(newOrder(order.get()));
1112 replaceOrder.origCIOrdId_ = order->cIOrdId_;
1113
1114 Screen::info(replaceOrder.toString());
1115
1116 replaceRequest_->price(replaceOrder.price_.raw())
1117 .orderQty(replaceOrder.orderQty_)
1118 .symbol(replaceOrder.securityId_)
1119 .clOrdId(replaceOrder.cIOrdId_)
1120 .stopPx(replaceOrder.stopPx_.raw())
1121 .ordType(replaceOrder.ordType_)
1122 .timeInForce(replaceOrder.timeInForce_)
1123 .side(replaceOrder.side_)
1124 .origClOrdId(replaceOrder.origCIOrdId_)
1125 .maxShow(replaceOrder.maxShow_.raw());
1126
1127 if (replaceOrder.timeInForce_ == TimeInForceEnum::GTD && replaceOrder.expireDate_)
1128 replaceRequest_->expireDate(*replaceOrder.expireDate_);
1129 else
1130 replaceRequest_->expireDate(nullOpt);
1131
1132 TradingClient::send(bgwSession_, replaceRequest_);
1133}
1134
1135void TradingClient::onNewOrderCrossReport(const Messaging::NewOrderCrossReport msg, Session* sn)
1136{
1138
1139 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1140 return;
1141
1142 const auto status = msg.rfcStatus();
1143 if(status == RFCStatusEnum::None || status == RFCStatusEnum::Success)
1144 return;
1145
1146 const auto crossId = msg.crossId();
1147 auto crossOrder = orderBook_.findCross(crossId);
1148
1149 if (!crossOrder)
1150 {
1151 CUI::Screen::warning("No cross with id=", crossId, " is found");
1152 return;
1153 }
1154
1155 auto& buySideOrder = *(crossOrder->get()->buySideOrder_);
1156 auto& sellSideOrder = *(crossOrder->get()->sellSideOrder_);
1157
1158 if(status == RFCStatusEnum::PartialSuccessBidFailure || status == RFCStatusEnum::Failure)
1159 {
1160 buySideOrder.orderStatus_ = ExecTypeEnum::Rejected;
1161 Screen::info("Order changed: " + buySideOrder.toString());
1162 }
1163
1164 if(status == RFCStatusEnum::PartialSuccessOfferFailure || status == RFCStatusEnum::Failure)
1165 {
1166 sellSideOrder.orderStatus_ = ExecTypeEnum::Rejected;
1167 Screen::info("Order changed: " + sellSideOrder.toString());
1168 }
1169}
1170
1171void TradingClient::onExecutionReport_New(const Messaging::ExecutionReport_New msg, Session* sn)
1172{
1174
1175 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1176 return;
1177
1178 if(auto order = findByOrderId(msg.clOrdId()))
1179 {
1180 setOrdStatus(**order, msg, ExecTypeEnum::New);
1181 setCommonMessageFields(**order, msg);
1182
1183 Screen::info("Order changed: " + order->get()->toString());
1184 }
1185}
1186
1187void TradingClient::onExecutionReport_Reject(const Messaging::ExecutionReport_Reject msg, Session* sn)
1188{
1190
1191 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1192 return;
1193
1194 if(msg.rejectResponseTo() == RejectResponseToEnum::NewOrder)
1195 {
1196 if(auto order = findByOrderId(msg.clOrdId()))
1197 {
1198 setOrdStatus(**order, msg, ExecTypeEnum::Rejected);
1199 setCommonMessageFields(**order, msg);
1200
1201 Screen::info("Order changed: " + order->get()->toString());
1202 }
1203 }
1204}
1205
1206void TradingClient::onExecutionReport_Cancel(const Messaging::ExecutionReport_Cancel msg, Session* sn)
1207{
1209
1210 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1211 return;
1212
1213 const auto origClOrdId = msg.origClOrdId();
1214
1215 if(origClOrdId != nullOpt)
1216 {
1217 if(auto order = findByOrderId(*origClOrdId))
1218 {
1219 setOrdStatus(**order, msg, ExecTypeEnum::Cancelled);
1220 setCommonMessageFields(**order, msg);
1221
1222 Screen::info("Order changed: " + order->get()->toString());
1223 }
1224 }
1225}
1226
1227void TradingClient::onExecutionReport_Modify(const Messaging::ExecutionReport_Modify msg, Session* sn)
1228{
1230
1231 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1232 return;
1233
1234 auto newOrder = findByOrderId(msg.clOrdId());
1235
1236 const auto origClOrdId = msg.origClOrdId();
1237 auto oldOrder = origClOrdId ? findByOrderId(*origClOrdId) : decltype(findByOrderId(*origClOrdId)){};
1238
1239 if(newOrder)
1240 {
1241 setOrdStatus(**newOrder, msg, ExecTypeEnum::New);
1242 setCommonMessageFields(**newOrder, msg);
1243
1244 if(oldOrder)
1245 newOrder->get()->origCIOrdId_ = oldOrder->get()->cIOrdId_;
1246
1247 Screen::info("Order changed: " + newOrder->get()->toString());
1248 }
1249
1250 if(oldOrder)
1251 oldOrder->get()->orderStatus_ = ExecTypeEnum::Replaced;
1252}
1253
1254void TradingClient::onExecutionReport_Trade(const Messaging::ExecutionReport_Trade msg, Session* sn)
1255{
1257
1258 if(hasFlag(msg.headerFlags(), HeaderFlags::PossDupe | HeaderFlags::PossResend))
1259 return;
1260
1261 if(auto order = findByOrderId(msg.clOrdId()))
1262 {
1263 setOrdStatus(**order, msg, msg.leavesQty() > 0 ? ExecTypeEnum::PartialFill : ExecTypeEnum::Fill);
1264
1265 setCommonMessageFields(**order, msg);
1266 order->get()->lastPx_ = msg.lastPx();
1267
1268 Screen::info("Order changed: " + order->get()->toString());
1269 }
1270}
1271
1272void TradingClient::onExecutionReport_Snapshot(const Messaging::ExecutionReport_Snapshot msg, Session* sn)
1273{
1275
1276 std::shared_ptr<Order> order;
1277 auto found = findByOrderId(msg.clOrdId());
1278
1279 if(found)
1280 order = *found;
1281 else
1282 order = std::make_shared<Order>();
1283
1284 const auto status = msg.orderStatus();
1285
1286 if(status != nullOpt && (*status == OrderStatusEnum::New || *status == OrderStatusEnum::PartialFill))
1287 {
1288 if(*status == OrderStatusEnum::New)
1289 order->orderStatus_ = ExecTypeEnum::New;
1290 else if(*status == OrderStatusEnum::PartialFill)
1291 order->orderStatus_ = ExecTypeEnum::PartialFill;
1292
1293 order->cIOrdId_ = msg.clOrdId();
1294 order->price_ = msg.price();
1295 order->orderQty_ = msg.leavesQty();
1296 order->leavesQty_ = msg.leavesQty();
1297 order->securityId_ = msg.symbol();
1298 order->side_ = msg.side();
1299 order->ordType_ = msg.ordType();
1300 order->stopPx_ = msg.stopPx();
1301 order->timeInForce_ = msg.timeInForce();
1302 order->expireDate_ = msg.expireDate();
1303 order->transactTime_ = msg.execId().transactTime();
1304 order->maxShow_ = msg.maxShow();
1305 order->execInst_ = msg.execInst();
1306 order->origCIOrdId_ = msg.clOrdId();
1307
1308 if(!found)
1309 orderBook_.store(order);
1310 }
1311}
1312
1313void TradingClient::onIPReport(const Messaging::IPReport msg, Session* sn)
1314{
1316
1317 try
1318 {
1319 const auto users = msg.users();
1320
1321 if(users.empty())
1322 throw std::runtime_error("'IPReport' message does not contain connectivity information.");
1323
1324 Messaging::IPReport::UsersEntry entry = users[0];
1325
1326 if (!(entry.success() && *entry.success() == Messaging::BooleanEnum::True))
1327 throw std::runtime_error("IPReport::UsersEntry is invalid: success flag is missing or not set to True.");
1328
1329 if (!entry.ipAddress() || !entry.port() || !entry.ipSessionToken())
1330 throw std::runtime_error("Invalid 'IPReport::UsersEntry'");
1331
1332 auto credentials = BgwCredentials(Messaging::toStr(*entry.ipAddress()), *entry.port(), Messaging::toStr(*entry.ipSessionToken()));
1333
1334 bgwCredentials_ = credentials;
1335 }
1336 catch(std::exception& e)
1337 {
1338 Screen::error(e.what());
1339 }
1340}
1341
1342void TradingClient::onSecurityDefinitionReport(const Messaging::SecurityDefinitionReport msg, Session* sn)
1343{
1344 if(sn == bgwSession_.get())
1346 else
1347 Screen::printProgress(msg.listSeqNo(), msg.rpts());
1348
1349 std::shared_ptr<std::vector<uint8_t>> p(new std::vector<uint8_t>(msg.calculateBinarySize()));
1350 assert(p->size() == msg.calculateBinarySize());
1351 std::memcpy(p->data(), msg.binary(), p->size());
1352
1353 instruments_.push_back(p);
1354}
1355
1356void TradingClient::onSecurityDefinitionReport_Strategy(const Messaging::SecurityDefinitionReport_Strategy msg, Session* sn)
1357{
1358 if(sn == bgwSession_.get())
1360 else
1361 Screen::printProgress(msg.listSeqNo(), msg.rpts());
1362
1363 std::shared_ptr<std::vector<uint8_t>> p(new std::vector<uint8_t>(msg.calculateBinarySize()));
1364 assert(p->size() == msg.calculateBinarySize());
1365 std::memcpy(p->data(), msg.binary(), p->size());
1366
1367 instruments_.push_back(p);
1368}
1369
1370void TradingClient::onError(SessionErrorReason::Enum, const std::string & description, Session * sn, Messaging::SbeMessage)
1371{
1372 Screen::error("[" + sn->id() + "] error: [", description, "]");
1373}
1374
1375void TradingClient::onWarning(SessionWarningReason::Enum, const std::string & description, Session * sn, Messaging::SbeMessage)
1376{
1377 Screen::warning("[" + sn->id() + "] warning: [", description, "]");
1378}
1379
1380void TradingClient::onStateChange(SessionStateId::Enum newState, SessionStateId::Enum /*prevState*/, Session * sn)
1381{
1382 Screen::trace("[" + sn->id() + "] changed it's state to [", SessionStateId::toString(newState), "]");
1383}
1384
1385void TradingClient::onMessageSending(char* bytes, size_t size, Session* sn)
1386{
1387 const auto msg = SbeMessage(bytes, static_cast<Messaging::MessageSize>(size));
1388
1391}
1392
1393}
#define ONIXS_ICEBOE_NAMESPACE
Definition ABI.h:113
#define ONIXS_ICEBOE_MESSAGING_NAMESPACE
Definition ABI.h:114
Contains the SimpleOpenFramingHeader, the SBE message, and the data buffer.
const void * binary() const noexcept
MessageTemplateId templateId() const noexcept
MessageSize EncodedLength
Length of the message binary data.
HeaderFlags headerFlags() const noexcept
The time point without the time-zone information.
Definition Time.h:470
static Timestamp fromStr(const std::string &, TimestampFormat::Enum=TimestampFormat::YYYYMMDDHHMMSSnsec)
De-serializes a timestamp from the given string.
Definition Time.h:848
Ticks sinceEpoch() const noexcept
Definition Time.h:622
const std::string & userId() const noexcept
SessionSettings & licenseStore(const std::string &value)
Sets the path to the folder that contains license file(s).
std::string id() const
OptionalRef< CrossOrder > findCross(BookEntryId id)
Finds a cross order.
Definition Book.cpp:86
OptionalRef< Order > find(BookEntryId id)
Finds an instance of the entry by its identifier.
Definition Book.cpp:78
void createStrategy()
Creates a strategy.
void traderLogout()
Logs the trader out from the BGW session.
TradingClient(const Settings &settings)
Initializes the client with the given settings.
void listInstruments()
Prints the list of instruments currently known to the client.
void requestBgwCredentials()
Requests BGW credentials (IpRequest) over the active BUS session.
void connectBus()
Commands.
void connectBgw()
Establishes a BGW session using previously obtained credentials.
void createFlex()
Creates a flexible instrument (flex).
void sendOrderCross()
Sends a cross order.
void sendMassCancel()
Submits a mass cancel request.
void replaceOrder()
Issues a replace for an existing live order.
void lookupInstruments()
Prints the list of instruments currently known to the client by the provided Symbol value.
void sendQuoteCancelRequest()
Cancels a previously submitted quote.
void cancelOrder()
Sends a cancel request for a specific order.
void sendOrder()
Sends a new order via BGW.
void sendMassQuote()
Sends a multiple quote request.
void showActiveOrders()
Displays active orders sent by this client session and their last-known statuses.
void showOrders()
Displays orders sent by this client session and their last-known statuses.
void sendQuote()
Sends a quote message.
void traderLogon()
Logs a trader into the connected BGW session.
void requestInstruments()
Submits a SecurityDefinitionRequest to fetch/refresh known instruments.
OrderTypeEnum
OrderTypeEnum type.
Definition Fields.h:202
FloatingPointDecimal< Int64, Int32 > Decimal
Universal decimal type.
BooleanEnum
BooleanEnum type.
Definition Fields.h:406
constexpr std::enable_if<!details::HasMemberTraits< Value >::value, size_t >::type size() noexcept
Definition Memory.h:303
SideEnum
SideEnum type.
Definition Fields.h:394
constexpr std::enable_if< MaxMessageSizeTraits< Message >::UseCustomValue, MessageSize >::type getMaxMessageSize(UInt8)
Calculates the buffer size for a message with the given number of repeating group items.
Int64 Decimal9
Quantity, Price with constant exponent -9.
Definition Fields.h:32
constexpr bool hasFlag(T value, T flag, typename std::enable_if< isBitset< T >::value, void * >::type=nullptr) noexcept
Definition Bits.h:107
std::string toStr(const FixedPointDecimal< Mantissa, Exponent > &)
Serializes a fixed-point decimal into a string.
SecurityRequestTypeEnum
SecurityRequestTypeEnum type.
Definition Fields.h:773
CustOrderHandlingInstEnum
CustOrderHandlingInstEnumNULL type.
Definition Fields.h:178
UInt16 MessageSize
Message length type.
Definition Aliases.h:29
TimeInForceEnum
TimeInForceEnum type.
Definition Fields.h:295
StrRef toStrRef(const std::string &str)
Constructs a StrRef instance over th std::string content.
Definition StrRef.h:392
Int64 Int64NULL
int64NULL.
Definition Fields.h:86
unsigned short Port
Definition Defines.h:41
constexpr auto Side
Definition Defaults.h:50
constexpr Int32 MarketTypeId
Definition Defaults.h:48
constexpr Int32 Symbol
Definition Defaults.h:44
constexpr Int32 QuantityMantissa
Definition Defaults.h:49
constexpr Port TlsPort
Definition Defaults.h:32
constexpr Int32 Symbols[]
Definition Defaults.h:46
constexpr Int32 UnderlyingSymbol
Definition Defaults.h:45
const Timestamp Timestamp
Definition Defaults.h:57
constexpr Decimal9 PriceMantissa
Definition Defaults.h:51
MessageHolder< CancelReplaceRequest > CancelReplaceRequestMsg
auto print(OrderPtr order)
Definition Order.h:77
constexpr size_t MassQuoteRequestMaxEntriesCount
void setOrdStatus(Order &order, MsgType &&msg, ExecTypeEnum defaultValue)
Definition Utils.h:122
MessageHolder< OrderMassCancelRequest > OrderMassCancelRequestMsg
MessageHolder< SecurityDefinitionRequest > SecurityDefinitionRequestMsg
T parseUserInput(const std::string &userInput, typename std::enable_if< std::is_integral< T >::value, void * >::type=nullptr)
Definition Utils.h:142
void ignoreUnusedVariableWarning(T &&...) noexcept
Definition Tools.h:23
std::shared_ptr< CrossOrder > CrossOrderPtr
Definition Order.h:104
MessageHolder< NewOrderRequest > NewOrderRequestMsg
auto join(It first, It last, char delim, typename std::enable_if< isScopedEnum< typename It::value_type >::value, void * >::type=nullptr)
Definition Utils.h:208
MessageHolder< QuoteRequest > QuoteRequestMsg
std::optional< std::shared_ptr< T > > OptionalRef
Manages an optional contained reference.
Definition Utils.h:224
MessageHolder< MassQuoteRequest, getMaxMessageSize< MassQuoteRequest >(MassQuoteRequestMaxEntriesCount)> MassQuoteRequestMsg
MessageHolder< QuoteCancelRequest, getMaxMessageSize< QuoteCancelRequest >(QuoteCancelRequestMaxEntriesCount)> QuoteCancelRequestMsg
std::string toStr(Order::PriceOptional value)
Definition Order.cpp:34
std::shared_ptr< Order > OrderPtr
Definition Order.h:75
MessageHolder< NewOrderCrossRequest, getMaxMessageSize< NewOrderCrossRequest >(NewOrderCrossRequestMaxEntriesCount)> NewOrderCrossRequestMsg
bool activeOrder(const Order &order) noexcept
MessageHolder< CancelRequest > CancelRequestMsg
Decimal9 toPriceMantissa(Decimal value)
Definition Utils.h:136
static void outputItems(const EntryList &items, Print print=[](auto item){ return toStr(item);}, size_t itemsPerPage=100)
Outputs list items.
Definition CUI.h:473
static void traceMsg(const std::string &sessionId, SbeMessage message, Direction direction)
Definition CUI.h:211
static void error(const Args &... args)
Definition CUI.h:155
static void trace(const Args &... args)
Definition CUI.h:169
static void printProgress(size_t cur, size_t total)
Definition CUI.h:182
static std::ostream & out()
Definition CUI.h:130
static void warning(const Args &... args)
Definition CUI.h:162
static void info(const Args &... args)
Definition CUI.h:148
static T getInput(const T &defaultValue={})
Definition CUI.h:136
auto origClOrdId() const noexcept
int64NULL.
Definition Messages.h:18577
auto clOrdId() const noexcept
Provides access to clOrdID field.
Definition Messages.h:17891
auto origClOrdId() const noexcept
int64NULL.
Definition Messages.h:17989
auto clOrdId() const noexcept
Provides access to clOrdID field.
Definition Messages.h:17438
auto rejectResponseTo() const noexcept
Provides access to rejectResponseTo field.
Definition Messages.h:19109
auto clOrdId() const noexcept
Provides access to clOrdID field.
Definition Messages.h:18951
auto maxShow() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:19561
auto execId() const noexcept
Provides access to execID field.
Definition Messages.h:19445
auto clOrdId() const noexcept
Provides access to clOrdID field.
Definition Messages.h:19463
auto leavesQty() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:19587
auto orderStatus() const noexcept
uint8NULL.
Definition Messages.h:19735
auto timeInForce() const noexcept
Provides access to timeInForce field.
Definition Messages.h:19717
auto expireDate() const noexcept(dateToTimestamp::Nothrow)
UTC days since Unix epoch (January 1st, 1970).
Definition Messages.h:19675
auto side() const noexcept
Provides access to side field.
Definition Messages.h:19517
auto symbol() const noexcept
Provides access to symbol field.
Definition Messages.h:19481
auto ordType() const noexcept
Provides access to ordType field.
Definition Messages.h:19499
auto stopPx() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:19649
auto price() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:19623
auto execInst() const noexcept
Provides access to execInst field.
Definition Messages.h:20125
auto clOrdId() const noexcept
Provides access to clOrdID field.
Definition Messages.h:20681
auto leavesQty() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:20797
auto lastPx() const noexcept
Quantity, Price with constant exponent -9.
Definition Messages.h:20833
auto success() const noexcept
uint8NULL.
Definition Messages.h:8552
auto port() const noexcept
int16NULL.
Definition Messages.h:8607
auto ipSessionToken() const noexcept
ipSessionToken for the Gateway ID for assigned ipAddress and port for use in Binary Order Gateway Log...
Definition Messages.h:8634
auto ipAddress() const noexcept
Provides access to ipAddress field.
Definition Messages.h:8578
Users users() const noexcept
Definition Messages.h:8805
auto crossId() const noexcept
Provides access to crossID field.
Definition Messages.h:21932
auto rfcStatus() const noexcept
Provides access to rfcStatus field.
Definition Messages.h:21967
auto rpts() const noexcept
Provides access to noRpts field.
Definition Messages.h:2608
auto listSeqNo() const noexcept
Provides access to listSeqNo field.
Definition Messages.h:2626
Security Definition for futures, options, and FLEX creations. Each report will contain a single marke...
Definition Messages.h:4235
auto symbol() const noexcept
Market ID. Unique identifier of the market.
Definition Messages.h:4649
auto rpts() const noexcept
Provides access to noRpts field.
Definition Messages.h:4685
EncodedLength calculateBinarySize() const noexcept
Definition Messages.h:6337
auto listSeqNo() const noexcept
Provides access to listSeqNo field.
Definition Messages.h:4703
Security Definition Request to create a strategy.
Definition Messages.h:16310
static constexpr Int32 nanosecondsPerSecond() noexcept
Definition Time.h:57
static const std::string & toString(Enum state) noexcept
@ Established
Session is fully established.
@ BUS
Binary Utility Service Gateway.
Definition Session.h:51
@ BGW
Binary Order Gateway.
Definition Session.h:54
static int32_t newId()
Definition Helpers.h:43
TimeInForceEnum timeInForce_
Definition Order.h:66
SideEnum side_
Definition Order.h:63
std::string toString() const
Human-readable presentation of the most interesting fields stored in the order.
Definition Order.cpp:39
OrderTypeEnum ordType_
Definition Order.h:64
SecurityId securityId_
Definition Order.h:62
decltype(std::declval< const NewOrderRequest & >().maxShow()) QtiOptional
Definition Order.h:41
ClOrderId cIOrdId_
Definition Order.h:57
Qty orderQty_
Definition Order.h:60
PriceOptional price_
Definition Order.h:59
decltype(std::declval< const NewOrderRequest & >().execInst()) ExecInstOptional
Definition Order.h:43
ExecTypeEnum orderStatus_
Definition Order.h:70
Qty leavesQty_
Definition Order.h:61