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:

BL_config.xml
<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:

BL_config.xml
<StartSession SenderCompID="Sender" TargetCompID="Target" SessionQualifier="Q1" />

Sending instructions

Sending instructions can refer to sessions with the use of SessionQualifier as well:

BL_config.xml
<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: 

BL_config.xml
<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:

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:

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:

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:

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:

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:

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:

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:

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:

bindWithQualifier.js
qualifier = getSourceSessionQualifier();
ClOrdID = getStringField(11) + "-" + qualifier; 
setStringField(11, ClOrdID); // enrich message with session identifier 11=<ClOrdId>-<session qualifier>

sendToQualifier.js:

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.