OnixS C++ FIX Engine 4.14.0
Users' manual and API documentation
Loading...
Searching...
No Matches
Sell Side Sample

This sample waits for incoming connections on the configured port (acts as a FIX Acceptor). If the incoming application-level message is SingleOrder - New then the ExecutionReport message is sent to the counterparty. Otherwise the Email message is sent back.

Source code

Listener.h

class Listener : public OnixS::FIX::ISessionListener
{
public:
Listener();
OnixS::Threading::Semaphore & completionEvent();
bool failed() const;
void onInboundApplicationMsg(OnixS::FIX::Message & msg, OnixS::FIX::Session * sn) final;
void onInboundSessionMsg(OnixS::FIX::Message & msg, OnixS::FIX::Session * sn) final;
void onStateChange(OnixS::FIX::SessionState::Enum newState, OnixS::FIX::SessionState::Enum prevState, OnixS::FIX::Session * sn) final;
void onError(OnixS::FIX::ErrorReason::Enum reason, const std::string & description, OnixS::FIX::Session * sn) final;
void onWarning(OnixS::FIX::WarningReason::Enum reason, const std::string & description, OnixS::FIX::Session * sn) final;
private:
enum SessionActivity
{
SessionNotEstablished,
SessionEstablished,
SessionConnectionCompleted
};
void recordFailure();
int ordersCounter_;
mutable OnixS::Threading::Mutex failureMutex_;
bool failed_;
SessionActivity sessionActivity_;
OnixS::Threading::Semaphore sessionDisconnected_;
};

Listener.cpp

#include "Listener.h"
#include <OnixS/FIXEngine/FIX/FIX44.h>
#include <memory>
#include "../../Common/Settings.h"
#include "../../Common/Helpers.h"
using namespace Settings;
using namespace OnixS::FIX;
using namespace OnixS::FIX::FIX44;
using namespace OnixS::FIX::FIX44::Values;
Listener::Listener() :
ordersCounter_(0),
failed_(false),
sessionActivity_(SessionNotEstablished),
sessionDisconnected_(0)
{}
bool Listener::failed() const
{
OnixS::Threading::MutexGuard guard(failureMutex_);
return failed_;
}
void Listener::recordFailure()
{
OnixS::Threading::MutexGuard guard(failureMutex_);
failed_ = true;
}
OnixS::Threading::Semaphore & Listener::completionEvent()
{
return sessionDisconnected_;
}
void Listener::onInboundApplicationMsg(Message & msg, Session * sn)
{
std::clog << "\nIncoming application-level message:\n" << msg << std::endl;
if(msg.type() == MsgType::NewOrderSingle)
std::clog << "SellSide received NewOrderSingle." << std::endl;
try {
std::unique_ptr<Message> reply;
if(msg.type() == MsgType::NewOrderSingle) { // New Order - Single
const Message & order = msg;
reply.reset(new Message(MsgType::ExecutionReport, FixProtocolVersion));
reply->set(Tags::OrderID, order.get(Tags::ClOrdID).toString());
constexpr size_t ExecIdSize = 128;
char execID[ExecIdSize];
xsnprintf(execID, ExecIdSize - 1, "ExecID_%d", ++ordersCounter_);
reply->set(Tags::ExecID, execID)
.set(Tags::ExecType, "0")
.set(Tags::ExecTransType, "0") // New
.set(Tags::OrdStatus, "0") // New
.set(Tags::Symbol, order.get(Tags::Symbol).toString())
.set(Tags::Side, order.get(Tags::Side).toString())
.set(Tags::OrderQty, order.get(Tags::OrderQty).toString())
.set(Tags::CumQty, order.get(Tags::OrderQty).toString())
.set(Tags::AvgPx, 100.0)
.set(Tags::LastPx, 0)
.set(Tags::LeavesQty, order.get(Tags::OrderQty).toString());
}
else {
reply.reset(new Message(MsgType::Email, FixProtocolVersion));
reply->set(Tags::EmailType, 0);
Group group = reply->setGroup(Tags::NoLinesOfText, 1);
group[0].set(Tags::Text, "The message with MsgType=" + msg.type().toString() + " was received");
}
if(reply) {
sn->send(reply.get());
std::clog << "\nSent to the counterparty:\n" << *reply << std::endl;
if(msg.type() == MsgType::NewOrderSingle)
std::clog << "Sent ExecutionReport." << std::endl;
}
}
catch(const std::exception & ex) {
recordFailure();
sessionDisconnected_.release();
std::clog << "Exception during the processing of incoming message: " << ex.what() << std::endl;
}
}
void Listener::onInboundSessionMsg(Message & msg, Session * )
{
std::clog << "\nIncoming session-level message:\n" << msg << std::endl;
if(msg.type() == MsgType::Logon)
std::clog << "SellSide received Logon." << std::endl;
else if(msg.type() == MsgType::Logout)
std::clog << "SellSide received Logout." << std::endl;
}
void Listener::onStateChange(SessionState::Enum newState, SessionState::Enum prevState,
Session * )
{
std::clog << "\nSession's state is changed, prevState=" << SessionState::toString(prevState)
<< ", newState=" << SessionState::toString(newState) << std::endl;
if(newState == SessionState::Active)
{
sessionActivity_ = SessionEstablished;
return;
}
if(sessionActivity_ != SessionEstablished)
return;
// After a graceful peer Logout, an acceptor returns to LoginInProgress to await another Logon.
if(newState != SessionState::Disconnected &&
!(prevState == SessionState::Active && newState == SessionState::LoginInProgress))
return;
sessionActivity_ = SessionConnectionCompleted;
sessionDisconnected_.release();
}
void Listener::onError(ErrorReason::Enum , const std::string & description, Session * )
{
recordFailure();
sessionDisconnected_.release();
std::cerr << "\nSession-level error:" << description << std::endl;
}
void Listener::onWarning(WarningReason::Enum , const std::string & description,
Session * )
{
std::cerr << "\nSession-level warning:" << description << std::endl;
}

SellSide.cpp

#include "Listener.h"
#include "../../Common/Helpers.h"
#include "../../Common/SampleArguments.h"
#include "../../Common/Settings.h"
using namespace Settings;
using namespace OnixS::FIX;
// Uncomment if you'd like to test SSL feature.
//#define SSL_ENCRYPTION 1
namespace {
class MyEngineListener : public OnixS::FIX::IEngineListener
{
public:
explicit MyEngineListener(OnixS::Threading::Semaphore & completionEvent) :
completionEvent_(completionEvent),
failed_(false)
{
}
bool failed() const
{
OnixS::Threading::MutexGuard guard(failureMutex_);
return failed_;
}
void onUnknownIncomingConnection(const FlatMessage & /*incomingLogon*/, const int /*istenPort*/,
const int /*counterpartyPort*/, const std::string & /*counterpartyIpAddress*/,
std::string * /*rejectReason*/) override {};
void onError(EngineErrorReason::Enum , const std::string & description) override {
recordFailure();
completionEvent_.release();
std::cerr << "\nEngine-level error: " << description << std::endl;
}
void onWarning(EngineWarningReason::Enum , const std::string & description) override {
std::cerr << "\nEngine-level warning: " << description << std::endl;
}
private:
void recordFailure()
{
OnixS::Threading::MutexGuard guard(failureMutex_);
failed_ = true;
}
OnixS::Threading::Semaphore & completionEvent_;
mutable OnixS::Threading::Mutex failureMutex_;
bool failed_;
};
}
int runSellSide(const Sample::Arguments & arguments)
{
std::clog << "SellSide sample." << std::endl << std::endl;
try {
EngineSettings settings;
manageLinuxSignals();
#ifdef SSL_ENCRYPTION
std::clog << "SSL Mode." << std::endl;
settings.sslListenPort(arguments.port)
.sslCertificateFile("test.pem")
.sslPrivateKeyFile("test.pem");
#else
settings.listenPort(arguments.port);
#endif
settings.licenseStore(LicenseStore)
.sendLogoutOnException(true); // E.g. to send a Logout when the sequence number of the incoming Logon (A) message is less than expected.
Listener listener;
MyEngineListener engineListener(listener.completionEvent());
Engine::init(settings);
EngineShutdownGuard engineShutdownGuard;
Engine::instance()->registerListener(&engineListener);
Session session(TargetCompId, SenderCompId, FixProtocolVersion, &listener);
#ifdef SSL_ENCRYPTION
session.encryptionMethod(EncryptionMethod::SSL);
#endif
session.logonAsAcceptor();
std::clog << "Awaiting session-initiator on port " << arguments.port << "..." << std::endl;
Sample::waitForUserOrEvent(
arguments,
"Press any key to terminate the acceptor.",
listener.completionEvent());
Sample::shutdownAcceptor(arguments, session);
Engine::instance()->unregisterListener();
const bool sampleFailed = listener.failed() || engineListener.failed();
if(sampleFailed)
return 1;
std::clog << "SellSide completed successfully." << std::endl;
}
catch(const std::exception & ex) {
processSampleException(ex.what());
return 1;
}
return 0;
}
int main(int argc, char * argv[])
{
const int defaultPort =
#ifdef SSL_ENCRYPTION
SslListenPort;
#else
ListenPort;
#endif
return Sample::runSample(argc, argv, defaultPort, &runSellSide);
}