1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
20
24#include "Utils.h"
25
27
29
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
76{
77 checkSettingSanity(settings);
78
80
81 sessionSettings
84 .clientId(settings.
get<
Int32>(
"ClientId"))
85 .rawData(settings.
get(
"Password"))
86 .reconnectAttempts(100)
87 .reconnectInterval(1)
88 .keepAliveInterval(settings.
get<
UInt16>(
"KeepAliveInterval"))
90 ;
91
92 return sessionSettings;
93}
94
95auto initSecurityDefinitionRequest(
const Settings&)
96{
98 return request;
99}
100
101auto initNewOrder(
const Settings& settings)
102{
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"))
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{
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"))
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{
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{
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{
244
245 request->
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
257 return request;
258}
259
260
261auto queryString(const char* name, const std::string& defaultValue)
262{
263 Screen::out(
"Enter ", name,
" (default=", defaultValue,
"): ");
265}
266
267auto queryTimestamp(
const char* name,
Timestamp defaultValue)
268{
271
272 if(userInput.empty())
273 return defaultValue;
274
276}
277
278template <typename OptionalType>
279auto queryOptionalTimestamp(const char* name, OptionalType defaultValue = {})
280{
283
284 if(userInput.empty())
285 return defaultValue;
286
288 return OptionalType{};
289
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{
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{
304
306
308 return OptionalType{};
309
311}
312
313auto queryDecimal(
const char* name,
Decimal9 defaultValue)
314{
317
318 if(userInput.empty())
319 return defaultValue;
320
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
330
331 if(userInput.empty())
332 return defaultValue;
333
335 return OptionalType{};
336
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
347
348 if(userInput.empty())
349 return defaultValue;
350
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
366
367 if(userInput.empty())
368 return defaultValue;
369
371 return OptionalType{};
372
374
375 return OptionalType{value};
376}
377
378template<size_t Size>
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>
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>
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>
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>
446{
447 return queryEnum("CustOrderHandlingInst", allowedValues, defaultValue);
448}
449
450struct QuoteIdGenerator
451{
453 {
455 }
456};
457
458}
459
460void TradingClient::checkConnected(const SessionPtr& sn, const char* kind)
461{
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
484{
485 auto ord = orderBook_.find(orderId);
486
487 if (!ord)
489
490 return ord;
491}
492
494{
495 auto settings = sessionSettings_;
496
497 if(!busSession_)
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
522 const auto requestType = querySecurityRequestType(
523 {SecurityRequestTypeEnum::RequestListofOptions,
524 SecurityRequestTypeEnum::RequestListofStrategies,
525 SecurityRequestTypeEnum::RequestListofFutures,
526 SecurityRequestTypeEnum::RequestListOfProducts
527 });
528
530 request->marketTypeId(marketTypeId);
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_)
544
545 std::reverse(messages.begin(), messages.end());
546
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{
561
562 std::vector<Messaging::SecurityDefinitionReport> messages;
563
564 for (auto element : instruments_)
565 {
567
568 if(msg.
symbol() == symbol)
569 messages.push_back(msg);
570 }
571
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_)
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());
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
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
732
733 TradingClient::send(bgwSession_, newOrderCrossRequest_);
734}
735
737{
738 checkConnected(bgwSession_, "BGW");
739
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
778 const auto side = querySide({SideEnum::Buy, SideEnum::Sell});
780
781 quoteRequest_
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 {
819
820 quote
822 .underlyingSymbol(underlyingSymbol)
823 .quoteSetId(getQuoteSetId(underlyingSymbol))
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
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
889
890 if(endDate)
891 msg->endDate(*endDate);
892 else
894
895 const auto legsCount = queryNumeric(
"Number of Legs",
UInt32{2});
896
897 assert(legsCount <= CreateStrategyMaxLegsCount);
898
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);
935
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
961
962 TradingClient::send(bgwSession_, msg);
963}
964
966{
967 auto crossOrder = std::make_shared<CrossOrder>();
968
969 Order& buySideOrder = *crossOrder->buySideOrder_;
970 Order& sellSideOrder = *crossOrder->sellSideOrder_;
971
975
976 const auto ordType = queryOrderType({OrderTypeEnum::Market, OrderTypeEnum::Limit}, OrderTypeEnum::Limit);
977
980
981 if (ordType == OrderTypeEnum::Limit)
982 {
983 const auto price = queryDecimal("Price", 64570000);
984 buySideOrder.
price_ = price;
985 sellSideOrder.
price_ = price;
986 }
987
993
996
997 buySideOrder.
side_ = SideEnum::Buy;
998 sellSideOrder.
side_ = SideEnum::Sell;
999
1000 return crossOrder;
1001}
1002
1004{
1005 OrderPtr result = std::make_shared<Order>();
1006 auto& order = *result;
1007
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)
1016
1017 if (order.ordType_ == OrderTypeEnum::StopLimit || order.ordType_ == OrderTypeEnum::Stop)
1019
1021 order.leavesQty_ = order.orderQty_;
1022
1023 order.timeInForce_ = queryTimeInForce(
1024 {TimeInForceEnum::Day, TimeInForceEnum::GTC, TimeInForceEnum::FAK, TimeInForceEnum::FOK, TimeInForceEnum::GTD},
1026
1027 if (order.timeInForce_ == TimeInForceEnum::GTD)
1029
1030 order.side_ = querySide({SideEnum::Buy, SideEnum::Sell}, base ? base->
side_ : SideEnum::Buy);
1031
1033
1034 const auto maxShow =
1036
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{
1051}
1052
1054{
1055 return order.orderStatus_ == ExecTypeEnum::New || order.orderStatus_ == ExecTypeEnum::PartialFill || order.orderStatus_ == ExecTypeEnum::Replaced;
1056}
1057
1059{
1061}
1062
1064{
1065 checkConnected(bgwSession_, "BGW");
1066
1067 const auto ordersInBook = orderBook_.getEntries(
activeOrder);
1068
1069 if (ordersInBook.empty())
1070 {
1072 return;
1073 }
1074
1076
1077 Screen::out(
"Enter the index of the order to be canceled");
1078
1080 const Order& order = *ordersInBook.at(orderIndex - 1);
1081
1082 cancelRequest_->
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 {
1101 return;
1102 }
1103
1105
1106 Screen::out(
"Enter the index of the order to be replaced");
1107
1109 const auto order = ordersInBook.at(orderIndex - 1);
1110
1111 auto replaceOrder = orderBook_.store(newOrder(order.get()));
1113
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
1136{
1138
1140 return;
1141
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 {
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 {
1162 }
1163
1164 if(status == RFCStatusEnum::PartialSuccessOfferFailure || status == RFCStatusEnum::Failure)
1165 {
1168 }
1169}
1170
1172{
1174
1176 return;
1177
1178 if(
auto order = findByOrderId(msg.
clOrdId()))
1179 {
1181 setCommonMessageFields(**order, msg);
1182
1184 }
1185}
1186
1188{
1190
1192 return;
1193
1195 {
1196 if(
auto order = findByOrderId(msg.
clOrdId()))
1197 {
1199 setCommonMessageFields(**order, msg);
1200
1202 }
1203 }
1204}
1205
1207{
1209
1211 return;
1212
1214
1216 {
1217 if(auto order = findByOrderId(*origClOrdId))
1218 {
1220 setCommonMessageFields(**order, msg);
1221
1223 }
1224 }
1225}
1226
1228{
1230
1232 return;
1233
1234 auto newOrder = findByOrderId(msg.
clOrdId());
1235
1237 auto oldOrder = origClOrdId ? findByOrderId(*origClOrdId) : decltype(findByOrderId(*origClOrdId)){};
1238
1239 if(newOrder)
1240 {
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
1255{
1257
1259 return;
1260
1261 if(
auto order = findByOrderId(msg.
clOrdId()))
1262 {
1264
1265 setCommonMessageFields(**order, msg);
1267
1269 }
1270}
1271
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
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();
1297 order->securityId_ = msg.
symbol();
1298 order->side_ = msg.
side();
1299 order->ordType_ = msg.
ordType();
1300 order->stopPx_ = msg.
stopPx();
1303 order->transactTime_ = msg.
execId().transactTime();
1304 order->maxShow_ = msg.
maxShow();
1306 order->origCIOrdId_ = msg.
clOrdId();
1307
1308 if(!found)
1309 orderBook_.store(order);
1310 }
1311}
1312
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
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
1330 throw std::runtime_error("Invalid 'IPReport::UsersEntry'");
1331
1333
1334 bgwCredentials_ = credentials;
1335 }
1336 catch(std::exception& e)
1337 {
1339 }
1340}
1341
1343{
1344 if(sn == bgwSession_.get())
1346 else
1348
1349 std::shared_ptr<std::vector<uint8_t>> p(
new std::vector<uint8_t>(msg.
calculateBinarySize()));
1351 std::memcpy(p->data(), msg.
binary(), p->size());
1352
1353 instruments_.push_back(p);
1354}
1355
1357{
1358 if(sn == bgwSession_.get())
1360 else
1362
1363 std::shared_ptr<std::vector<uint8_t>> p(
new std::vector<uint8_t>(msg.
calculateBinarySize()));
1365 std::memcpy(p->data(), msg.
binary(), p->size());
1366
1367 instruments_.push_back(p);
1368}
1369
1371{
1373}
1374
1376{
1378}
1379
1381{
1383}
1384
1385void TradingClient::onMessageSending(
char* bytes,
size_t size,
Session* sn)
1386{
1388
1391}
1392
1393}
#define ONIXS_ICEBOE_NAMESPACE
#define ONIXS_ICEBOE_MESSAGING_NAMESPACE
BGW session connection credentials.
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.
static Timestamp fromStr(const std::string &, TimestampFormat::Enum=TimestampFormat::YYYYMMDDHHMMSSnsec)
De-serializes a timestamp from the given string.
Ticks sinceEpoch() const noexcept
const std::string & userId() const noexcept
SessionSettings & licenseStore(const std::string &value)
Sets the path to the folder that contains license file(s).
T get(const std::string &key, typename std::enable_if< std::is_integral< T >::value, void * >::type=nullptr) const
bool isSet(const std::string &key) const
OrderTypeEnum
OrderTypeEnum type.
FloatingPointDecimal< Int64, Int32 > Decimal
Universal decimal type.
BooleanEnum
BooleanEnum type.
constexpr std::enable_if<!details::HasMemberTraits< Value >::value, size_t >::type size() noexcept
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.
constexpr bool hasFlag(T value, T flag, typename std::enable_if< isBitset< T >::value, void * >::type=nullptr) noexcept
std::string toStr(const FixedPointDecimal< Mantissa, Exponent > &)
Serializes a fixed-point decimal into a string.
SecurityRequestTypeEnum
SecurityRequestTypeEnum type.
CustOrderHandlingInstEnum
CustOrderHandlingInstEnumNULL type.
UInt16 MessageSize
Message length type.
TimeInForceEnum
TimeInForceEnum type.
StrRef toStrRef(const std::string &str)
Constructs a StrRef instance over th std::string content.
Int64 Int64NULL
int64NULL.
constexpr Int32 MarketTypeId
constexpr Int32 QuantityMantissa
constexpr Int32 Symbols[]
constexpr Int32 UnderlyingSymbol
const Timestamp Timestamp
constexpr Decimal9 PriceMantissa
auto print(OrderPtr order)
void setOrdStatus(Order &order, MsgType &&msg, ExecTypeEnum defaultValue)
T parseUserInput(const std::string &userInput, typename std::enable_if< std::is_integral< T >::value, void * >::type=nullptr)
void ignoreUnusedVariableWarning(T &&...) noexcept
auto join(It first, It last, char delim, typename std::enable_if< isScopedEnum< typename It::value_type >::value, void * >::type=nullptr)
std::string toStr(Order::PriceOptional value)
bool activeOrder(const Order &order) noexcept
Decimal9 toPriceMantissa(Decimal value)
static void outputItems(const EntryList &items, Print print=[](auto item){ return toStr(item);}, size_t itemsPerPage=100)
Outputs list items.
static void traceMsg(const std::string &sessionId, SbeMessage message, Direction direction)
static void error(const Args &... args)
static void trace(const Args &... args)
static void printProgress(size_t cur, size_t total)
static std::ostream & out()
static void warning(const Args &... args)
static void info(const Args &... args)
static T getInput(const T &defaultValue={})
auto origClOrdId() const noexcept
int64NULL.
auto clOrdId() const noexcept
Provides access to clOrdID field.
auto origClOrdId() const noexcept
int64NULL.
auto clOrdId() const noexcept
Provides access to clOrdID field.
New Order, cancel-replace, or cancel reject.
auto rejectResponseTo() const noexcept
Provides access to rejectResponseTo field.
auto clOrdId() const noexcept
Provides access to clOrdID field.
auto maxShow() const noexcept
Quantity, Price with constant exponent -9.
auto execId() const noexcept
Provides access to execID field.
auto clOrdId() const noexcept
Provides access to clOrdID field.
auto leavesQty() const noexcept
Quantity, Price with constant exponent -9.
auto orderStatus() const noexcept
uint8NULL.
auto timeInForce() const noexcept
Provides access to timeInForce field.
auto expireDate() const noexcept(dateToTimestamp::Nothrow)
UTC days since Unix epoch (January 1st, 1970).
auto side() const noexcept
Provides access to side field.
auto symbol() const noexcept
Provides access to symbol field.
auto ordType() const noexcept
Provides access to ordType field.
auto stopPx() const noexcept
Quantity, Price with constant exponent -9.
auto price() const noexcept
Quantity, Price with constant exponent -9.
auto execInst() const noexcept
Provides access to execInst field.
auto clOrdId() const noexcept
Provides access to clOrdID field.
auto leavesQty() const noexcept
Quantity, Price with constant exponent -9.
auto lastPx() const noexcept
Quantity, Price with constant exponent -9.
auto success() const noexcept
uint8NULL.
auto port() const noexcept
int16NULL.
auto ipSessionToken() const noexcept
ipSessionToken for the Gateway ID for assigned ipAddress and port for use in Binary Order Gateway Log...
auto ipAddress() const noexcept
Provides access to ipAddress field.
Response to IPRequest for Binary Gateways.
Users users() const noexcept
auto crossId() const noexcept
Provides access to crossID field.
auto rfcStatus() const noexcept
Provides access to rfcStatus field.
Security Definition for a strategy.
auto rpts() const noexcept
Provides access to noRpts field.
EncodedLength calculateBinarySize() const noexcept
auto listSeqNo() const noexcept
Provides access to listSeqNo field.
Security Definition for futures, options, and FLEX creations. Each report will contain a single marke...
auto symbol() const noexcept
Market ID. Unique identifier of the market.
auto rpts() const noexcept
Provides access to noRpts field.
EncodedLength calculateBinarySize() const noexcept
auto listSeqNo() const noexcept
Provides access to listSeqNo field.
Security Definition Request to create a strategy.
static constexpr Int32 nanosecondsPerSecond() noexcept
static const std::string & toString(Enum state) noexcept
@ Established
Session is fully established.
@ BUS
Binary Utility Service Gateway.
@ BGW
Binary Order Gateway.
TimeInForceEnum timeInForce_
TimestampOptional expireDate_
std::string toString() const
Human-readable presentation of the most interesting fields stored in the order.
decltype(std::declval< const NewOrderRequest & >().maxShow()) QtiOptional
decltype(std::declval< const NewOrderRequest & >().execInst()) ExecInstOptional
ExecInstOptional execInst_
ExecTypeEnum orderStatus_