An advanced interactive console application to send orders and receive responses.
#include "Book.h"
#include <iostream>
#include <string>
#include <vector>
namespace CUI {
struct Screen
{
struct MessagePrinter
{
explicit MessagePrinter(const std::string& prefix) : prefix_(prefix) {}
template <typename MessageType>
void operator()(const MessageType& msg) const
{
info(prefix_, msg.toString());
}
std::string prefix_;
};
typedef Threading::Mutex Mutex;
typedef Threading::Guard<Threading::Mutex> Guard;
static Mutex& mutex()
{
static Mutex mutex;
return mutex;
}
static std::string getInput()
{
std::string userInput;
std::getline(std::cin, userInput);
return userInput;
}
template <typename T>
static T getInput(const T & defaultValue = T())
{
std::string userInput;
std::getline(std::cin, userInput);
if (userInput.empty())
return defaultValue;
else
{
Messaging::Int64 converted = Messaging::Int64();
std::istringstream ss(userInput);
ss >> converted;
return static_cast<T>(converted);
}
}
template <typename T>
static void getInput(T & value, const T & defaultValue = T())
{
std::string userInput;
std::getline(std::cin, userInput);
if (userInput.empty())
value = defaultValue;
else
{
Messaging::Int64 converted = Messaging::Int64();
std::istringstream ss(userInput);
ss >> converted;
value = static_cast<T>(converted);
}
}
{
std::string userInput;
std::getline(std::cin, userInput);
Timestamp timestamp;
if(
fromStr(timestamp, userInput, TimestampFormat::YYYYMMDD))
else
value = 0;
}
template <typename T>
static void getInputChar(T & value, const T & defaultValue = T())
{
std::string userInput;
std::getline(std::cin, userInput);
if (userInput.empty())
value = defaultValue;
else
{
std::istringstream ss(userInput);
ss >> converted;
value = static_cast<T>(converted);
}
}
static void info(const std::string& message)
{
info("INFO: ", message);
}
static void info(const std::string& prefix, const std::string& message)
{
Guard g(mutex());
std::cout << std::endl << prefix << message << std::endl;
}
static void out(const std::string& message)
{
Guard g(mutex());
std::cout << message << std::endl;
}
static void out(const std::string& prefix, const SbeMessage& message)
{
info("Unknown message type.");
}
template <typename ItemType>
static void outItems(const ItemType & items)
{
Guard g(mutex());
for (size_t index = 0; index < items.size(); ++index)
std::cout << (index + 1) << ") " << items[index].text << std::endl;
}
static bool shouldContinue()
{
{
Guard g(mutex());
std::cout << std::endl << "Press <Enter> to view next page or Enter 'quit' to abort current action: ";
}
const std::string userInput = getInput();
{
Guard g(mutex());
std::cout << std::endl;
}
return userInput.empty();
}
};
enum CommandExecutionStatus
{
TerminateExecution,
ContinueExecution,
RepeatExecution
};
template <typename Owner>
class Menu
{
public:
typedef void (Owner::*Command)(CommandExecutionStatus*);
explicit Menu(Owner* owner)
: owner_(owner)
{
}
~Menu()
{
}
Menu& add(const std::string& text, const std::string& commandText, Command command)
{
items_.push_back(Item(text, commandText, command));
return *this;
}
void processRequests() const
{
CommandExecutionStatus status = ContinueExecution;
while (TerminateExecution != status)
{
outputItems();
processRequest(&status);
}
}
private:
struct Item
{
Item(const std::string& itemText, const std::string& itemCommandText, Command itemCommand)
: text(itemText)
, commandText(itemCommandText)
, command(itemCommand)
{
}
Item(const Item& other)
: text(other.text)
, commandText(other.commandText)
, command(other.command)
{
}
std::string text;
std::string commandText;
Command command;
};
Owner* owner_;
std::vector<Item> items_;
void outputItems() const
{
Screen::info("Select operation you want to perform: ");
Screen::outItems(items_);
}
void processRequest(CommandExecutionStatus* status) const
{
Screen::out("Enter your choice : ");
std::string userInput = Screen::getInput();
const size_t selectedItemNumber = static_cast<size_t>(atoi(userInput.c_str()) - 1);
if (items_.size() <= selectedItemNumber)
{
Screen::info("Invalid command requested. Repeat your choice.");
}
else
{
try
{
const Item& selectedItem = items_[selectedItemNumber];
Screen::info(selectedItem.commandText);
(owner_->*(selectedItem.command))(status);
const unsigned int CommandExecutionTimeout = 500;
Threading::ThisThread::sleep(CommandExecutionTimeout);
}
catch (const std::exception& ex)
{
Screen::info("ERROR: ", ex.what());
}
}
}
};
template <typename Stringable>
class ListViewer
{
public:
typedef typename Samples::Book<Stringable>::EntryList StringableList;
static void outputItems(const StringableList& items, size_t itemsPerPage)
{
if (0 == items.size())
{
Screen::info("No items available.");
}
else
{
size_t itemNumber = 0;
size_t itemsToOutput = itemsPerPage;
for (StringableListConstEntry itemPtr = items.begin(); itemPtr != items.end(); ++itemPtr)
{
if (0 == --itemsToOutput)
{
itemsToOutput = itemsPerPage;
if (!Screen::shouldContinue())
return;
}
Screen::out(
toStr(++itemNumber) +
") " + (*itemPtr)->toString() +
".");
}
}
}
private:
typedef typename StringableList::const_iterator StringableListConstEntry;
};
}
#include "../Settings/Defaults.h"
#include "MessageFactory.h"
namespace Samples {
MessageFactory::MessageFactory(const std::string& sessionId)
: sessionId_(sessionId)
{}
NewOrderSingle MessageFactory::initNewOrder() const
{
NewOrderSingle msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
NewOrderSingle & MessageFactory::getNewOrder(const Order& order) const
{
static NewOrderSingle msg = initNewOrder();
msg->setPrice(
PRICE9(order.price_))
.setOrderQty(order.orderQty_)
.setSecurityId(order.securityId_)
.setClOrdId(order.cIOrdId_)
.setOrderRequestId(IdGenerator::newIntId())
.setStopPx(
PRICE9(order.stopPx_))
.setMinQty(order.minQty_)
.setDisplayQty(order.displayQty_)
.setOrdType(order.ordType_)
.setTimeInForce(order.timeInForce_)
.setSide(order.side_);
return msg;
}
OrderCancelReplaceRequest MessageFactory::initOrderCancelReplaceRequest() const
{
OrderCancelReplaceRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
OrderCancelReplaceRequest & MessageFactory::getModifyRequest(const Order& order) const
{
static OrderCancelReplaceRequest msg = initOrderCancelReplaceRequest();
msg->setPrice(
PRICE9(order.price_))
.setOrderQty(order.orderQty_)
.setSecurityId(order.securityId_)
.setClOrdId(order.cIOrdId_)
.setOrderId(order.orderId_)
.setOrderRequestId(IdGenerator::newIntId())
.setStopPx(
PRICE9(order.stopPx_))
.setMinQty(order.minQty_)
.setOrdType(order.ordType_)
.setTimeInForce(order.timeInForce_);
return msg;
}
OrderCancelRequest MessageFactory::initOrderCancelRequest() const
{
OrderCancelRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
OrderCancelRequest & MessageFactory::getCancelRequest(const Order& order) const
{
static OrderCancelRequest msg = initOrderCancelRequest();
msg->setClOrdId(order.cIOrdId_)
.setOrderId(order.orderId_)
.setOrderRequestId(IdGenerator::newIntId())
.setSecurityId(order.securityId_);
return msg;
}
NewOrderCross MessageFactory::initNewOrderCross() const
{
NewOrderCross msg;
msg->setSenderId(sessionId_)
.setLocation(Location)
return msg;
}
NewOrderCross & MessageFactory::getNewOrderCross(const Order& buySideOrder, const Order& sellSideOrder) const
{
static NewOrderCross msg = initNewOrderCross();
msg->setPrice(
PRICE9(buySideOrder.price_))
.setSecurityId(buySideOrder.securityId_)
.setCrossId(IdGenerator::newIntId())
.setOrderRequestId(IdGenerator::newIntId())
NewOrderCross544::SidesEntry buyEntry = noSides[0];
NewOrderCross544::SidesEntry sellEntry = noSides[1];
buyEntry.setClOrdId(buySideOrder.cIOrdId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setOrderQty(buySideOrder.orderQty_)
.setSide(buySideOrder.side_)
sellEntry.setClOrdId(sellSideOrder.cIOrdId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setOrderQty(sellSideOrder.orderQty_)
.setSide(sellSideOrder.side_)
return msg;
}
OrderMassActionRequest MessageFactory::initOrderMassActionRequest() const
{
OrderMassActionRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
OrderMassActionRequest & MessageFactory::getOrderMassActionRequest(
MassActionScope::Enum scope,
const std::string & traits)
const{
static OrderMassActionRequest msg = initOrderMassActionRequest();
msg->setOrderRequestId(IdGenerator::newIntId())
.setMassActionScope(scope);
switch (scope)
{
{
msg->setMarketSegmentId(fromStr<UInt8>(traits));
break;
}
{
msg->setSecurityGroup(traits);
break;
}
{
msg->setSecurityId(fromStr<Int32>(traits));
break;
}
default: {}
}
return msg;
}
RequestForQuote MessageFactory::initRequestForQuote() const
{
RequestForQuote msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
{
static RequestForQuote msg = initRequestForQuote();
msg->setQuoteReqId(IdGenerator::newIntId());
noRelatedSym[0].setOrderQty(qti)
.setSide(side)
.setSecurityId(securityId);
return msg;
}
SecurityDefinitionRequest MessageFactory::initSecurityDefinitionRequest() const
{
SecurityDefinitionRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
.setSecuritySubType("COMBO");
return msg;
}
SecurityDefinitionRequest & MessageFactory::getSecurityDefinitionRequest() const
{
static SecurityDefinitionRequest msg = initSecurityDefinitionRequest();
msg->setSecurityReqId(IdGenerator::newIntId());
noLegs[0].setLegSecurityId(DefaultSecurityId)
.setLegPrice(
PRICE9(DefaultPriceMantissa))
.setLegRatioQty(1);
noLegs[1].setLegSecurityId(DefaultSecurityId + 1)
.setLegPrice(
PRICE9(DefaultPriceMantissa))
.setLegRatioQty(1);
return msg;
}
OrderMassStatusRequest MessageFactory::initOrderMassStatusRequest() const
{
OrderMassStatusRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
return msg;
}
OrderMassStatusRequest & MessageFactory::getOrderMassStatusRequest(
MassStatusReqTyp::Enum type,
const std::string & traits)
const{
static OrderMassStatusRequest msg = initOrderMassStatusRequest();
msg->setMassStatusReqId(IdGenerator::newIntId())
.setMassStatusReqType(type);
switch (type)
{
{
msg->setSecurityGroup(traits);
break;
}
{
msg->setSecurityId(fromStr<Int32>(traits));
break;
}
{
msg->setMarketSegmentId(fromStr<UInt8>(traits));
break;
}
{
break;
}
}
return msg;
}
}
#include "MessageFactory.h"
#include "Settings.h"
#include "CUI.h"
#include "Order.h"
#include "Book.h"
namespace Samples
{
{
public:
explicit TradingClient(const Settings& settings);
void run();
private:
const Settings& settings_;
PtrTraits<Session>::UniquePtr primarySession_;
PtrTraits<Session>::UniquePtr backupSession_;
bool connected_;
Book<Order> orderBook_;
typedef Book<Order>::EntryList OrderList;
MessageFactory messageFactory_;
typedef CUI::Menu<TradingClient> Menu;
Menu menu_;
void constructMenu();
void createSessions();
void onSendSequence(CUI::CommandExecutionStatus*);
void onExit(CUI::CommandExecutionStatus*);
void onOrderCancelRequest(CUI::CommandExecutionStatus*);
void onOrderMassActionRequest(CUI::CommandExecutionStatus*);
void onOrderModifyRequest(CUI::CommandExecutionStatus*);
void onSendNewOrder(CUI::CommandExecutionStatus*);
void onViewOrders(CUI::CommandExecutionStatus*);
void onViewSessions(CUI::CommandExecutionStatus*);
void onSecurityDefinitionRequest(CUI::CommandExecutionStatus*);
void onMassStatusRequest(CUI::CommandExecutionStatus*);
void onRequestForQuote(CUI::CommandExecutionStatus*);
void onCrossOrder(CUI::CommandExecutionStatus*);
void resetSequenceNumbers(CUI::CommandExecutionStatus*);
void establishConnection(CUI::CommandExecutionStatus*);
void disconnect(CUI::CommandExecutionStatus*);
bool checkSessionConnected();
template <typename SbeMessageType, size_t MaxMessageSize, typename MessageInitializer>
void send(Messaging::MessageHolder<SbeMessageType, MaxMessageSize, MessageInitializer> &msg)
{
if (!checkSessionConnected())
return;
if (failover_)
{
if (FTI::Primary == primarySession_->faultToleranceIndicator())
primarySession_->send(msg);
else if (FTI::Primary == backupSession_->faultToleranceIndicator())
backupSession_->send(msg);
else
CUI::Screen::info("Cannot send an iLink3 message because there is not a session with the primary role.");
}
else
primarySession_->send(msg);
}
template <typename MsgType>
Order* findByOrderId(const MsgType& report)
{
Order* const msg = orderBook_.find(clOrdId);
if (!msg)
{
std::string errReason("Cannot process received Execution Report. No order was sent with ClOrdID (tag = 11) equal to '");
errReason += clOrdId;
errReason += " in the current session'";
throw std::domain_error(errReason);
}
return msg;
}
template <typename MsgType>
void setCommonFields(Order * order, const MsgType& msg)
{
order->orderId(msg.orderId())
.orderQty(msg.orderQty())
.securityId(msg.securityId())
.transactTime(msg.transactTime());
Timestamp expireDate;
if(msg.expireDate(expireDate))
TimeInForce::Enum timeInForce;
if(msg.timeInForce(timeInForce))
order->timeInForce_ = timeInForce;
}
template <typename MsgType>
void setOrdStatus(std::string & ordStatus, const MsgType& msg)
{
ordStatus = OrderStatus::toString(static_cast<OrderStatus::Enum>(msg.ordStatus().value()));
}
Order newOrder();
bool failover_;
void onMessageSending(
char* bytes,
size_t size,
Session*) ONIXS_ILINK3_OVERRIDE;
void onNegotiationResponse(const NegotiationResponse501 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onNegotiationReject(const NegotiationReject502 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onEstablishmentAck(const EstablishmentAck504 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onEstablishmentReject(const EstablishmentReject505 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onSequence(const Sequence506 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onTerminate(const Terminate507 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onRetransmitReject(const Messaging::RetransmitReject510 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onRetransmission(const Messaging::Retransmission509 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
NotAppliedAction::Enum onNotApplied(const Messaging::NotApplied513 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onBusinessReject(const BusinessReject521 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportNew(const ExecutionReportNew522 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportModify(const ExecutionReportModify531 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportCancel(const ExecutionReportCancel534 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportStatus(const ExecutionReportStatus532 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeOutright(const ExecutionReportTradeOutright525 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeSpread(const ExecutionReportTradeSpread526 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeSpreadLeg(const ExecutionReportTradeSpreadLeg527 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportElimination(const ExecutionReportElimination524 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportReject(const ExecutionReportReject523 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeAddendumOutright(const ExecutionReportTradeAddendumOutright548 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeAddendumSpread(const ExecutionReportTradeAddendumSpread549 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportTradeAddendumSpreadLeg(const ExecutionReportTradeAddendumSpreadLeg550 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onOrderCancelReject(const OrderCancelReject535 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onOrderCancelReplaceReject(const OrderCancelReplaceReject536 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onSecurityDefinitionResponse(const SecurityDefinitionResponse561 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onMassQuoteAck(const MassQuoteAck545 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onRequestForQuoteAck(const RequestForQuoteAck546 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onQuoteCancelAck(const QuoteCancelAck563& msg,
Session* sn) ONIXS_ILINK3_OVERRIDE;
void onOrderMassActionReport(const OrderMassActionReport562& msg,
Session* sn) ONIXS_ILINK3_OVERRIDE;
void onPartyDetailsDefinitionRequestAck(const PartyDetailsDefinitionRequestAck519 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onPartyDetailsListReport(const PartyDetailsListReport538 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportPendingCancel(const Messaging::ExecutionReportPendingCancel564 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onExecutionReportPendingReplace(const Messaging::ExecutionReportPendingReplace565 & msg,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onStateChange(SessionStateId::Enum newState, SessionStateId::Enum prevState,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onFailover(Messaging::FTI::Enum faultToleranceIndicator,
Session * sn) ONIXS_ILINK3_OVERRIDE;
void onError(SessionErrorReason::Enum reason, const
std::
string & description,
Session * sn, Messaging::SbeMessage) ONIXS_ILINK3_OVERRIDE;
void onWarning(SessionWarningReason::Enum reason, const
std::
string & description,
Session * sn, Messaging::SbeMessage) ONIXS_ILINK3_OVERRIDE;
};
}
#include "../Settings/Defaults.h"
#include "TradingClient.h"
namespace Samples
{
const SessionSettings& settings, std::string segment, SessionListener* listener,
UInt64 uuid = Session::UndefinedUuid,
const std::string& customKey =
"")
{
std::transform(segment.begin(), segment.end(), segment.begin(), ::toupper);
if(segment == "CGW")
return new CgwSession(settings, listener, SessionStorageType::FileBased,
ONIXS_ILINK3_NULLPTR, uuid, customKey);
}
using namespace CUI;
typedef ListViewer<Order> OrdersViewer;
TradingClient::TradingClient(const Settings& settings)
: settings_(settings)
, connected_(false)
, messageFactory_(settings.get("SessionId"))
, menu_(this)
, failover_(settings.getAsBool("FaultTolerance", false))
{
createSessions();
constructMenu();
}
void TradingClient::run()
{
menu_.processRequests();
}
void TradingClient::constructMenu()
{
menu_
.add("Connect Sessions.", "Sending Negotiation/Establishment.. ", &TradingClient::establishConnection)
.add("Review the status of sessions. ", "Viewing the status of sessions.. ", &TradingClient::onViewSessions)
.add("Send Sequence. ", "Sending Sequence.. ", &TradingClient::onSendSequence)
.add("Review sent orders and their status. ", "Viewing sent orders and their status.. ", &TradingClient::onViewOrders)
.add("Create and send a New Order. ", "Creating new order.. ", &TradingClient::onSendNewOrder)
.add("Submit Order Modify Request. ", "Order Modify Request.. ", &TradingClient::onOrderModifyRequest)
.add("Submit Order Cancel Request. ", "Order Cancel Request.. ", &TradingClient::onOrderCancelRequest)
.add("Submit Order Mass Action Request. ", "Order Mass Action Request.. ", &TradingClient::onOrderMassActionRequest)
.add("Submit Order Mass Status Request. ", "Order Mass Status Request.. ", &TradingClient::onMassStatusRequest)
.add("Submit SecurityDefinitionRequest. ", "Creating SecurityDefinition.. ", &TradingClient::onSecurityDefinitionRequest)
.add("Submit RequestForQuote. ", "Creating RFQ.. ", &TradingClient::onRequestForQuote)
.add("Submit New Order Cross. ", "Creating Cross Order.. ", &TradingClient::onCrossOrder)
.add("Disconnect all sessions", "Closing connections...", &TradingClient::disconnect)
.add("Reset Sequence Numbers", "Reset Sequence Numbers", &TradingClient::resetSequenceNumbers)
.add("Close the connection and exit. ", "Exiting application.. ", &TradingClient::onExit);
}
bool TradingClient::checkSessionConnected()
{
if (!connected_)
Screen::info("Session is not connected. Please establish the connection first.");
return connected_;
}
void TradingClient::createSessions()
{
Screen::info("Creating the primary iLink3 Session..");
SessionSettings settings;
settings
.licenseStore("../../license")
.sessionId(settings_.get("SessionId"))
.secretKey(settings_.get("SecretKey"))
.accessKey(settings_.get("AccessKey"))
.firmId(settings_.get("FirmId"))
.tradingSystemName(settings_.get("TradingSystemName"))
.tradingSystemVersion(settings_.get("TradingSystemVersion"))
.tradingSystemVendor(settings_.get("TradingSystemVendor"))
.keepAliveInterval(settings_.getAsInt("KeepAliveInterval"));
primarySession_.reset(createSession(settings, settings_.get("MarketSegment"), this));
const int incomingSequenceNumber = settings_.getAsInt("InSeqNum");
if (incomingSequenceNumber > 0)
primarySession_->inSeqNum(incomingSequenceNumber);
const int outgoingSequenceNumber = settings_.getAsInt("OutSeqNum");
if (outgoingSequenceNumber > 0)
primarySession_->outSeqNum(outgoingSequenceNumber);
if (failover_)
{
Screen::info("Creating the backup iLink3 Session..");
backupSession_.reset(
createSession(settings, settings_.get("MarketSegment"), this, primarySession_->uuid(), "Backup"));
}
}
void TradingClient::establishConnection(CommandExecutionStatus* status)
{
if (!connected_)
{
try
{
primarySession_->connect(settings_.get("Host"), settings_.getAsInt("Port"));
}
catch (const std::exception& ex)
{
Screen::info("Cannot connect to the primary host: ", ex.what());
if (!failover_)
throw;
}
if (failover_)
{
try
{
backupSession_->connect(settings_.get("BackupHost"), settings_.getAsInt("BackupPort"));
}
catch (const std::exception& ex)
{
Screen::info("Cannot connect to the backup host: ", ex.what());
throw;
}
}
Screen::info("Done");
}
else
Screen::info("Connection is already established.");
*status = ContinueExecution;
}
void TradingClient::disconnect(CommandExecutionStatus*)
{
if (failover_)
{
{
Screen::info("Disconnecting from backup counterparty.. ");
backupSession_->disconnect();
}
}
{
Screen::info("Disconnecting from primary counterparty.. ");
primarySession_->disconnect();
}
Screen::info("Done");
}
void TradingClient::onSendSequence(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
if (failover_)
{
if (
FTI::Primary == primarySession_->faultToleranceIndicator())
primarySession_->sendSequenceMessage();
else if (
FTI::Primary == backupSession_->faultToleranceIndicator())
backupSession_->sendSequenceMessage();
else
Screen::info("Cannot send a Sequence message because there is no a session with the primary role.");
}
else
primarySession_->sendSequenceMessage();
Screen::info("Done");
}
void TradingClient::onViewOrders(CommandExecutionStatus*)
{
OrderList orderList;
orderBook_.getEntries(orderList);
OrdersViewer::outputItems(orderList, 10);
}
void TradingClient::onViewSessions(CommandExecutionStatus*)
{
Screen::info(std::string("Fail-over is ") + (failover_ ? "on." : "off."));
Screen::info("Primary iLink3 session: ",
".");
if (failover_)
Screen::info("Backup iLink3 session: ",
".");
}
void TradingClient::onOrderMassActionRequest(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Screen::info("Sending Order Mass Action Request to counterparty.. ");
Screen::info("Enter MassActionScope (1=Instrument (default), 9=Market Segment ID, 10=Group Code): ");
Screen::info(
"Enter " +
toStr(massActionScope) +
" : ");
const std::string traits = Screen::getInput();
OrderMassActionRequest & msg = messageFactory_.getOrderMassActionRequest(massActionScope, traits);
send(msg);
Screen::info("Done");
}
void TradingClient::onRequestForQuote(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Screen::info("Sending Request For Quote to counterparty.. ");
Screen::info("Enter Qty (default = 100):");
const UInt32 qti = Screen::getInput<UInt32>(100u);
Screen::info("Enter Side ( 1 = Buy (default), 2 = Sell, 8 = Cross): ");
Screen::info(
"Enter SecurityId (default=" +
toStr(DefaultSecurityId) +
"): ");
const Int32 securityId = Screen::getInput<Int32>(DefaultSecurityId);
RequestForQuote & msg = messageFactory_.getRequestForQuote(qti, side, securityId);
send(msg);
Screen::info("Done");
}
void TradingClient::onSecurityDefinitionRequest(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Screen::info("Sending Security Definition Request to counterparty.. ");
SecurityDefinitionRequest & msg = messageFactory_.getSecurityDefinitionRequest();
send(msg);
Screen::info("Done");
}
void TradingClient::onMassStatusRequest(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Screen::info("Sending Mass Status Request to counterparty.. ");
Screen::info("Enter massStatusReqType (1 = Instrument (default), 3 = Group Code, 100 = Market Segment : ");
Screen::info(
"Enter " +
toStr(massStatusReqType) +
" : ");
const std::string traits = Screen::getInput();
OrderMassStatusRequest & msg = messageFactory_.getOrderMassStatusRequest(massStatusReqType, traits);
send(msg);
Screen::info("Done");
}
void TradingClient::onSendNewOrder(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Screen::info("Sending new order to counterparty.. ");
Order order = newOrder();
NewOrderSingle & msg = messageFactory_.getNewOrder(order);
send(msg);
orderBook_.store(order);
Screen::info("Done");
}
void TradingClient::onOrderCancelRequest(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
OrderList ordersInBook;
orderBook_.getEntries(ordersInBook);
if (ordersInBook.empty())
{
Screen::info("No orders found");
return;
}
OrdersViewer orderViewer;
orderViewer.outputItems(ordersInBook, 10);
Screen::out("Enter the index of the order to be canceled ");
const int orderIndex = atoi(Screen::getInput().c_str());
const Order * order = ordersInBook.at(orderIndex - 1);
OrderCancelRequest & msg = messageFactory_.getCancelRequest(*order);
send(msg);
Screen::info("Done");
}
void TradingClient::onOrderModifyRequest(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
OrderList ordersInBook;
orderBook_.getEntries(ordersInBook);
if (ordersInBook.empty())
{
Screen::info("No orders found");
return;
}
OrdersViewer orderViewer;
orderViewer.outputItems(ordersInBook, 10);
Screen::out("Enter the index of the order to be modified ");
const int orderIndex = atoi(Screen::getInput().c_str());
Order* const order = ordersInBook.at(orderIndex - 1);
Screen::info("Enter new OrderQty (or Enter to skip): ");
Screen::getInput(order->orderQty_, order->orderQty_);
Screen::info("Enter new Price mantissa (or Enter to skip): ");
Screen::getInput(order->price_, order->price_);
OrderCancelReplaceRequest & msg = messageFactory_.getModifyRequest(*order);
send(msg);
Screen::info("Done");
}
void TradingClient::onCrossOrder(CommandExecutionStatus*)
{
if (!checkSessionConnected())
return;
Order buySideOrder;
Screen::info(
"Enter Price mantissa (default = " +
toStr(DefaultPriceMantissa) +
"): ");
Screen::getInput(buySideOrder.price_, DefaultPriceMantissa);
Screen::info(
"Enter SecurityId (default=" +
toStr(DefaultSecurityId) +
"): ");
Screen::getInput(buySideOrder.securityId_, DefaultSecurityId);
Screen::info("Enter Quantity (default = 100): ");
Screen::getInput(buySideOrder.orderQty_, 100u);
Order sellSideOrder;
sellSideOrder
.price(buySideOrder.price_)
.securityId(buySideOrder.securityId_)
.orderQty(buySideOrder.orderQty_)
NewOrderCross & msg = messageFactory_.getNewOrderCross(buySideOrder, sellSideOrder);
send(msg);
orderBook_
.store(buySideOrder)
.store(sellSideOrder);
Screen::info("Done");
}
void TradingClient::onExit(CommandExecutionStatus* status)
{
*status = TerminateExecution;
}
void TradingClient::resetSequenceNumbers(CommandExecutionStatus*)
{
{
if(primarySession_->negotiated())
primarySession_->reset(false);
}
else
Screen::info("Operation can be performed only when the sessions are disconnected");
backupSession_->reset(false);
Screen::info("Done");
}
Order TradingClient::newOrder()
{
Order order;
Screen::info(
"Enter SecurityId (default=" +
toStr(DefaultSecurityId) +
"): ");
Screen::getInput(order.securityId_, DefaultSecurityId);
Screen::info(
"Enter OrderType(40) (1-Market order, 2 - Limit order (default), 3 - Stop order, 4 - Stop - Limit order, K - Market - Limit order): ");
{
Screen::info(
"Enter Price mantissa (default = " +
toStr(DefaultPriceMantissa) +
"): ");
Screen::getInput(order.price_, DefaultPriceMantissa);
}
{
Screen::info("Enter StopPx: ");
Screen::getInput(order.stopPx_);
}
Screen::info("Enter OrderQuantity (default = 100): ");
Screen::getInput(order.orderQty_, 100u);
Screen::info("Enter MinQty or skip");
Screen::getInput(order.minQty_,
NullUInt32().value());
Screen::info("Enter DisplayQty or skip");
Screen::getInput(order.displayQty_,
NullUInt32().value());
Screen::info(
"Enter TimeInForce (0 - Day (default), 1 - Good Till Cancel, 3 - Fill and Kill, 6 - Good Till Date): ");
{
Screen::info("Enter Expire date YYYYMMDD: ");
Screen::getInputLocalMktDate(order.expireDate_);
}
Screen::info("Enter Side (1 - Buy (default), 2 - Sell): ");
return order;
}
void TradingClient::onMessageSending(
char* bytes,
size_t size,
Session*)
{
Screen::out("Outbound message: ", SbeMessage(bytes, static_cast<Messaging::MessageSize>(size)));
}
void TradingClient::onBusinessReject(
const BusinessReject521 & msg,
Session * sn)
{
Screen::info("BusinessReject received from counterparty: ", msg.toString());
+ (msg.refTagId(refTagId) ?
", refTagId=" +
toStr(refTagId) :
std::string()));
if (!msg.refSeqNum(refSeqNum))
sn->outSeqNum(sn->outSeqNum() - 1);
}
void TradingClient::onNegotiationResponse(
const NegotiationResponse501 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onNegotiationReject(
const NegotiationReject502 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onEstablishmentAck(
const EstablishmentAck504 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onEstablishmentReject(
const EstablishmentReject505 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onSequence(
const Sequence506 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onTerminate(
const Terminate507 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onRetransmitReject(
const Messaging::RetransmitReject510 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onRetransmission(
const Messaging::Retransmission509 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onExecutionReportNew(
const ExecutionReportNew522 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
setOrdStatus(order->orderStatus_, msg);
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportModify(
const ExecutionReportModify531 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
setOrdStatus(order->orderStatus_, msg);
order->leavesQty(msg.leavesQty())
.cumQty(msg.cumQty());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportCancel(
const ExecutionReportCancel534 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
setOrdStatus(order->orderStatus_, msg);
order->leavesQty(msg.cumQty());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportReject(
const ExecutionReportReject523 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
setOrdStatus(order->orderStatus_, msg);
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportStatus(
const ExecutionReportStatus532 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
.leavesQty(msg.leavesQty())
.cumQty(msg.cumQty());
Screen::info("Order changed: " + order->toString());
if (msg.lastRptRequested(lastRptRequested))
Screen::info(
"LastRptRequested = " +
toStr(lastRptRequested));
if (msg.massStatusReqId(massStatusReqId))
Screen::info(
"MassStatusReqID = " +
toStr(massStatusReqId));
}
void TradingClient::onExecutionReportTradeOutright(
const ExecutionReportTradeOutright525 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
.leavesQty(msg.leavesQty())
.cumQty(msg.cumQty())
.lastPx(msg.lastPx().mantissa());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportTradeSpread(
const ExecutionReportTradeSpread526 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
.leavesQty(msg.leavesQty())
.cumQty(msg.cumQty())
.lastPx(msg.lastPx().mantissa());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportTradeSpreadLeg(
const ExecutionReportTradeSpreadLeg527 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
order->orderId(msg.orderId());
order->securityId(msg.securityId());
order->cumQty(msg.cumQty());
order->lastPx(msg.lastPx().mantissa());
order->transactTime(msg.transactTime());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportElimination(
const ExecutionReportElimination524 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
setCommonFields(order, msg);
setOrdStatus(order->orderStatus_, msg);
order->leavesQty(msg.cumQty());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportTradeAddendumOutright(
const ExecutionReportTradeAddendumOutright548 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
order->orderId(msg.orderId())
.securityId(msg.securityId())
.lastPx(msg.lastPx().mantissa())
.transactTime(msg.transactTime());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportTradeAddendumSpread(
const ExecutionReportTradeAddendumSpread549 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
order->orderId(msg.orderId())
.securityId(msg.securityId())
.lastPx(msg.lastPx().mantissa())
.transactTime(msg.transactTime());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onExecutionReportTradeAddendumSpreadLeg(
const ExecutionReportTradeAddendumSpreadLeg550 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
if(msg.possRetransFlag())
return;
Order * const order = findByOrderId(msg);
assert(order);
order->orderId(msg.orderId())
.securityId(msg.securityId())
.lastPx(msg.lastPx().mantissa())
.transactTime(msg.transactTime());
Screen::info("Order changed: " + order->toString());
}
void TradingClient::onOrderCancelReject(
const OrderCancelReject535 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onOrderCancelReplaceReject(
const OrderCancelReplaceReject536 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onSecurityDefinitionResponse(
const SecurityDefinitionResponse561 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onMassQuoteAck(
const MassQuoteAck545 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onRequestForQuoteAck(
const RequestForQuoteAck546 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onQuoteCancelAck(
const QuoteCancelAck563& msg,
Session*)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onOrderMassActionReport(
const OrderMassActionReport562& msg,
Session*)
{
Screen::info("Received Order Mass Action Report: ", msg.toString());
Screen::info(
"MassActionScope=",
toStr(msg.massActionScope()));
Screen::info(
"MassActionResponse=",
toStr(msg.massActionResponse()));
if (msg.marketSegmentId(marketSegmentId))
Screen::info(
"MarketSegmentID=",
toStr(marketSegmentId));
}
void TradingClient::onPartyDetailsDefinitionRequestAck(
const PartyDetailsDefinitionRequestAck519 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onPartyDetailsListReport(
const PartyDetailsListReport538 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onExecutionReportPendingCancel(
const Messaging::ExecutionReportPendingCancel564 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
void TradingClient::onExecutionReportPendingReplace(
const Messaging::ExecutionReportPendingReplace565 & msg,
Session *)
{
Screen::info("Message received from counterparty: ", msg.toString());
}
{
}
{
const bool IsPrimarySession = (sn == primarySession_.get());
Screen::info(
"Changing the session role of " + std::string(IsPrimarySession ? "primary" : "backup") + " session to " +
toStr(faultToleranceIndicator) +
" ..");
{
if (sn == backupSession_.get())
{
backupSession_
->inSeqNum(primarySession_->inSeqNum())
.outSeqNum(primarySession_->outSeqNum());
}
else
{
primarySession_
->inSeqNum(backupSession_->inSeqNum())
.outSeqNum(backupSession_->outSeqNum());
}
}
}
{
Screen::info("Session-level error: ", description);
}
{
Screen::info("Session-level warning: ", description);
}
}