OnixS C++ CME iLink 3 Binary Order Entry Handler  1.18.0
API Documentation
Trading Client Sample

An advanced interactive console application to send orders and receive responses.


Source code


CUI.h:

#include "Book.h"
#include <iostream>
#include <string>
#include <vector>
namespace CUI {
// Utility class which provides facilities to notify a user
// about important events like an incoming message receipt.
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);
}
}
static void getInputLocalMktDate(LocalMktDate & value)
{
std::string userInput;
std::getline(std::cin, userInput);
Timestamp timestamp;
if(fromStr(timestamp, userInput, TimestampFormat::YYYYMMDD))
value = timestampToLocalMktDate(timestamp);
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)
{
if (!processTypified(message, MessagePrinter(prefix)))
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();
}
};
// Command execution status represents command execution feedback.
enum CommandExecutionStatus
{
TerminateExecution,
ContinueExecution,
RepeatExecution
};
// Abstraction of the main menu for the application.
// Implemented as a template to simplify command handling.
template <typename Owner>
class Menu
{
public:
// Command, which is invoked on a menu item selection.
typedef void (Owner::*Command)(CommandExecutionStatus*);
// Initializes an empty menu.
explicit Menu(Owner* owner)
: owner_(owner)
{
}
// Utilizes resources.
~Menu()
{
}
// Adds a new menu item to the menu.
Menu& add(const std::string& text, const std::string& commandText, Command command)
{
items_.push_back(Item(text, commandText, command));
return *this;
}
// Process user requests until any command terminates the execution.
void processRequests() const
{
CommandExecutionStatus status = ContinueExecution;
while (TerminateExecution != status)
{
outputItems();
processRequest(&status);
}
}
private:
// Menu item-related attributes.
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;
};
// Instance of the class whose members are invoked as menu commands.
Owner* owner_;
// Menu items.
std::vector<Item> items_;
// Outputs items' names onto the screen.
// Assigns a sequence number to each item for future reference.
void outputItems() const
{
Screen::info("Select operation you want to perform: ");
Screen::outItems(items_);
}
// Invokes command associated with the menu item selected by the user.
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;
// Wait for some timeout to give to complete the command
// and print the corresponding responses to make the output more readable.
Threading::ThisThread::sleep(CommandExecutionTimeout);
}
catch (const std::exception& ex)
{
Screen::info("ERROR: ", ex.what());
}
}
}
};
// Abstraction of a list viewer, which outputs list items on a per-page basis.
// Implemented as a template to abstract from the list items type, which must support
// the ability to return its string presentation through the toString() member.
template <typename Stringable>
class ListViewer
{
public:
typedef typename Samples::Book<Stringable>::EntryList StringableList;
// Outputs list items on the screen.
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;
};
}

Settings.h:

#include <string>
#include <map>
namespace Samples
{
class Settings
{
public:
explicit Settings(const std::string& filePath);
std::string get(const std::string& key) const;
std::string get(const std::string& key, const std::string& defaultValue) const;
std::string getIfAny(const std::string& key) const;
int getAsInt(const std::string& key) const;
int getAsInt(const std::string& key, int defaultValue) const;
bool getAsBool(const std::string& key) const;
bool getAsBool(const std::string& key, bool defaultValue) const;
bool isSet(const std::string& key) const;
private:
typedef std::map<std::string, std::string> Key2ValueMap;
typedef Key2ValueMap::const_iterator Key2ValueMapEntry;
Key2ValueMap map_;
};
}

Settings.cpp:

#include "Settings.h"
namespace
{
void trimSpaces(std::string* str)
{
const char whiteSpace[] = " \t\r";
size_t found = str->find_last_not_of(whiteSpace);
if (std::string::npos == found)
str->resize(0);
else
str->resize(found + 1);
found = str->find_first_not_of(whiteSpace);
if (std::string::npos != found && 0 != found)
str->erase(0, found);
}
int lexicalCompare(const std::string& left, const std::string& right)
{
#if defined(_WIN32)
return _stricmp(left.c_str(), right.c_str());
#else
return strcasecmp(left.c_str(), right.c_str());
#endif
}
}
namespace Samples
{
Settings::Settings(const std::string& filePath)
{
std::ifstream in(filePath.c_str());
if (!in)
{
std::string errReason("Cannot open the settings file '");
errReason += filePath;
errReason += "'";
throw std::domain_error(errReason);
}
std::string line;
while (getline(in, line))
{
const std::string::size_type comment = line.find('#');
if (std::string::npos != comment)
line.resize(comment);
std::string::size_type separator = line.find('=');
if (std::string::npos == separator)
continue;
std::string key = line.substr(0, separator);
trimSpaces(&key);
std::string value = line.substr(separator + 1);
trimSpaces(&value);
map_.insert(make_pair(key, value));
}
}
std::string Settings::get(const std::string& key) const
{
const Key2ValueMapEntry it = map_.find(key);
if (map_.end() == it)
{
std::string errReason("There's no setting '");
errReason += key;
errReason += "' available";
throw std::domain_error(errReason);
}
return it->second;
}
std::string Settings::get(const std::string& key, const std::string& defaultValue) const
{
const Key2ValueMapEntry it = map_.find(key);
return (map_.end() == it) ? defaultValue : it->second;
}
std::string Settings::getIfAny(const std::string& key) const
{
return get(key, std::string());
}
int Settings::getAsInt(const std::string& key) const
{
const std::string value = get(key);
return atoi(value.c_str());
}
int Settings::getAsInt(const std::string& key, int defaultValue) const
{
const std::string value = getIfAny(key);
return value.empty() ? defaultValue : atoi(value.c_str());
}
bool Settings::getAsBool(const std::string& key) const
{
const std::string value = get(key);
return 0 == lexicalCompare("true", value);
}
bool Settings::getAsBool(const std::string& key, bool defaultValue) const
{
const std::string value = getIfAny(key);
return !value.empty() ? 0 == lexicalCompare("true", value) : defaultValue;
}
bool Settings::isSet(const std::string& key) const
{
return map_.count(key) > 0;
}
}

Book.h:

#include <string>
#include <vector>
#include <map>
namespace Samples
{
// Collection of book entries (e.g., orders) currently manipulated by the trading client.
template <typename EntryType>
class Book
{
public:
typedef std::map<std::string, EntryType> BookEntries;
typedef typename BookEntries::iterator EntryIter;
// Adds an entry to the book.
Book& store(const EntryType& entry);
Book& store(const EntryType& entry, const std::string& id);
// Finds an instance of the entry by its identifier.
// If there's no entry available, returns NULL.
EntryType* find(const std::string& id);
typedef std::vector<EntryType*> EntryList;
// Returns a collection of stored book entries.
void getEntries(EntryList & list);
private:
typedef Threading::Mutex Mutex;
typedef Threading::Guard<Threading::Mutex> Guard;
Mutex mutex_;
BookEntries entries_;
};
template <typename EntryType>
Book<EntryType>& Book<EntryType>::store(const EntryType& newEntry)
{
return store(newEntry, newEntry.id());
}
template <typename EntryType>
Book<EntryType>& Book<EntryType>::store(const EntryType& newEntry, const std::string& id)
{
const Guard guard(mutex_);
const std::pair<EntryIter, bool> result = entries_.insert(std::make_pair(id, newEntry));
if (!result.second)
throw std::domain_error("Book already has an entry registered under ID = '" + id + "'.");
return *this;
}
template <typename EntryType>
EntryType* Book<EntryType>::find(const std::string& id)
{
const Guard guard(mutex_);
const EntryIter entry = entries_.find(id);
return entry == entries_.end() ? ONIXS_ILINK3_NULLPTR : &entry->second;
}
template <typename EntryType>
void Book<EntryType>::getEntries(Book<EntryType>::EntryList & list)
{
const Guard guard(mutex_);
for (EntryIter iter = entries_.begin(); iter != entries_.end(); ++iter)
list.push_back(&iter->second);
}
}

Order.h:

#include <string>
namespace Samples
{
struct Order
{
// Initializes an order.
Order();
// Human-readable presentation of the most interesting fields stored in the order.
std::string toString() const;
// Returns a unique order id.
std::string id() const;
// Setters.
Order& cIOrdId(const std::string& value);
Order& orderId(UInt64 value);
Order& price(UInt64 value);
Order& orderQty(UInt32 value);
Order& minQty(UInt32 value);
Order& displayQty(UInt32 value);
Order& leavesQty(UInt32 value);
Order& cumQty(UInt32 value);
Order& securityId(UInt32 value);
Order& side(SideReq::Enum value);
Order& ordType(OrderTypeReq::Enum value);
Order& stopPx(Int64 value);
Order& timeInForce(TimeInForce::Enum value);
Order& expireDate(LocalMktDate value);
Order& orderStatus(const std::string& value);
Order& lastPx(Int64 value);
Order& transactTime(UInt64 value);
std::string cIOrdId_;
UInt64 orderId_;
Int64 price_;
UInt32 orderQty_;
UInt32 minQty_;
UInt32 displayQty_;
UInt32 leavesQty_;
UInt32 cumQty_;
Int32 securityId_;
SideReq::Enum side_;
OrderTypeReq::Enum ordType_;
Int64 stopPx_;
TimeInForce::Enum timeInForce_;
LocalMktDate expireDate_;
std::string orderStatus_;
Int64 lastPx_;
UInt64 transactTime_;
};
}

Order.cpp:

#include "Order.h"
#include "../Common/Helpers.h"
namespace Samples
{
Order::Order()
: cIOrdId_(IdGenerator::newStrId())
, orderId_()
, price_(NullPRICE9::NullMantissa().value())
, orderQty_()
, minQty_(NullUInt32().value())
, displayQty_(NullUInt32().value())
, leavesQty_(NullUInt32().value())
, cumQty_(NullUInt32().value())
, securityId_()
, side_(SideReq::Buy)
, ordType_(OrderTypeReq::Limit)
, stopPx_(NullPRICE9::NullMantissa().value())
, timeInForce_(TimeInForce::Day)
, expireDate_(NullUInt16().value())
, orderStatus_("New")
, lastPx_()
, transactTime_()
{
}
template<typename T>
std::string toStrOptional(T value, T emptyValue)
{
return value == emptyValue ? std::string() : toStr(value);
}
std::string Order::toString() const
{
std::ostringstream builder;
builder
<< "ClOrdID = " << cIOrdId_
<< ", OrderID = " << toStr(orderId_)
<< ", SecurityId = " << toStr(securityId_)
<< ", OrderStatus = " << orderStatus_
<< ", Type = " << toStr(ordType_)
<< ", Price = " << toStr(price_)
<< ", Quantity = " << toStr(orderQty_)
<< ", MinQty = " << toStrOptional(minQty_, NullUInt32().value())
<< ", DisplayQty = " << toStrOptional(displayQty_, NullUInt32().value())
<< ", LeavesQty = " << toStrOptional(leavesQty_, NullUInt32().value())
<< ", CumQty = " << toStrOptional(cumQty_, NullUInt32().value())
<< ", Side = " << toStr(side_)
<< ", StopPx = " << toStrOptional(stopPx_, NullPRICE9::NullMantissa().value())
<< ", LastFillPrice = " << toStr(lastPx_)
<< ", TimeInForce = " << toStr(timeInForce_)
<< ", ExpireDate = " << toStr(localMktDateToTimestamp(expireDate_), TimestampFormat::YYYYMMDD)
<< ", TransactTime = " << Timestamp(transactTime_).toString();
return builder.str();
}
std::string Order::id() const
{
return cIOrdId_;
}
Order& Order::cIOrdId(const std::string& value)
{
cIOrdId_ = value;
return *this;
}
Order& Order::orderId(UInt64 value)
{
orderId_ = value;
return *this;
}
Order& Order::price(UInt64 value)
{
price_ = value;
return *this;
}
Order& Order::orderQty(UInt32 value)
{
orderQty_ = value;
return *this;
}
Order& Order::minQty(UInt32 value)
{
minQty_ = value;
return *this;
}
Order& Order::displayQty(UInt32 value)
{
displayQty_ = value;
return *this;
}
Order& Order::leavesQty(UInt32 value)
{
leavesQty_ = value;
return *this;
}
Order& Order::cumQty(UInt32 value)
{
cumQty_ = value;
return *this;
}
Order& Order::securityId(UInt32 value)
{
securityId_ = value;
return *this;
}
Order& Order::side(SideReq::Enum value)
{
side_ = value;
return *this;
}
Order& Order::ordType(OrderTypeReq::Enum value)
{
ordType_ = value;
return *this;
}
Order& Order::stopPx(Int64 value)
{
stopPx_ = value;
return *this;
}
Order& Order::timeInForce(TimeInForce::Enum value)
{
timeInForce_ = value;
return *this;
}
Order& Order::expireDate(LocalMktDate value)
{
expireDate_ = value;
return *this;
}
Order& Order::orderStatus(const std::string& value)
{
orderStatus_ = value;
return *this;
}
Order& Order::lastPx(Int64 value)
{
lastPx_ = value;
return *this;
}
Order& Order::transactTime(UInt64 value)
{
transactTime_ = value;
return *this;
}
}

MessageFactory.h:

#include "../Common/Helpers.h"
#include "Order.h"
namespace Samples {
// Constructs SBE messages of specific types according to the given parameters.
class MessageFactory
{
public:
explicit MessageFactory(const std::string& sessionId);
// Constructs a reusable NewOrderSingle message according to the given order traits.
NewOrderSingle & getNewOrder(const Order& order) const;
// Constructs a reusable OrderCancelReplaceRequest message for the given order.
OrderCancelReplaceRequest & getModifyRequest(const Order& order) const;
// Constructs a reusable OrderCancelRequest message for the given order.
OrderCancelRequest & getCancelRequest(const Order& order) const;
// Constructs a reusable NewOrderCross message according to the given order traits.
NewOrderCross & getNewOrderCross(const Order& buySideOrder, const Order& sellSideOrder) const;
// Constructs a reusable OrderMassActionRequest message according to the given traits.
OrderMassActionRequest & getOrderMassActionRequest(MassActionScope::Enum scope, const std::string & traits) const;
// Constructs a reusable RequestForQuote message according to the given traits.
RequestForQuote & getRequestForQuote(UInt32 qti, RFQSide::Enum side, Int32 securityId) const;
// Constructs a reusable SecurityDefinitionRequest message.
SecurityDefinitionRequest & getSecurityDefinitionRequest() const;
// Constructs a reusable OrderMassStatusRequest message according to the given traits.
OrderMassStatusRequest & getOrderMassStatusRequest(MassStatusReqTyp::Enum type, const std::string & traits) const;
private:
NewOrderSingle initNewOrder() const;
OrderCancelReplaceRequest initOrderCancelReplaceRequest() const;
OrderCancelRequest initOrderCancelRequest() const;
NewOrderCross initNewOrderCross() const;
OrderMassActionRequest initOrderMassActionRequest() const;
RequestForQuote initRequestForQuote() const;
SecurityDefinitionRequest initSecurityDefinitionRequest() const;
OrderMassStatusRequest initOrderMassStatusRequest() const;
std::string sessionId_;
};
}

MessageFactory.cpp:

#include "../Settings/Defaults.h"
#include "MessageFactory.h"
namespace Samples {
const char Location[] = "GB";
MessageFactory::MessageFactory(const std::string& sessionId)
: sessionId_(sessionId)
{}
NewOrderSingle MessageFactory::initNewOrder() const
{
NewOrderSingle msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Manual)
.setExecutionMode(ExecMode::Aggressive)
.setExecInst(ExecInst());
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_);
if (order.timeInForce_ == TimeInForce::GoodTillDate)
msg->setExpireDate(localMktDateToTimestamp(order.expireDate_));
return msg;
}
OrderCancelReplaceRequest MessageFactory::initOrderCancelReplaceRequest() const
{
OrderCancelReplaceRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setSide(SideReq::Buy)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Manual)
.setExecutionMode(ExecMode::Aggressive)
.setExecInst(ExecInst())
.setOfmOverride(OFMOverrideReq::Disabled);
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_);
if (order.timeInForce_ == TimeInForce::GoodTillDate)
msg->setExpireDate(localMktDateToTimestamp(order.expireDate_));
return msg;
}
OrderCancelRequest MessageFactory::initOrderCancelRequest() const
{
OrderCancelRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setSide(SideReq::Buy)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Manual);
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)
.setManualOrderIndicator(ManualOrdIndReq::Manual);
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())
.setTransBkdTime(UtcWatch::now().sinceEpoch());
NewOrderCross544::Sides noSides = msg->sides(2);
NewOrderCross544::SidesEntry buyEntry = noSides[0];
NewOrderCross544::SidesEntry sellEntry = noSides[1];
buyEntry.setClOrdId(buySideOrder.cIOrdId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setOrderQty(buySideOrder.orderQty_)
.setSide(buySideOrder.side_)
.setSideTimeInForce(SideTimeInForce::Day);
sellEntry.setClOrdId(sellSideOrder.cIOrdId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setOrderQty(sellSideOrder.orderQty_)
.setSide(sellSideOrder.side_)
.setSideTimeInForce(SideTimeInForce::Day);
return msg;
}
OrderMassActionRequest MessageFactory::initOrderMassActionRequest() const
{
OrderMassActionRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Automated);
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)
.setManualOrderIndicator(ManualOrdIndReq::Automated)
.setQuoteType(QuoteTyp::Tradeable);
return msg;
}
RequestForQuote & MessageFactory::getRequestForQuote(UInt32 qti, RFQSide::Enum side, Int32 securityId) const
{
static RequestForQuote msg = initRequestForQuote();
msg->setQuoteReqId(IdGenerator::newIntId());
RequestForQuote543::RelatedSym noRelatedSym = msg->relatedSym(1);
noRelatedSym[0].setOrderQty(qti)
.setSide(side)
.setSecurityId(securityId);
return msg;
}
SecurityDefinitionRequest MessageFactory::initSecurityDefinitionRequest() const
{
SecurityDefinitionRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Automated)
.setSecuritySubType("COMBO");
return msg;
}
SecurityDefinitionRequest & MessageFactory::getSecurityDefinitionRequest() const
{
static SecurityDefinitionRequest msg = initSecurityDefinitionRequest();
msg->setSecurityReqId(IdGenerator::newIntId());
SecurityDefinitionRequest560::Legs noLegs = msg->legs(2);
noLegs[0].setLegSecurityId(DefaultSecurityId)
.setLegSide(SideReq::Buy)
.setLegOptionDelta(Decimal32NULL(1, -1))
.setLegPrice(PRICE9(DefaultPriceMantissa))
.setLegRatioQty(1);
noLegs[1].setLegSecurityId(DefaultSecurityId + 1)
.setLegSide(SideReq::Sell)
.setLegOptionDelta(Decimal32NULL(3, -1))
.setLegPrice(PRICE9(DefaultPriceMantissa))
.setLegRatioQty(1);
return msg;
}
OrderMassStatusRequest MessageFactory::initOrderMassStatusRequest() const
{
OrderMassStatusRequest msg;
msg->setSenderId(sessionId_)
.setPartyDetailsListReqId(PartyDetailsListReqID)
.setLocation(Location)
.setManualOrderIndicator(ManualOrdIndReq::Automated);
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;
}
}

TradingClient.h:

#include "MessageFactory.h"
#include "Settings.h"
#include "CUI.h"
#include "Order.h"
#include "Book.h"
namespace Samples
{
// Sample console-based trading client which sends orders to counterparty
// allows modifying and canceling them. It also handles all other issues
// like handling messages from the counterparty.
class TradingClient ONIXS_ILINK3_FINAL : private SessionListener
{
public:
// Initializes the client with a given behavior.
explicit TradingClient(const Settings& settings);
// Performs trading by processing user requests.
void run();
private:
// Set of control parameters that affect trading.
const Settings& settings_;
// Primary iLink3 session with the counterparty.
PtrTraits<Session>::UniquePtr primarySession_;
// Backup iLink3 session with the counterparty.
PtrTraits<Session>::UniquePtr backupSession_;
bool connected_;
// Store of orders sent to the counterparty.
Book<Order> orderBook_;
typedef Book<Order>::EntryList OrderList;
// Creates SBE messages to be sent to the counterparty.
MessageFactory messageFactory_;
// UI-specific part of the trading client.
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*);
// Trading-specific routines.
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)
{
const std::string clOrdId = Messaging::toStr(report.clOrdId());
Order* const msg = orderBook_.find(clOrdId);
if (!msg)
{
// The sample is implementing not all message chain processing.
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))
order->expireDate_ = timestampToLocalMktDate(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();
// Failover-specific part.
bool failover_;
// Listener part.
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;
};
}

TradingClient.cpp:

#include "../Settings/Defaults.h"
#include "TradingClient.h"
namespace Samples
{
Session* createSession(
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);
return new Session(settings, atoi(segment.c_str()), 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()
{
// 1. Creates session according to the application settings.
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);
// 2. If FaultTolerance is used, then create the backup session.
if (failover_)
{
Screen::info("Creating the backup iLink3 Session..");
backupSession_.reset(
createSession(settings, settings_.get("MarketSegment"), this, primarySession_->uuid(), "Backup"));
backupSession_->faultToleranceIndicator(FTI::Backup);
}
}
// Menu actions
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 the FaultTolerance is used and the primary iLink3 session is out of service, then we try to conne
if (!failover_)
throw;
}
// 3. If the FaultTolerance is used, then we connect to the backup iLink3 session to activate the fail-over logic.
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_)
{
if (ONIXS_ILINK3_NULLPTR != backupSession_.get() && backupSession_->state() != SessionStateId::Disconnected)
{
Screen::info("Disconnecting from backup counterparty.. ");
backupSession_->disconnect();
}
}
if (ONIXS_ILINK3_NULLPTR != primarySession_.get() && primarySession_->state() != SessionStateId::Disconnected)
{
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: ",
primarySession_->toString() + ", State=" + SessionStateId::toString(primarySession_->state()) +
".");
if (failover_)
Screen::info("Backup iLink3 session: ",
backupSession_->toString() + ", State=" + SessionStateId::toString(backupSession_->state()) +
".");
}
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): ");
const MassActionScope::Enum massActionScope = Screen::getInput<MassActionScope::Enum>(MassActionScope::Instrument);
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): ");
const RFQSide::Enum side = Screen::getInput<RFQSide::Enum>(RFQSide::Buy);
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 : ");
const MassStatusReqTyp::Enum massStatusReqType = Screen::getInput<MassStatusReqTyp::Enum>(
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);
// Changing OrderQty
Screen::info("Enter new OrderQty (or Enter to skip): ");
Screen::getInput(order->orderQty_, order->orderQty_);
// Changing Price
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_)
.side(SideReq::Sell);
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 (ONIXS_ILINK3_NULLPTR != primarySession_.get() && primarySession_->state() == SessionStateId::Disconnected)
{
if(primarySession_->negotiated())
primarySession_->reset(false);
}
else
Screen::info("Operation can be performed only when the sessions are disconnected");
if (failover_ && backupSession_->state() == SessionStateId::Disconnected && backupSession_->negotiated())
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::getInputChar(order.ordType_, OrderTypeReq::Limit);
if (order.ordType_ == OrderTypeReq::Limit || order.ordType_ == OrderTypeReq::StopLimit)
{
Screen::info("Enter Price mantissa (default = " + toStr(DefaultPriceMantissa) + "): ");
Screen::getInput(order.price_, DefaultPriceMantissa);
}
if (order.ordType_ == OrderTypeReq::StopLimit || order.ordType_ == OrderTypeReq::StopwithProtection)
{
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::getInput(order.timeInForce_, TimeInForce::Day);
if (order.timeInForce_ == TimeInForce::GoodTillDate)
{
Screen::info("Enter Expire date YYYYMMDD: ");
Screen::getInputLocalMktDate(order.expireDate_);
}
Screen::info("Enter Side (1 - Buy (default), 2 - Sell): ");
Screen::getInput(order.side_, SideReq::Buy);
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());
UInt16 refTagId = UInt16();
Screen::info("Reject reason : ", BusinessRejectReason::toString(msg.businessRejectReason())
+ (msg.refTagId(refTagId) ? ", refTagId=" + toStr(refTagId) : std::string()));
// See https://www.cmegroup.com/confluence/display/EPICSANDBOX/iLink+3+Business+Reject:
// If the tag 45 value is NULL, the client system does not need to increment
// the next expected sequence number of the next business message to be sent.
UInt32 refSeqNum = UInt32();
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());
}
NotAppliedAction::Enum TradingClient::onNotApplied(const Messaging::NotApplied513 & msg, Session * sn)
{
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);
order->orderStatus(OrderStatus::toString(msg.ordStatus()))
.leavesQty(msg.leavesQty())
.cumQty(msg.cumQty());
Screen::info("Order changed: " + order->toString());
BooleanNULL::Enum lastRptRequested = BooleanNULL::Enum();
if (msg.lastRptRequested(lastRptRequested))
Screen::info("LastRptRequested = " + toStr(lastRptRequested));
UInt64 massStatusReqId = UInt64();
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);
order->orderStatus(OrdStatusTrd::toString(msg.ordStatus()))
.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);
order->orderStatus(OrdStatusTrd::toString(msg.ordStatus()))
.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->orderStatus(OrdStatusTrd::toString(msg.ordStatus()));
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())
.orderStatus(OrdStatusTrdCxl::toString(msg.ordStatus()))
.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())
.orderStatus(OrdStatusTrdCxl::toString(msg.ordStatus()))
.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())
.orderStatus(OrdStatusTrdCxl::toString(msg.ordStatus()))
.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()));
UInt8 marketSegmentId = UInt8();
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());
}
void TradingClient::onStateChange(SessionStateId::Enum newState, SessionStateId::Enum /*prevState*/, Session *)
{
Screen::info("Session state changed to ", SessionStateId::toString(newState));
connected_ = (newState == SessionStateId::Established);
}
void TradingClient::onFailover(FTI::Enum faultToleranceIndicator, Session * sn)
{
const bool IsPrimarySession = (sn == primarySession_.get());
Screen::info(
"Changing the session role of " + std::string(IsPrimarySession ? "primary" : "backup") + " session to " +
toStr(faultToleranceIndicator) + " ..");
if (faultToleranceIndicator == FTI::Primary)
{
if (sn == backupSession_.get())
{
backupSession_
->inSeqNum(primarySession_->inSeqNum())
.outSeqNum(primarySession_->outSeqNum());
primarySession_->faultToleranceIndicator(FTI::Backup);
}
else
{
primarySession_
->inSeqNum(backupSession_->inSeqNum())
.outSeqNum(backupSession_->outSeqNum());
backupSession_->faultToleranceIndicator(FTI::Backup);
}
}
}
void TradingClient::onError(SessionErrorReason::Enum, const std::string & description, Session *, Messaging::SbeMessage)
{
Screen::info("Session-level error: ", description);
}
void TradingClient::onWarning(SessionWarningReason::Enum, const std::string & description, Session *, Messaging::SbeMessage)
{
Screen::info("Session-level warning: ", description);
}
}

Main.cpp:

#include "Settings.h"
#include "TradingClient.h"
using namespace Samples;
namespace
{
void ensureSettingsAreUpToDate(const Settings& appSettings)
{
const std::string upToDateParameter("settingsAreUpToDate");
if (!appSettings.getAsBool(upToDateParameter))
{
std::string errReason("Please update the configuration file (settings.ini) with values received from CME Support Team and set the '");
errReason += upToDateParameter;
errReason += "' configuration parameter to 'true'";
throw std::domain_error(errReason);
}
}
}
int main(int argc, char * argv[])
{
try
{
std::cout << "CME iLink 3 Trading Client sample." << std::endl
<< "Usage: " << argv[0] << " {ConfigurationFileName}" << std::endl;
std::string configurationFileName = (argc > 1) ? argv[1] : "settings.ini";
Settings settings(configurationFileName);
ensureSettingsAreUpToDate(settings);
TradingClient client(settings);
client.run();
}
catch (const std::exception& ex)
{
std::cerr << std::endl << "Error: " << ex.what() << "." << std::endl;
return 1;
}
return 0;
}