To shutdown the Engine the FIXForge::FIX::Engine::shutdown method is used.
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; try{ Engine::init(); // Session-related logic... Engine::shutdown(); }catch(const EngineException& ex){ clog << "Exception: " << ex.what() << endl; }
Example:
Each FIX version has its own namespace that contains objects that are unique for the version, e.g.:
using namespace FIXForge::FIX::FIX40;
Below is an example of a FIX message:
It is represented with the FIXForge::FIX::Message class.
To create a message the FIXForge::FIX::Message(const std::string& type, FIXForge::FIX::Version version) constructor is used.
To parse a message in the raw (tag=value) FIX format the FIXForge::FIX::Message(const std::string& rawMessage) constructor is used.
To validate a message the FIXForge::FIX::Message::validate method is used. This method checks for the presence of required fields.
There are several overloaded methods FIXForge::FIX::Message::toString() to simplify debugging and monitoring. To update the BodyLength (9) and CheckSum (10) fields the FIXForge::FIX::Message::updateCheckSum() method is used.
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; { Message order("D", FIX_42); // New Order - Single (MsgType = D) order.updateCheckSum(); clog << "Order" << order << endl; } { string rawMsg = "8=FIX.4.0\0x019=86\0x0135=D\0x0149=0\0x0156=0\0x0134=1\0x0152=99990909-17:17:17\0x0111=90001008\0x0121=1\0x0155=IBM\0x0154=1\0x0138=10\0x0140=1\0x0159=0\0x0110=191\0x01"; Message order(rawMsg); order.validate(); clog << order.toString() << endl; clog << order.toString(' ') << endl; clog << order.toString(Message::TAG_NAME | Message::TAG_NUMBER) << endl; }
To get a field value the FIXForge::FIX::Message::get method is used.
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX40; Message order("D", FIX_40); // New Order - Single order.set(11, "Unique identifier of execution message"); string ClOrdID = order.get(11);
To remove a field the FIXForge::FIX::Message::remove method is used.
The FIXForge::FIX::FIX42::Tags class contains the constants for the tag values. This class is defined for each FIX version namespace. The use of these constants makes the source code more readable.
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX40; Message order("D", FIX_40); // New Order - Single order.set(Tags::ClOrdID, "90001008"); order.set(Tags::Side, "1"); order.set(Tags::TimeInForce, "0");
To create a session the FIXForge::FIX::Session's constructors are used.
To terminate the session the FIXForge::FIX::Session::shutdown method is used.
A session has one of two possible roles: Acceptor or Initiator.
Acceptor is the receiving party of the FIX session. It listens for the incoming connection on the pre-defined port. The acceptor has responsibility to perform first level authentication and formally declare the connection request "accepted" through transmission of an acknowledgment Logon message.
Initiator establishes the telecommunications link and initiates the session via transmission of the initial Logon message.
To obtain the current role the FIXForge::FIX::Session::getRole method is used.
To establish the session as Acceptor the FIXForge::FIX::Session::logonAsAcceptor method is used.
To establish the session as Initiator the FIXForge::FIX::Session::logonAsInitiator method is used.
To disconnect the session the FIXForge::FIX::Session::logout method is used.
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX40; const string SENDER_COMP_ID = "SenderCompID"; const string TARGET_COMP_ID = "TargetCompID"; const Version VERSION = FIX_40; const string HOST = "Localhost"; int ACCEPTOR_PORT = Engine::instance()->getListenPort(); ISessionListener listener; Session acceptor(SENDER_COMP_ID, TARGET_COMP_ID, VERSION, &listener); Session initiator(TARGET_COMP_ID, SENDER_COMP_ID, VERSION, &listener); acceptor.logonAsAcceptor(); initiator.logonAsInitiator(HOST, ACCEPTOR_PORT); // Sends the Logon message and waits for the acknowledgment Logon // Message exchange and processing ... acceptor.logout(); // Sends the Logout message and waits for the confirming Logout initiator.logout(); acceptor.shutdown(); // Free resources initiator.shutdown(); // Free resources
To receive incoming application-level messages it is necessary to override the FIXForge::FIX::ISessionListener::onInboundApplicationMsg method.
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX42; class SessionListener : public ISessionListener{ public: virtual void onInboundApplicationMsg(const Message& msg, Session* sn){ clog << "Incoming application-level message: " << msg << endl; // processing of the application-level incoming message... } }; const string SENDER_COMP_ID = "AcceptorAndInitiator_SND"; const string TARGET_COMP_ID = "AcceptorAndInitiator_TRG"; const Version VERSION = FIX_42; const string ACCEPTOR_HOST = "localhost"; int ACCEPTOR_PORT = Engine::instance()->getListenPort(); SessionListener listener; Session acceptor(SENDER_COMP_ID, TARGET_COMP_ID, VERSION, &listener); acceptor.logonAsAcceptor(); Session initiator(TARGET_COMP_ID, SENDER_COMP_ID, VERSION, &listener); initiator.logonAsInitiator(ACCEPTOR_HOST, ACCEPTOR_PORT); Message order("D", VERSION); order.set(Tags::ClOrdID, "Unique identifier for Order as assigned by the buy-side"); order.set(Tags::HandlInst, "1"); order.set(Tags::Symbol, "Ticker symbol"); order.set(Tags::Side, "1"); order.set(Tags::TransactTime, "20051012-22:10:11"); order.set(Tags::OrdType, "1"); order.validate(); acceptor.send(&order); // continue the message exchange... acceptor.logout(); initiator.logout(); acceptor.shutdown(); initiator.shutdown();
Sequence numbers are initialized at the start of each FIX Session starting at 1 (one) and increment throughout the session. Each session establishes an independent incoming and outgoing sequence series. A single FIX session can exist across multiple sequential (not concurrent) physical connections. Parties can connect and disconnect multiple times while maintaining a single FIX session.
In other words, FIX Session is comprised of one or more FIX Connections.
Resetting the inbound and outbound sequence numbers back to 1, for whatever reason, constitutes the beginning of a new FIX session. Monitoring sequence numbers enables parties to gracefully synchronize applications when reconnecting during a FIX session.
To get or set the expected sequence number of the next incoming message the FIXForge::FIX::Session::getInSeqNum(), FIXForge::FIX::Session::setInSeqNum() methods are used.
To get or set the sequence number of the next outgoing message the FIXForge::FIX::Session::getOutSeqNum(), FIXForge::FIX::Session::setOutSeqNum() methods are used.
To disconnect the FIX Connection while maintaining a single FIX Session the FIXForge::FIX::Session::logout() method is used.
It is possible to continue the session later using the FIXForge::FIX::Session::logonAsAcceptor() or FIXForge::FIX::Session::logonAsInitiator() methods again.
To terminate a FIX Session the FIXForge::FIX::Session::shutdown() method is used.
The Engine automatically synchronizes sequence numbers when reconnecting during a FIX session on the base of the information previously stored in log files.
To synchronize sequence numbers manually FIXForge::FIX::Session::setInSeqNum() and FIXForge::FIX::Session::setOutSeqNum() methods are used (before FIXForge::FIX::Session::logonAsAcceptor() or FIXForge::FIX::Session::logonAsInitiator() method calls).
Some implementations of FIX protocol (FIX Dialects) expect that the FIX Session coincides with FIX Connection, in other words that the sequence numbers are reset back to 1 after the Logout messages exchange. To interact with such FIX dialects, the keepSequenceNumbersAfterLogout parameter of FIXForge::FIX::Session's constructor should be set to false.
In this case after FIXForge::FIX::Session::shutdown() method sequence numbers are set back to 1. Next time when the FIXForge::FIX::Session object is created incoming and outgoing sequence numbers will start from 1 (in other words, a new FIX Session will be created).
For each FIX session two files are created:
When the FIXForge::FIX::Session object is created anew after the Engine's restart, FIX Session's state (the sequence numbers of last received and sent messages, previously sent messages, etc) is restored from these files.
To start a FIX session as a new one (so called "clean start"), it is necessary to remove the log files from the previous runs.
Connecting parties must bi-laterally agree as to when sessions are to be started/stopped and log files are backed up based upon individual system and time zone requirements.
When the FIX session is finished, the log files are not needed anymore. They can be backed up and later a new FIX session with the same SenderCompID and TargetCompID will start sequence numbers from 1. The usual practice is to backup the log files at the end of each business day (so called "End Of Day procedure") to start the sequence numbers from 1 at the beginning of the next day.
Example:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="FixEngine" type="System.Configuration.NameValueSectionHandler"/> </configSections> <FixEngine> <add key="Dialect" value="LavaDialect.xml"/> <add key="ListenPort" value="4500"/> <add key="Log.InboundMessages" value="true"/> <add key="Validate.NumberOfRepeatingGroupInstances" value="false"/> <add key="Validate.RequiredFields" value="true"/> <add key="Resending.QueueSize" value="2500"/> <add key="Validate.UnknownFields" value="true"/> <add key="Validate.UnknownMessages" value="true"/> </FixEngine> </configuration>
| Setting | Description | Default value
|
|---|---|---|
| ConnectionRetries.Number | Number of attempts to restore the telecommunication link. | 3
|
| ConnectionRetries.Interval | The time interval between the attempts to restore the telecommunication link (in seconds). | 30
|
| Dialect | Specify the description of the FIX_Dialect. | Empty |
| ListenPort | FIX Engine listens on this port for incoming connections. If '0' then only session-initiators can be created. If '-1' then the telecommunication level is disabled and only message parsing/assembling can be used. | 0 |
| Log.Directory | Inbound and outboundmessages, session's state data and the FIX Engine log file (FixEngine.log) are stored in this directory. | MsgStorage |
| Log.FlushFileAfterEachMessage | Option to flush output files after each logged message. | True |
| Log.InboundMessages | Option to log inbound messages. | True
|
| Log.SessionSummary | Option to create a summary log file with inbound and outbound messages (in *.summary file). | True
|
| Resending.QueueSize | Number of sent messages that are available for resending on counterparty's Resend Request <2> message. | 1000
|
| SSL.CertificateFile | The path to the SSL certificate file in (Privacy Enhanced Mail) Base64 encoded (.pem) format. | Empty
|
| SSL.ListenPort | FIX Engine listens on this port for incoming SSL connections. If it is set to '0' then only SSL-based session-initiators can be created. If '-1' then the SSL encryption is disabled. | 0
|
| SSL.PrivateKeyFile | The path to the SSL private key file in (Privacy Enhanced Mail) Base64 encoded (.pem) format. | Empty
|
| SSL.PrivateKeyPassword | The password to load private keys that are protected by a password. | Empty
|
| SSL.VerifyPeer | Option to request client certificates and perform the certificate verification. | False
|
| Validate.NumberOfRepeatingGroupInstances | Option to validate that the declared number of Repeating Group instances is equal to the actual one. | True |
| Validate.RequiredFields | Option to validate the presence of required fields in inbound and outbound messages. | False |
| Validate.UnknownFields | Option to validate the presence of unknown fields (fields that do not belong to the message in accordance with the FIX protocol or its FIX Dialect. | False
|
| Validate.UnknownMessages | Option to validate the presence of unknown FIX messages (messages that do not belong to the message in accordance with the FIX protocol or its FIX Dialect. | False
|
"215=2<SOH></a>216=2<SOH>217=Dest_1<SOH>216=4<SOH>217=Dest_2<SOH>"represents a repeating group with two repeating instances "delimited" by tag 216 (first field in the repeating group.). The NoRoutingIDs<215> field specifies the number of repeating group instances (2 in this case). This is so called NumberOfInstances field. The NumberOfInstances field must immediately precede the repeating group contents (repeating group instances).
The FIX repeating group is represented with the FIXForge::FIX::Group class.
To get the Group object that represents the existing repeating group of the message the FIXForge::FIX::Message::getGroup(int numberOfInstancesTag) method is used.
To create a new repeating group or modify the number of instances in the existing one the FIXForge::FIX::Message::setGroup(int numberOfInstancesTag, int numberOfInstances) method is used.
To remove a repeating group method FIXForge::FIX::Message::remove(int numberOfInstancesTag) is used.
The FIXForge::FIX::Group class works with fields and embedded repeating groups in the same manner as the FIXForge::FIX::Message class, but each method has an additional parameter that defines the index of the repeating group instance (starting from 0).
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX42; Message request("V", FIX_42); request.set(Tags::MDReqID, "ABSD"); request.set(Tags::SubscriptionRequestType, 1); request.set(Tags::MarketDepth, 1); request.set(Tags::MDUpdateType, 1); request.set(Tags::AggregatedBook, "N"); // create a repeating group NoMDEntryTypes with two instances Group* groupMDEntryTypes = request.setGroup(Tags::NoMDEntryTypes, 2); groupMDEntryTypes->set(Tags::MDEntryType, 0, "EntryType_1"); // first instance groupMDEntryTypes->set(Tags::MDEntryType, 1, "EntryType_2"); // second instance // create a repeating group NoRelatedSym with two instances Group* groupRelatedSym = request.setGroup(Tags::NoRelatedSym, 2); groupRelatedSym->set(Tags::Symbol, 0, "EURUSD_0"); // first instance groupRelatedSym->set(Tags::Symbol, 1, "EURUSD_1"); // second instance request.validate(); clog << request << endl;
The states of the FIX session are listed below.
To be notified about the changes in the session stateoverwrite the FIXForge::FIX::ISessionListener::onStateChange method.
Example:
class Listener : public ISessionListener{ public : virtual void Listener::onStateChange(Session::State newState, Session::State prevState, Session* sn){ clog << "\nSession's state is changed, prevState=" << Session::state2string(prevState) << ", newState=" << Session::state2string(newState) << endl; } };
The methods of the FIXForge::FIX::ISessionListener class are listed below.
| Method (Event handler) | Description |
|---|---|
| onStateChange | Session state is changed. |
| onError | Error condition is detected. |
| onInboundApplicationMsg | Application-level message is received from the counterparty. |
| onInboundSessionMsg | Session-level message is received from the counterparty. |
| onOutboundApplicationMsg | Application-level message will be sent to the counterparty. |
| onOutboundSessionMsg | Session-level message will be sent to the counterparty.
|
| onResendRequest | Sent application-level message is about to be resent to the counterparty. |
| onWarning | Warning condition is detected. |
Example:
#include <FIXForge_FIXEngine.h> using namespace FIXForge::FIX; using namespace FIXForge::FIX::FIX43; const string SENDER_COMP_ID = "CustomLogonMessage_SND"; const string TARGET_COMP_ID = "CustomLogonMessage_TRG"; const Version VERSION = FIX_43; const int HBI = 30; const string USERNAME = "USER_NAME"; const string PASSWORD = "PASSWORD"; int port = Engine::instance()->getListenPort(); ISessionListener listener; Session acceptor(SENDER_COMP_ID, TARGET_COMP_ID, VERSION, &listener); acceptor.logonAsAcceptor(); Session initiator(TARGET_COMP_ID, SENDER_COMP_ID, VERSION, &listener); Message customLogonMsg("A", FIX_43); customLogonMsg.set(Tags::Username, USERNAME); customLogonMsg.set(Tags::Password, PASSWORD); initiator.logonAsInitiator("localhost", port, HBI, &customLogonMsg); // message exchange and processing ... acceptor.logout(); initiator.logout(); acceptor.shutdown(); initiator.shutdown();
The FixEngine.Dialect configuration setting specifies the description of such dialects in XML format. This description must confirm to the Dialect.xsd XML Schema file.
To add a new user-defined field to a FIX Message add the corresponding Field entity to the FIX Dialect description. For example:
<FIX version="4.0"> <Message type="D"> <Field tag="526" name="SecondaryClOrdID"/> <!-- Does not belong to Standard FIX 4.0 --> </Message> </FIX>
To add a new user-defined repeating group to a FIX Message add the corresponding Group entity to the FIX Dialect description. For example:
<FIX version="4.0"> <Message type="D"> <Group numberOfInstancesTag="78" name="NoAllocs"> <!-- Number of repeating groups for pre-trade allocation, does not belong to Standard FIX 4.0 --> <Field tag="79" name="AllocAccount"/> <!-- Does not belong to Standard FIX 4.0 --> <Field tag="661" name="AllocAcctIDSource"/> <!-- Does not belong to Standard FIX 4.0 --> <Field tag="736" name="AllocSettlCurrency"/> <!-- Does not belong to Standard FIX 4.0 --> <!-- Other group fields --> </Group> </Message> </FIX>
To make a field, which is required according to the FIX Protocol specification, optional, and visa-versa, add the corresponding Field entity to the FIX Dialect description and set the isRequired attribute accordingly. For example:
<FIX version="4.0"> <Message type="D"> <Field tag="21" isRequired="false" name="HandlInst"/> <!-- Required in Standard FIX 4.0, but optional in this FIX dialect --> <Field tag="109" isRequired="true" name="ClientID"/> <!-- Optional in Standard FIX 4.0, but required in this FIX dialect --> </Message> </FIX>
To define a User Defined Message add the corresponding Message entity to the FIX Dialect description. For example:
<FIX version="4.0"> <Message type="UserDefinedMessage_1"> <Field tag="100"/> <Field tag="101"/> </Message> </FIX>
Such a user-defined message can be used exactly the same way as the standard FIX Message:
Message udm_1("UserDefinedMessage_1", FIX_43); udm_1.set(100, "Field 100"); udm_1.set(101, "Field 101"); udm_1.validate(); clog << "UDM: " << udm_1 << endl;
Example of a FIX Dialect description file:
<?xml version="1.0" encoding="utf-8"?> <Dialect xmlns="http://tempuri.org/Dialect.xsd" name="Lava"> <FIX version="4.2"> <Message type="N"> <Group numberOfInstancesTag="73" name="RefAllocID"> <!-- An additional field in the existing repeating group --> <Field tag="37" name="OrderID"/> </Group> </Message> </FIX> <FIX version="4.3"> <Message type="y"> <Group numberOfInstancesTag="146" name="NoRelatedSym"> <!-- An additional field in the existing repeating group --> <Field tag="64" isRequired="true" name="FutSettDate"/> </Group> </Message> <Message type="W"> <Group numberOfInstancesTag="268" name="NoMDEntries"> <!-- An additional field in the existing repeating group --> <Field tag="278" name="MDEntryID"/> </Group> <Field tag="64" name="FutSettDate"/> </Message> <Message type="X"> <!-- An additional field --> <Field tag="55" name="Symbol"/> <!-- An additional field --> <Field tag="64" name="FutSettDate"/> </Message> </FIX> </Dialect>
If the sent application-level message should not be resent to the counterparty (e.g. an aged order) then the FIXForge::FIX::ISessionListener::onResendRequest() method should return false. In this case the Sequence Reset-GapFill (4) message will be sent instead.
For example:
ISessionListener listener; Session initiator("SenderCompIDValue", "TargetCompIDValue", FIX_42, &listener); initiator.setEncryptionMethod(Session::SSL); initiator.logonAsInitiator("localhost", 443, true); // Message exchange ... initiator.logout("SSL connection is finished."); initiator.shutdown();
To convert into this format from other format types, the openssl command-line tool could be used (http://www.openssl.org).
For example, to convert from "Personal Information Exchange - PKCS#12" (.pfx) to "Base64 Encoded" (.pem), the following command is run on the PFX file:
openssl pkcs12 -in <file_name>.pfx -out <file_name>.pem -nodes
For example:
const string targetCompID = "CNX"; const string host = "TargetHost"; { // Stream FIX Session const string streamSenderCompID = "str"; ISessionListener listener; Session streamSession(streamSenderCompID, targetCompID, FIX_42, &listener); streamSession.setEncryptionMethod(Session::SSL); const string streamSslCertificateAndPrivateKeyFile = "str.pem"; // If your counterpart performs the verification of your SSL certificate you need to set both SSL Certificate File and SSL Private Key File. streamSession.setSslCertificateFile(streamSslCertificateAndPrivateKeyFile); streamSession.setSslPrivateKeyFile(streamSslCertificateAndPrivateKeyFile); const int streamPort = 442; streamSession.logonAsInitiator(host, streamPort, 30, true); clog << "Stream session is established" << endl; streamSession.logout(); } { // Trading FIX Session const string tradingSenderCompID = "tr"; ISessionListener listener; Session tradingSession(tradingSenderCompID, targetCompID, FIX_42, &listener); tradingSession.setEncryptionMethod(Session::SSL); const string tradingSslCertificateAndPrivateKeyFile = "tr.pem"; // If your counterpart performs the verification of your SSL certificate you need to set both SSL Certificate File and SSL Private Key File. tradingSession.setSslCertificateFile(tradingSslCertificateAndPrivateKeyFile); tradingSession.setSslPrivateKeyFile(tradingSslCertificateAndPrivateKeyFile); const int tradingPort = 443; tradingSession.logonAsInitiator(host, tradingPort, 30, true); clog << "Trading session is established" << endl; tradingSession.logout(); }
FAST-related classes can be found in the FIXForge::FIX::FAST_1_1 namespace.
To encode a FIX message into a FAST stream the FIXForge::FIX::FAST_1_1::Encoder class is used.
For example:
string xmlFastTemplate = readTextFile("UdpFastTemplate.xml"); const bool encodeEachMessageIndependently = true; Encoder encoder(xmlFastTemplate, sourceFixMessage.getVersion(), encodeEachMessageIndependently); const int fastTemplateID = 36; const size_t bufferSize = 1024; char fastStreamChunk[bufferSize]; size_t chunkSize = encoder.encode(sourceFixMessage, fastTemplateID, fastStreamChunk, bufferSize);
To decode a part of a FAST stream back into a FIX message the FIXForge::FIX::FAST_1_1::Decoder class is used.
For example:
const bool decodeEachMessageIndependently = true; Decoder decoder(xmlFastTemplate, sourceFixMessage.getVersion(), decodeEachMessageIndependently); const Message& decodedMessage = decoder.decode(fastStreamChunk, chunkSize);
A FAST Template specifies the encoding and decoding rules in accordance with the FAST specification.
For example:
<?xml version="1.0" encoding="utf-8"?> <templates> <template name="Market Data - Incremental Refresh (X)" id="88"> <uInt32 name="BodyLength" id="9"/> <string name="MessageType" id="35"> <constant value="X" /> </string> <string name="SenderCompID" id="49"> <copy/> </string> <string name="TargetCompID" id="56"> <copy/> </string> <uInt64 name="MsgSeqNum" id="34"> <increment value="1"/> </uInt64> <string name="SendingTime" id="52"> <tail/> </string> <string name="PosDupFlag" id="43" presence="optional"> <default/> </string> <sequence name="MDEntries"> <length name="NoMDEntries" id="268"/> <string name="MDUpdateAction" id="279"/> <string name="Symbol" id="55"/> </sequence> <string name="CheckSum" id="10"/> </template> <templates>
The optional presence attribute indicates whether the field is mandatory or optional. If the attribute is not specified, the field is mandatory.
The required name attribute identifies the corresponding field in the current FIX message type by the field name.
The optional id attribute identifies the corresponding field in the current FIX message type by the tag number.
The following field operators are supported:
|
A. You can use FIXForge::FIX::Session::setInSeqNum and FIXForge::FIX::Session::setOutSeqNum methods to set the start sequence numbers before establishing the session.
A. You need to define and use the corresponding XML-based FIX Dialect description. See: FIX Dialects.
ResetSeqNumFlag (141) field in the Logon message?
A. To send a Logon message with this field during FIX Connection establishment, use the Custom Logon Message . It is also possible to send a Logon message with the ResetSeqNumFlag set when the FIX Session is established (e.g. to maintain 24 hour connectivity). For example:
FIX Session-Initiator changes its state to RECONNECTING and tries to restore the FIX Connection pre-configured number of times in pre-configured interval (using the binary exponential back off algorithm). Please note that FIX Engine automatically handles sending of Test Request messages (when needed).
For example:
customLogonMsg.set(Tags::SenderSubID, "SenderSubID_Value"); customLogonMsg.set(Tags::OnBehalfOfSubID, "OnBehalfOfSubID_Value");
"Invalid FIX Engine settings: Cannot open the persistent storage folder ('MsgStorage')" error (exception) when I try to run my FIX application as a Windows service? When I run my application as a standalone one, all work perfectly OK.A. You can use FIXForge::FIX::Session::senderSubID(const std::string &value), FIXForge::FIX::Session::targetSubID(const std::string &value), FIXForge::FIX::Session::senderLocationID(const std::string &value), FIXForge::FIX::Session::targetLocationID(const std::string &value) methods of the FIXForge::FIX::Session object.
1.5.2