How to use SessionQualifier
Session Qualifier Overview
In some cases, it's needed to create several sessions with the same SenderCompId/TargetCompId pair. Starting from version 6.5.0 of FIXEdge an extra string identifier called SessionQualifier has been introduced in addition to SenderCompId/TargetCompId pair to distinguish between such sessions.
To establish several sessions with the same SenderCompId and TargetCompId, both Initiator and Acceptor should create several session objects which differ from each other by SessionQualifier property. The SessionQualifier property on the Initiator side must be the same as the SessionQualifier property of the corresponding session on the acceptor side. When Initiator connects to Acceptor, it sends SessionQualifier along with SenderCompId and TargetCompId in the Logon message. The SessionQualifier tag in the Logon message is optional and can be configured in the FIXEdge.properties file. When Acceptor receives the Logon message with the SessionQualifier it searches for a registered session with SessionId corresponding to the received TargetCompId, SenderCompId, and SessionQualifier. If the session is found it is associated with the incoming connection, otherwise, the connection is rejected.
If a user creates a session by passing only SenderCompId and TargetCompId parameters (without SessionQualifier), the SessionId structure is created and stored internally with an empty qualifier_ property. If the Acceptor registers a session without SessionQualifier it won't accept any incoming connection with SessionQualifier defined in the Logon message. And vice versa, if Acceptor has registered a session or several sessions with qualifiers, it won't accept connections from Initiators without SessionQualifier.
If the Acceptor application doesn't use the FIX Antenna library it may define its own rules on how to determine the correspondence between sessions on Initiator and Acceptor side. For example, it may distinguish sessions based on the TCP port to which they are connected to. In this case, passing SessionQualifier in the Logon message is not necessary and may even lead to rejection by the Acceptor side.
Configuring FIXEdge.properties to use SessionQualifier
To use SessionQualifier two new parameters have been added to FIXEdge.properties:
- SessionQualifierValue (for defining SessionQualifier name);
- LogonMessageSessionQualifierTag (for defining a tag containing SessionQualifier name).
Session Identification
Both the Initiator and the Acceptor have their own logical textual identifiers that must be bilaterally agreed between counterparties. If SessionQualifier is used there will be a set of three identifiers in each FIX message: SenderCompID (49), TargetCompID (56), and SessionQualifier (*Custom tag set by LogonMessageSessionQualifierTag*). This "triple" identification relates both to Registered and Unregistered FIXEdge Sessions.
Business rules
FIX session definitions in the BL_Config.xml file are enhanced with SessionQualifier in addition to SenderCompId/TargetCompId combination.
Source element
The source from which the FIX message can come for processing defines either a FIX Session or a Transport Client (i.e. Transport Adaptor Session) by the element FIXSession. FIX session is identified by the set of attributes "SenderCompID", "TargetCompID" and "SessionQualifier".
Example:
<Source> <FixSession SenderCompID="Sender" TargetCompID="Target" SessionQualifier="Q1"> </Source>
The values of the attributes have to coincide with values defined for properties: FixLayer.FixEngine.Session.<Name>.SenderCompID, FixLayer.FixEngine.Session.<Name>.TargetCompID and FixLayer.FixEngine.Session.<Name>.SessionQualifierValue which was configured for FIX Sessions.
Session instructions
Session instructions such as StartSession, DisconnectSession, and TerminateSession are enhanced with SessionQualifier. E.g. StartSession instruction executes FIX session defined by specified SenderCompID/TargetCompID/SessionQualifier combination:
<StartSession SenderCompID="Sender" TargetCompID="Target" SessionQualifier="Q1" />
Sending instructions
Sending instructions can refer to sessions with the use of SessionQualifier as well:
<Send><FixSession SenderCompID="Sender" TargetCompID="Target" SessionQualifier="Q1"/></Send>
Routing rules for incoming messages from TA client
The routing approach for handling the incoming messages from the TA client is the same as for incoming messages from FIX sessions, except for one difference: the source is always a Client ID. FIX messages from TA clients are routed to the requisite FIX sessions based on the SenderCompID, TargetCompID, and SessionQualifier fields.
Example:
<Rule> <Source> <Client Name="TestClient"/> </Source> <Condition> <MatchField Field="35" Value=".*"/> <MatchField Field="571" Value="IST-\\d+"/> </Condition> <Action> <Send> <FixSession SenderCompID="TestSender" TargetCompID="TestTarget" SessionQualifier="Q1"/> </Send> </Action> </Rule>
JS
All these JS functions now support SessionQualifier as a parameter to identify a session:
send(<SenderCompId>,<TargetCompId>,<SessionQualifier>) getMsgBySeqNum(<SenderCompId>,<TargetCompId>,<SessionQualifier>,<SeqNum>) disconnectSession(<SenderCompId>,<TargetCompId>,<SessionQualifier>,<Reason>) terminateSession(<SenderCompId>,<TargetCompId>,<SessionQualifier>,<Reason>) startSession(<SenderCompId>,<TargetCompId>,<SessionQualifier>)
A new function getSourceSessionQualifier() has been added. The function returns the name of SessionQualifier (String) in case SessionQualifier is available for the source session.
Changes in logs
Any outputs of the SenderCompId/TargetCompId combination have been enhanced with SessionQualifier.
Session state internal notifications include SessionQualifier as a separate tag SenderSubID (50):
50=SessionQualifier^147=[WARN] Target:Sender AttemptToConnect^33=4^58=W^58=4^58=Target:Sender^58=Established
Example usage in BL_config.xml:
<Rule Description="Description"> <Source> .. </Source> <Condition> <EqualField Field="35" Value="C" /> <MatchMessage Value=".*50=SessionQualifier.*"/> </Condition> <Action> <Script Language="JavaScript" FileName="FIXEdge1/conf/JS.js"/> </Action> </Rule>
Using in FIXICC
In FIXICC SessionQualifier (SessionQualifierValue) and SessionQualifier Tag (LogonMessageSessionQualifierTag) parameters have been supported since version 2.9.9. They can be set in the corresponding fields of the "New Session" and "Edit Session" dialog windows. FE SessionID will be changed automatically reflecting the defined SenderCompID/TargetCompId/SessionQualifier.
How-to #1. Setup several Acceptor sessions with the same SenderCompId and TargetCompId
To establish several Acceptor sessions with the same SenderCompId and TargetCompId it's needed to define the SessionQualifier property as well as the SessionQualifier tag (SessionQualifierValue and LogonMessageSessionQualifierTag parameters respectively in the FIXEdge.properties file).
FIXEdge.properties:
FixLayer.FixEngine.Session.Session#1.Role = Acceptor FixLayer.FixEngine.Session.Session#1.SenderCompID = Target_Example1 FixLayer.FixEngine.Session.Session#1.TargetCompID = Sender_Example1 FixLayer.FixEngine.Session.Session#1.SessionQualifierValue = A1 FixLayer.FixEngine.Session.Session#1.LogonMessageSessionQualifierTag = 553 FixLayer.FixEngine.Session.Session#2.Role = Acceptor FixLayer.FixEngine.Session.Session#2.SenderCompID = Target_Example1 FixLayer.FixEngine.Session.Session#2.TargetCompID = Sender_Example1 FixLayer.FixEngine.Session.Session#2.SessionQualifierValue = A2 FixLayer.FixEngine.Session.Session#2.LogonMessageSessionQualifierTag = 553
BL_config.xml:
<FIXEdge> <BusinessLayer> <Rule> <Source> <FixSession SenderCompID="Target_Example1" TargetCompID="Sender_Example1" SessionQualifier="A2"/> </Source> <Action> <Script Language="JavaScript" FileName="FIXEdge1/conf/getQualifier.js" /> </Action> </Rule> <DefaultRule> <Action> <DoNothing/> </Action> </DefaultRule> </BusinessLayer> </FIXEdge>
getQualifier.js:
qualifier = getSourceSessionQualifier(); sessId = getSourceSessionId(); setStringField(553, "Your session qualifier is: " + qualifier); send(sessId);
How-to #2. Setup several Initiator sessions with the same SenderCompId and TargetCompId
To establish several Initiator sessions with the same SenderCompId and TargetCompId it's needed to define the SessionQualifier property (SessionQualifierValue parameter in FIXEdge.properties file).
FIXEdge.properties:
FixLayer.FixEngine.Session.Session#1.Role = Initiator FixLayer.FixEngine.Session.Session#1.SenderCompID = Sender_Example2 FixLayer.FixEngine.Session.Session#1.TargetCompID = Target_Example2 FixLayer.FixEngine.Session.Session#1.SessionQualifierValue = A1 FixLayer.FixEngine.Session.Session#1.LogonMessageSessionQualifierTag = 553 FixLayer.FixEngine.Session.Session#2.Role = Initiator FixLayer.FixEngine.Session.Session#2.SenderCompID = Sender_Example2 FixLayer.FixEngine.Session.Session#2.TargetCompID = Target_Example2 FixLayer.FixEngine.Session.Session#2.SessionQualifierValue = A2 FixLayer.FixEngine.Session.Session#2.LogonMessageSessionQualifierTag = 553
BL_config.xml:
<FIXEdge> <BusinessLayer> <Rule> <Source> <FixSession SenderCompID="Target_Example2" TargetCompID="Sender_Example2" SessionQualifier="A1"/> </Source> <Action> <Script Language="JavaScript" FileName="FIXEdge1/conf/disconnect.js" /> </Action> </Rule> <DefaultRule> <Action> <DoNothing/> </Action> </DefaultRule> </FIXEdge>
disconnect.js:
disconnectSession("Sender_Example2","Target_Example2", "A2", "Disconnect by message")
How-to #3. Set up several Initiator sessions with the same SenderCompId and TargetCompId using the Transport Adaptor.
When a transport adaptor is used in the message exchange chain, it's convenient to use significant identifying tag values as SessionQualifier names to distinguish between 2 sessions with common SenderCompID/TargetCompID pair.
Another approach is binding one session qualifier with some order identifier (e.g. enriching message content with the unique value of ClOrdID related to the session):
In this case, the properties and configuration like in the following examples with RMQ Adaptor are used.
FIXEdge.properties:
FixLayer.FixEngine.Session.Session#1.Role = Initiator FixLayer.FixEngine.Session.Session#1.SenderCompID = Sender_Example3 FixLayer.FixEngine.Session.Session#1.TargetCompID = Target_Example3 FixLayer.FixEngine.Session.Session#1.SessionQualifierValue = A1 FixLayer.FixEngine.Session.Session#1.LogonMessageSessionQualifierTag = 553 FixLayer.FixEngine.Session.Session#2.Role = Initiator FixLayer.FixEngine.Session.Session#2.SenderCompID = Sender_Example3 FixLayer.FixEngine.Session.Session#2.TargetCompID = Target_Example3 FixLayer.FixEngine.Session.Session#2.SessionQualifierValue = A2 FixLayer.FixEngine.Session.Session#2.LogonMessageSessionQualifierTag = 553 TransportLayer.TransportAdapters = TransportLayer.RMQTA TransportLayer.RMQTA.DllName = libUniversalTADll-MD-x64.so TransportLayer.RMQTA.Description = RMQ Transport Adaptor TransportLayer.RMQTA.JVMOptionsFile = ../FixEdge1/conf/JVM_Options.jvmopts TransportLayer.RMQTA.JavaClass = com.epam.fe.jms.jni.JMSAdaptor TransportLayer.RMQTA.AllowRejectMessages = true TransportLayer.RMQTA.ConnectionNames = Connection1 TransportLayer.RMQTA.ClientNames = TradeFlowMQProducer, TradeFlowMQConsumer TransportLayer.RMQTA.Connection.Connection1.ProviderURI = amqp://127.0.0.1:5672 TransportLayer.RMQTA.Connection.Connection1.User = sam1203 TransportLayer.RMQTA.Connection.Connection1.Password = test TransportLayer.RMQTA.Connection.Connection1.Reconnect = true TransportLayer.RMQTA.Connection.Connection1.ReconnectTries = 300 TransportLayer.RMQTA.Connection.Connection1.ReconnectInterval = 30000 TransportLayer.RMQTA.Client.TradeFlowMQProducer.ConnectionName = Connection1 TransportLayer.RMQTA.Client.TradeFlowMQProducer.StorageDir = ../FixEdge1/log TransportLayer.RMQTA.Client.TradeFlowMQProducer.SessionType = Producer TransportLayer.RMQTA.Client.TradeFlowMQProducer.DestinationURI = TradeFlow TransportLayer.RMQTA.Client.TradeFlowMQProducer.ExchangeName = exchange.OUT TransportLayer.RMQTA.Client.TradeFlowMQProducer.HeartBeat.Enable = true TransportLayer.RMQTA.Client.TradeFlowMQProducer.HeartBeat.Interval = 20 TransportLayer.RMQTA.Client.TradeFlowMQProducer.HeartBeat.MessageFile = ../FixEdge1/conf/rabbitMQHB.msg TransportLayer.RMQTA.Client.TradeFlowMQProducer.MessageProcessingOnMQDisconnect = reject TransportLayer.RMQTA.Client.TradeFlowMQProducer.StartTime= 09:00 TransportLayer.RMQTA.Client.TradeFlowMQProducer.EndTime= 18:00 TransportLayer.RMQTA.Client.TradeFlowMQConsumer.ConnectionName = Connection1 TransportLayer.RMQTA.Client.TradeFlowMQConsumer.StorageDir = ../FixEdge1/log TransportLayer.RMQTA.Client.TradeFlowMQConsumer.SessionType = Consumer TransportLayer.RMQTA.Client.TradeFlowMQConsumer.DestinationURI = TradeFlow TransportLayer.RMQTA.Client.TradeFlowMQConsumer.HeartBeat.Enable = true TransportLayer.RMQTA.Client.TradeFlowMQConsumer.HeartBeat.Interval = 20 TransportLayer.RMQTA.Client.TradeFlowMQConsumer.HeartBeat.MessageFile = ../FixEdge1/conf/rabbitMQHB.msg TransportLayer.RMQTA.Client.TradeFlowMQConsumer.HeartBeat.MissedCountBeforeDisconnect = 3
BL_config.xml:
<FIXEdge> <BusinessLayer> <Rule> <Source> <FixSession SenderCompID=".*" TargetCompID=".*" SessionQualifier=".*"/> </Source> <Condition> <MatchField Field="35" Value="D|G|F|n" /> </Condition> <Action> <Script Language="JavaScript" FileName="FIXEdge1/conf/bindWithQualifier.js" /> <Send Name="TradeFlowMQProducer" /> </Action> </Rule> <Rule> <Source Name="TradeFlowMQConsumer"/> <Condition> <MatchField Field="35" Value="8|9|j|n" /> </Condition> <Action> <Script Language="JavaScript" FileName="FIXEdge1/conf/sendToQualifier.js" /> </Action> </Rule> <DefaultRule> <Action> <DoNothing/> </Action> </DefaultRule> </FIXEdge>
bindWithQualifier.js:
qualifier = getSourceSessionQualifier(); ClOrdID = getStringField(11) + "-" + qualifier; setStringField(11, ClOrdID); // enrich message with session identifier 11=<ClOrdId>-<session qualifier>
sendToQualifier.js:
qualifier = ""; // no qualifier by default ClOrdID = getStringField(11); // 11=<ClOrdId>-<session qualifier> var regexp = /(.*)-([\w-]+)/g; match = regexp.exec(ClOrdID); if (match != null) // get qualifier from the ClOrdId tag. { qualifier = match[2]; } send("Sender_Example3", "Target_Example3", qualifier);
Troubleshooting
As any custom tag can be used to send SessionQualifier in a Logon message, the used dictionary should contain this tag in the Logon message or ProhibitUnknownTags should be set to "false". In other cases, this tag will be unknown and FIXEdge rejects messages with unknown tags.