OnixS C++ B3 BOE Binary Order Entry 1.4.0
Users' manual and API documentation
Loading...
Searching...
No Matches
Getting Started Sample

This sample shows how to connect to the B3 BOE Gateway or the local Gateway emulator.

When the session is established, the NewOrderSingle SBE message is sent to the counterparty.

#include "../Common/Helpers.h"
#include "../Common/Listener.h"
#include "../Settings/Defaults.h"
using namespace Samples;
Session* createSession(const SessionSettings& settings, SessionListener* listener)
{
return new Session(settings, listener);
}
int main(int argc, char * argv[])
{
clog << "B3 BOE Getting Started Sample." << endl << endl;
MarketSegmentID marketSegmentId = DefaultMarketSegmentId;
string host = "127.0.0.1";
Port port = 62000;
bool useEmulator = false;
if (argc < 4)
{
#if defined(ONIXS_B3_BOE_HAS_GATEWAY_EMULATOR)
useEmulator = true;
#else
std::cerr << "usage: [MarketSegmentId] [Host] [Port] (SecurityId) (PriceMantissa)" << std::endl;
return 1;
#endif
}
else
{
marketSegmentId = atoi(argv[1]);
host = argv[2];
port = atoi(argv[3]);
}
const SecurityID securityId = argc > 4 ? fromStr<SecurityID>(argv[4]) : DefaultSecurityId;
const Int64 priceMantissa = argc > 5 ? fromStr<Int64>(argv[5]) : DefaultPriceMantissa;
try
{
SignalHelper::manageLinuxSignals();
const SessionSettings settings = fillSettings(useEmulator);
#if defined(ONIXS_B3_BOE_HAS_GATEWAY_EMULATOR)
std::unique_ptr<GatewayEmulatorThread> gateway;
if (useEmulator)
gateway.reset(new GatewayEmulatorThread(settings.licenseStores(), host, port));
#endif
Listener listener;
ScopedPtr<Session> session(createSession(settings, &listener));
NewOrderSingle order;
Helper::setOrderFields(order, marketSegmentId, securityId, DefaultAccount, priceMantissa);
session
->connect(host, port)
.send(order);
clog << "\nThe order was sent." << endl;
Helper::waitUntilEnterKey("disconnect the session and terminate the application");
session->disconnect();
}
catch(const std::exception & ex)
{
cerr << "\nEXCEPTION: " << ex.what() << endl;
return 1;
}
return 0;
}

Helpers.h

#include "../Settings/Defaults.h"
#include <string>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <fstream>
#ifdef _WIN32
#include <conio.h>
#else
#include <pthread.h>
#include <csignal>
#include <cstdlib>
#include <vector>
#include <sys/poll.h>
#endif
#if defined(ONIXS_B3_BOE_HAS_GATEWAY_EMULATOR)
#include <thread>
#include <future>
#include <functional>
#include <chrono>
#endif
namespace Samples
{
using namespace OnixS::B3::BOE::Messaging;
typedef MessageHolder<SimpleNewOrder100> SimpleOrder;
typedef MessageHolder<NewOrderSingle102> NewOrderSingle;
typedef MessageHolder<OrderCancelReplaceRequest104> OrderCancelReplaceRequest;
typedef MessageHolder<OrderCancelRequest105> OrderCancelRequest;
typedef MessageHolder<OrderMassActionRequest701> OrderMassActionRequest;
typedef MessageHolder<QuoteRequest401> RequestForQuote;
typedef MessageHolder<SecurityDefinitionRequest300> SecurityDefinitionRequest;
typedef MessageHolder<NewOrderCross106> NewOrderCross;
class Helper
{
public:
static void setOrderFields(NewOrderSingle & order, MarketSegmentID marketSegmentId, SecurityID securityId, Messaging::Account account, Int64 priceMantissa) ONIXS_B3_BOE_NOTHROW
{
InboundBusinessHeader & header = order->businessHeader();
header.setMarketSegmentId(marketSegmentId);
order->setOrdTagId(100)
.setMmProtectionReset(Boolean::FalseValue)
.setClOrdId(1)
.setAccount(account)
.setSenderLocation("DMA")
.setEnteringTrader("TADA")
.setSelfTradePreventionInstruction(SelfTradePreventionInstruction::None)
.setSecurityId(securityId)
.setSide(Side::Buy)
.setOrdType(OrdType::Limit)
.setTimeInForce(TimeInForce::Day)
.setRoutingInstructionToNull()
.setOrderQty(100)
.setPrice(PriceOptional(priceMantissa))
.setInvestorIdToNull()
.setMemo("VALE3 1714479423613")
.setDeskId("1");
InvestorID iid;
iid.setPrefix(300);
iid.setDocument(123456);
order->setInvestorId(iid);
}
static void waitUntilEnterKey(const std::string& message)
{
std::clog << "\nPress the ENTER key to " << message << ".." << std::endl;
#ifdef _WIN32
_getch();
#else
getchar();
#endif
}
static bool keyPressed()
{
#ifdef __linux__
pollfd pfd = { 0, POLLIN, 0 };
return poll(&pfd, 1, 0) != 0;
#else
return _kbhit() != 0;
#endif
}
};
template <typename T>
T fromStr(const std::string & s)
{
std::istringstream ss(s);
T result = T();
ss >> result;
return result;
}
class IdGenerator
{
public:
static std::string newStrId()
{
static UInt64 idCounter = 0;
const size_t startOfTime = 9;
std::string timestamp = toStr(UtcWatch::now(), TimestampFormat::YYYYMMDDHHMMSSmsec).substr(startOfTime);
std::string id;
id += timestamp[0];
id += timestamp[1];
id += timestamp[3];
id += timestamp[4];
id += timestamp[6];
id += timestamp[7];
id += timestamp[9];
id += timestamp[10];
id += toStr(++idCounter);
return id;
}
static UInt64 newId()
{
return UtcWatch::now().time().nanoseconds();
}
};
#ifndef _WIN32
// The code below illustrates how to manage signals:
// - Mask signals in all threads;
// - Start a separate thread to catch signals;
class SignalHelper
{
public:
typedef std::vector<int> SuppressedSignals;
static void manageLinuxSignals()
{
SuppressedSignals suppressedSignals;
// Add signals we are waiting for.
suppressedSignals.push_back(SIGPIPE);
pthread_t signalThreadId;
int status;
// Mask signals in the primary thread.
// Child threads will inherit this signal mask.
sigemptyset(&signalSet());
for (SuppressedSignals::const_iterator i = suppressedSignals.begin(),
e = suppressedSignals.end();
i != e; ++i)
sigaddset(&signalSet(), *i);
status = pthread_sigmask(SIG_BLOCK, &signalSet(), ONIXS_B3_BOE_NULLPTR);
if (status != 0)
errorAbort(status, "Set signal mask");
// Create the sigwait thread.
status = pthread_create(&signalThreadId, ONIXS_B3_BOE_NULLPTR, signalWaiter, ONIXS_B3_BOE_NULLPTR);
if (status != 0)
errorAbort(status, "Create signalWaiter");
}
private:
static void errorAbort(int status, const char* reason)
{
printf("Aborted due to status %d: %s\n", status, reason ? reason : "no error message");
exit(1);
}
static void* signalWaiter(void* /*arg*/)
{
int signalNumber;
while (true)
{
sigwait(&signalSet(), &signalNumber);
printf("Signal %d received and suppressed.\n", signalNumber);
}
}
static sigset_t& signalSet()
{
static sigset_t set;
return set;
}
};
#else
struct SignalHelper
{
static void manageLinuxSignals(){}
};
#endif
#if defined(ONIXS_B3_BOE_HAS_GATEWAY_EMULATOR)
class GatewayListener : public Testing::ClientMessageListener
{
public:
void onNewOrderSingle(const NewOrderSingle102& order, Testing::Gateway* gateway) override
{
updateReport(order);
gateway->send(report_, ++reportsCounter_);
gateway->outSeqNum(reportsCounter_ + 1);
}
protected:
void updateReport(const NewOrderSingle102& order)
{
OutboundBusinessHeader & header = report_->businessHeader();
EventIndicator eventIndicator = header.eventIndicator();
eventIndicator.setPossResend(false);
header.setEventIndicator(eventIndicator);
OutboundBusinessHeader::SendingTime sendingTime;
sendingTime.setTime(UtcWatch::now().sinceEpoch());
header.setSendingTime(sendingTime);
report_->setOrdTagId(1)
.setMmProtectionResetToNull()
.setClOrdId(1714479417808)
.setAccount(1529)
.setSecurityId(200000163669)
.setSide(Side::Buy)
.setOrdType(OrdType::Limit)
.setTimeInForce(order.timeInForce())
.setOrderQty(100)
.setPrice(PriceOptional(200000))
.setInvestorIdToNull()
.setMemo("VALE3 1714479416336")
.setExecId(800422000000001091)
.setTransactTime(UTCTimestampNanos(1714479417836000000))
.setOrdStatus(OrdStatus::New)
.setSecondaryOrderId(804604488)
.setOrderId(8047407153)
.setTradeDate(Timestamp::fromStr("20240430-00:00:00.000000000", TimestampFormat::YYYYMMDDHHMMSSnsec))
.setWorkingIndicator(Boolean::FalseValue);
if (order.price(price))
report_->setPrice(price);
else
report_->setPrice(PriceOptional(DefaultPriceMantissa));
}
MessageHolder<ExecutionReportNew200> report_;
UInt32 reportsCounter_{ 0 };
};
class GatewayEmulatorThread
{
public:
GatewayEmulatorThread(const SessionSettings::LicenseStores& licenseStores, const std::string & host, Port port, Testing::ClientMessageListener * clientMessageListener = nullptr,
const std::chrono::seconds& acceptTimeout = std::chrono::seconds(10), const std::chrono::seconds& sendReceiveTimeout = std::chrono::seconds(10))
: gateway_(licenseStores, port, host.c_str(), acceptTimeout, sendReceiveTimeout)
, clientMessageListener_(clientMessageListener)
{
std::promise<void> emulatorTaskPromise;
emulatorTaskDone_ = emulatorTaskPromise.get_future();
std::thread(
std::bind(
[&](std::promise<void>& p)
{
try
{
if(clientMessageListener_)
{
gateway_.run(*clientMessageListener_);
}
else
{
GatewayListener clientMessageListener;
gateway_.run(clientMessageListener);
}
p.set_value();
}
catch (const std::exception& ex)
{
std::cerr << "Exception in Emulator's thread: " << ex.what() << '.' << std::endl;
p.set_exception(
std::current_exception());
}
catch (...)
{
std::cerr << "UNKNOWN Exception in Emulator's thread." << std::endl;
p.set_exception(
std::current_exception());
}
},
std::move(emulatorTaskPromise)))
.detach();
}
~GatewayEmulatorThread()
{
if(emulatorTaskDone_.valid())
emulatorTaskDone_.wait_for(std::chrono::seconds(10));
}
void wait(std::chrono::seconds timeout = std::chrono::seconds(10)) {
if(emulatorTaskDone_.valid()) {
std::future<void> f = std::move(emulatorTaskDone_);
f.wait_for(timeout);
f.get();
}
}
private:
Testing::Gateway gateway_;
Testing::ClientMessageListener * clientMessageListener_;
std::future<void> emulatorTaskDone_;
};
#endif
template <typename Object>
class ScopedPtr
{
public:
explicit ScopedPtr(Object* obj) ONIXS_B3_BOE_NOTHROW
: obj_(obj)
{
}
~ScopedPtr()
{
delete obj_;
}
Object* operator->() const ONIXS_B3_BOE_NOTHROW
{
assert(ONIXS_B3_BOE_NULLPTR != obj_);
return obj_;
}
Object& operator*() const ONIXS_B3_BOE_NOTHROW
{
assert(ONIXS_B3_BOE_NULLPTR != obj_);
return *obj_;
}
private:
Object * const obj_;
ScopedPtr(const ScopedPtr&);
ScopedPtr& operator =(const ScopedPtr&);
};
inline
SessionSettings fillSettings(bool useEmulator = false)
{
SessionSettings settings;
const std::string settingsFilename("settings.ini");
std::ifstream settingsFile(settingsFilename.c_str());
if (settingsFile)
{
settingsFile.close();
settings.load(settingsFilename);
}
else
{
settings
.licenseStore("../../license")
if(useEmulator)
settings
.sessionId(100000121)
.enteringFirm(900)
.accessKey("AccessKey")
.tradingSystemName("OnixS 1");
else
settings
.sessionId(100000121 /* "Value Received From B3" */)
.accessKey("Value Received From B3")
.enteringFirm(900 /* "Value Received From B3" */)
.tradingSystemName("OnixS 1");
}
if(useEmulator)
settings.keepAliveInterval(5000).reconnectAttempts(0);
return settings;
}
inline void setPriorityAndPolicy(OnixS::B3::BOE::Session* session = ONIXS_B3_BOE_NULLPTR)
{
#ifdef _WIN32
OnixS::B3::BOE::Threading::ThisThread::priority(THREAD_PRIORITY_ABOVE_NORMAL);
if(session)
session->receivingThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
#else
const int policy = SCHED_RR;
try
{
if(session)
session->receivingThreadPolicy(policy);
}
catch (const std::exception&)
{
std::cerr << "\nWARNING: Cannot change the scheduling policy to " << policy <<
", it requires root permissions, so you either have to be root or run it with sudo." << std::endl;
}
#endif
}
}

Listener.h

#include <functional>
namespace Samples
{
using namespace OnixS::B3::BOE;
using namespace OnixS::B3::BOE::Messaging;
struct MessagePrinter
{
template <typename MessageType>
void operator()(const MessageType& msg) const
{
std::clog << msg << std::endl;
}
static void printMsg(const Messaging::SbeMessage msg)
{
if (!processTypified(msg, MessagePrinter()))
std::clog << "Unknown message type";
}
};
class Listener : public SessionListener
{
public:
void onMessageSending(char* bytes, size_t size, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nOutbound message:\n";
MessagePrinter::printMsg(SbeMessage(bytes, static_cast<Messaging::MessageSize>(size)));
}
void onBusinessMessageReject(const BusinessMessageReject206& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl << "\tReject reason: " << msg.businessRejectReason() << std::endl;
}
void onNegotiateResponse(const NegotiateResponse2& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onNegotiateReject(const NegotiateReject3& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onEstablishAck(const EstablishAck5& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onEstablishReject(const EstablishReject6& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onSequence(const Sequence9& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n"
<< msg << std::endl;
}
void onTerminate(const Terminate7& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onRetransmitReject(const RetransmitReject14& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onRetransmission(const Retransmission13& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onNotApplied(const NotApplied8& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportNew(const ExecutionReportNew200& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportModify(const ExecutionReportModify201& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportCancel(const ExecutionReportCancel202& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
/*void onExecutionReportStatus(const ExecutionReportStatus532& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportTradeOutright(const ExecutionReportTradeOutright525& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportTradeSpread(const ExecutionReportTradeSpread526& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportTradeSpreadLeg(const ExecutionReportTradeSpreadLeg527& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportElimination(const ExecutionReportElimination524& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}*/
void onExecutionReportReject(const ExecutionReportReject204& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
/*void onExecutionReportTradeAddendumOutright(const ExecutionReportTradeAddendumOutright548& msg, Session* ) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportTradeAddendumSpread(const ExecutionReportTradeAddendumSpread549& msg, Session* ) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportTradeAddendumSpreadLeg(const ExecutionReportTradeAddendumSpreadLeg550& msg, Session* ) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onOrderCancelReject(const OrderCancelReject535& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onOrderCancelReplaceReject(const OrderCancelReplaceReject536& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}*/
void onSecurityDefinitionResponse(const SecurityDefinitionResponse301& msg, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
/*void onMassQuoteAck(const MassQuoteAck545& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onRequestForQuoteAck(const RequestForQuoteAck546& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onQuoteCancelAck(const QuoteCancelAck563& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onOrderMassActionReport(const OrderMassActionReport562& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onPartyDetailsDefinitionRequestAck(const PartyDetailsDefinitionRequestAck519& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onPartyDetailsListReport(const PartyDetailsListReport538& msg, Session*) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportPendingCancel(const Messaging::ExecutionReportPendingCancel564& msg, Session *) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}
void onExecutionReportPendingReplace(const Messaging::ExecutionReportPendingReplace565& msg, Session *) ONIXS_B3_BOE_OVERRIDE
{
std::clog << "\nReceived:\n" << msg << std::endl;
}*/
void onStateChange(SessionStateId::Enum newState, SessionStateId::Enum prevState, Session* /*sn*/) ONIXS_B3_BOE_OVERRIDE
{
std::clog
<< "\nSession's state is changed, prevState="
<< SessionStateId::toString(prevState)
<< ", newState="
<< SessionStateId::toString(newState)
<< std::endl;
}
void onError(
SessionErrorReason::Enum /*reason*/, const std::string& description, Session* /*sn*/, Messaging::SbeMessage msg) ONIXS_B3_BOE_OVERRIDE
{
std::cerr << "\nSession-level error: " << description;
if(msg.valid())
{
std::cerr << ",\nCaused by the message: ";
MessagePrinter::printMsg(msg);
}
std::cerr << std::endl;
}
void onWarning(
SessionWarningReason::Enum /*reason*/, const std::string& description, Session* /*sn*/, Messaging::SbeMessage msg) ONIXS_B3_BOE_OVERRIDE
{
std::cerr << "\nSession-level warning: " << description;
if(msg.valid())
{
std::cerr << ",\nCaused by the message: ";
MessagePrinter::printMsg(msg);
}
std::cerr << std::endl;
}
};
}

Defaults.h

namespace Samples
{
using namespace OnixS::B3::BOE;
const SecurityID DefaultSecurityId = 100000180319;
const Messaging::Int64 DefaultPriceMantissa = PriceOptional(200000).mantissa();
const MarketSegmentID DefaultMarketSegmentId = 80;
const Account DefaultAccount = 10101;
};