How to configure event-driven approach for sessions state handling

Description

Solution is designed for automatic session handling (stop/start) based on events from other sessions.

Design overview

Bellow schema describes FIX messages flow between Handler_Session and Driven_Session, and also events, which occur on each stage.


Package deployment

Package is distributed in the form of zip archive for FIXICC-H2 import.

Configuration includes two sessions (Handler_Session, Driven_Session) and set of business layer components for sessions handling:

Deployment guide:

  1. download package from EPAM's client space https://clientspace.b2bits.com/product-62 (contact sales@btobits.com for the access)
  2. archive content into FIXICC-H2_export.zip
  3. open FIXICC-H2 UI and navigate to "Import Server Configuration"
  4. select FIXICC-H2_export.zip from your laptop
  5. complete import
  6. enable Start_Handler_Session.js script

Detailed logic description

Main flow

Successful connection without any issues.

Assumed we have two sessions: Handler_Session (acceptor), Driven_Session (initiator).

In case end user connects to Handler_Session, then Driven_Session initiates connection to the venue. All business messages from Driven_Session, will be routed into the Handler_Session.

Exceptional flows

Logout comes from Handler_Session

In case end user disconnected from Handler_Session for any reason, the Driven_Session will be disconnected automatically.
Case is also valid for unexpected break of the Handler_Session.

Logout comes from Driven_Session

In case Driven_Session became disconnected, FIXEdge will try to reconnect Driven_Session and in case failure end user will be disconnected from Handler_Session automatically.

Endpoint for Driven_session unavailable

In case end user connects to Handler_Session, the Driven_Session initiates connection to the venue, but was not able to establish connection, Handler_Session will be disconnected automatically.
Case is also valid for unexpected break of the Driven_Session.

Schedules

It is possible to configure Handler_Session to listen by schedule and be restarted after disconnect only in the configured interval.

Since "DisconnectSession" command not just stops session, but also terminates it, there is JS script Start_Handler_Session.js (see in Example of configuration section) which is responsible for Handler_Session restart in the pre-configured schedule.

Kindly note, that it is required to adjust schedule for Handler_Session not just in session setting, but also in Start_Handler_Session.js

Example of configuration

Parameters used for sessions:

 Click here to expand...

FixLayer.FixEngine.Session.Driven_Session.Version=FIX42
FixLayer.FixEngine.Session.Driven_Session.SendingTimestampUnit=millisecond
FixLayer.FixEngine.Session.Driven_Session.CustomSessionType=GENERIC
FixLayer.FixEngine.Session.Driven_Session.Validation.ProhibitDuplicatedTags=true
FixLayer.FixEngine.Session.Driven_Session.TerminateOnLogout=false
FixLayer.FixEngine.Session.Driven_Session.Backup.ForcedReconnect=false
FixLayer.FixEngine.Session.Driven_Session.Backup.LogIncomingMessages=true
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.ProhibitUnknownTags=false
FixLayer.FixEngine.Session.Driven_Session.EnableAutoSwitchToBackupConnection=false
FixLayer.FixEngine.Session.Driven_Session.SocketOpPriority=EVEN
FixLayer.FixEngine.Session.Driven_Session.Validation.ProhibitUnknownTags=false
FixLayer.FixEngine.Session.Driven_Session.Backup.EnableAutoSwitchToBackupConnection=false
FixLayer.FixEngine.Session.Driven_Session.IgnoreSeqNumTooLowAtLogon=false
FixLayer.FixEngine.Session.Driven_Session.SSLProtocols=TLSv1_1,TLSv1_2,TLSv1
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.IsEnabled=false
FixLayer.FixEngine.Session.Driven_Session.StorageType=persistentMM
FixLayer.FixEngine.Session.Driven_Session.Validation.IsEnabled=false
FixLayer.FixEngine.Session.Driven_Session.Backup.SendLastMsgSeqNumProcessed=false
FixLayer.FixEngine.Session.Driven_Session.ResendRequestBlockSize=0
FixLayer.FixEngine.Session.Driven_Session.Backup.ReconnectMaxTries=3
FixLayer.FixEngine.Session.Driven_Session.DisableTCPBuffer=false
FixLayer.FixEngine.Session.Driven_Session.SendCpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.TargetCompID=Driven_Session
FixLayer.FixEngine.Session.Driven_Session.MaxMessagesAmountInBunch=0
FixLayer.FixEngine.Session.Driven_Session.CpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.EnableMessageRejecting=false
FixLayer.FixEngine.Session.Driven_Session.AggressiveReceiveDelay=500
FixLayer.FixEngine.Session.Driven_Session.Validation.VerifyTagsValues=true
FixLayer.FixEngine.Session.Driven_Session.Backup.IntradayLogoutToleranceMode=false
FixLayer.FixEngine.Session.Driven_Session.Schedule=Driven_Session
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.IgnoreUnknownFields=false
FixLayer.FixEngine.Session.Driven_Session.SenderCompID=FIXEDGE
FixLayer.FixEngine.Session.Driven_Session.Backup.ResendRequestBlockSize=0
FixLayer.FixEngine.Session.Driven_Session.Validation.IgnoreUnknownFields=false
FixLayer.FixEngine.Session.Driven_Session.Backup.ConfirmingLogonStrategy=RejectLogout
FixLayer.FixEngine.Session.Driven_Session.Backup.ForceSeqNumReset=0
FixLayer.FixEngine.Session.Driven_Session.OutgoingQueueSizeLimit=0
FixLayer.FixEngine.Session.Driven_Session.ReconnectMaxTries=5
FixLayer.FixEngine.Session.Driven_Session.RecvCpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.KeepConnectionState=true
FixLayer.FixEngine.Session.Driven_Session.Backup.ReconnectInterval=1000
FixLayer.FixEngine.Session.Driven_Session.LogoutTimeFrame=10
FixLayer.FixEngine.Session.Driven_Session.Backup.IgnoreSeqNumTooLowAtLogon=false
FixLayer.FixEngine.Session.Driven_Session.Backup.MaxMessagesAmountInBunch=0
FixLayer.FixEngine.Session.Driven_Session.HandleSeqNumAtLogon=false
FixLayer.FixEngine.Session.Driven_Session.RemoteHost=10.68.141.34
FixLayer.FixEngine.Session.Driven_Session.ResendMessagesLimit=-1
FixLayer.FixEngine.Session.Driven_Session.Backup.EnableMessageRejecting=false
FixLayer.FixEngine.Session.Driven_Session.Backup.AggressiveReceiveDelay=500
FixLayer.FixEngine.Session.Driven_Session.Backup.StorageRecoveryStrategy=NONE
FixLayer.FixEngine.Session.Driven_Session.Validation.CheckRequiredGroupFields=true
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.CheckRequiredGroupFields=true
FixLayer.FixEngine.Session.Driven_Session.LogonTimeFrame=10
FixLayer.FixEngine.Session.Driven_Session.LogIncomingMessages=true
FixLayer.FixEngine.Session.Driven_Session.ForcedReconnect=false
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.VerifyRepeatingGroupBounds=true
FixLayer.FixEngine.Session.Driven_Session.ConfiguredName=Driven_Session
FixLayer.FixEngine.Session.Driven_Session.Backup.SendCpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.HiddenLogonCredentials=false
FixLayer.FixEngine.Session.Driven_Session.StatusGroup=PLANNED
FixLayer.FixEngine.Session.Driven_Session.HBI=60
FixLayer.FixEngine.Session.Driven_Session.Backup.StorageType=persistentMM
FixLayer.FixEngine.Session.Driven_Session.ReconnectInterval=5000
FixLayer.FixEngine.Session.Driven_Session.Backup.SocketOpPriority=EVEN
FixLayer.FixEngine.Session.Driven_Session.IncomingThroughputLimit=0
FixLayer.FixEngine.Session.Driven_Session.Validation.VerifyRepeatingGroupBounds=true
FixLayer.FixEngine.Session.Driven_Session.ForceSeqNumReset=1
FixLayer.FixEngine.Session.Driven_Session.ConfirmingLogonStrategy=RejectLogout
FixLayer.FixEngine.Session.Driven_Session.Backup.LogoutTimeFrame=10
FixLayer.FixEngine.Session.Driven_Session.IncomingMessagesLimit=0
FixLayer.FixEngine.Session.Driven_Session.Backup.LogonTimeFrame=10
FixLayer.FixEngine.Session.Driven_Session.IntradayLogoutToleranceMode=true
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.ProhibitDuplicatedTags=true
FixLayer.FixEngine.Session.Driven_Session.Backup.CpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.Backup.RecvCpuAffinity=0
FixLayer.FixEngine.Session.Driven_Session.Backup.DisableTCPBuffer=false
FixLayer.FixEngine.Session.Driven_Session.Backup.KeepConnectionState=true
FixLayer.FixEngine.Session.Driven_Session.Backup.CustomSessionType=GENERIC
FixLayer.FixEngine.Session.Driven_Session.RemotePort=8901
FixLayer.FixEngine.Session.Driven_Session.Backup.Validation.VerifyTagsValues=true
FixLayer.FixEngine.Session.Driven_Session.Backup.HiddenLogonCredentials=false
FixLayer.FixEngine.Session.Driven_Session.Backup.HandleSeqNumAtLogon=false
FixLayer.FixEngine.Session.Driven_Session.StorageRecoveryStrategy=NONE
FixLayer.FixEngine.Session.Driven_Session.SendLastMsgSeqNumProcessed=false
FixLayer.FixEngine.Session.Driven_Session.Backup.SendingTimestampUnit=millisecond
FixLayer.FixEngine.Session.Driven_Session.Role=INITIATOR

FixLayer.FixEngine.Session.Handler_Session.IntradayLogoutToleranceMode=true
FixLayer.FixEngine.Session.Handler_Session.StorageType=persistentMM
FixLayer.FixEngine.Session.Handler_Session.HiddenLogonCredentials=false
FixLayer.FixEngine.Session.Handler_Session.TargetCompID=Handler_Session
FixLayer.FixEngine.Session.Handler_Session.RecreateOnLogout=true
FixLayer.FixEngine.Session.Handler_Session.ResetSeqNumFromFirstLogon=never
FixLayer.FixEngine.Session.Handler_Session.SocketOpPriority=EVEN
FixLayer.FixEngine.Session.Handler_Session.EnableAutoSwitchToBackupConnection=false
FixLayer.FixEngine.Session.Handler_Session.AggressiveReceiveDelay=500
FixLayer.FixEngine.Session.Handler_Session.SSLProtocols=TLSv1_2,TLSv1,TLSv1_1
FixLayer.FixEngine.Session.Handler_Session.LogoutTimeFrame=10
FixLayer.FixEngine.Session.Handler_Session.Validation.ProhibitDuplicatedTags=true
FixLayer.FixEngine.Session.Handler_Session.SenderCompID=FIXEDGE
FixLayer.FixEngine.Session.Handler_Session.SendLastMsgSeqNumProcessed=false
FixLayer.FixEngine.Session.Handler_Session.LogonTimeFrame=10
FixLayer.FixEngine.Session.Handler_Session.Validation.VerifyTagsValues=true
FixLayer.FixEngine.Session.Handler_Session.Validation.VerifyRepeatingGroupBounds=true
FixLayer.FixEngine.Session.Handler_Session.MaxMessagesAmountInBunch=0
FixLayer.FixEngine.Session.Handler_Session.SendCpuAffinity=0
FixLayer.FixEngine.Session.Handler_Session.EnableMessageRejecting=false
FixLayer.FixEngine.Session.Handler_Session.KeepConnectionState=true
FixLayer.FixEngine.Session.Handler_Session.ResendMessagesLimit=-1
FixLayer.FixEngine.Session.Handler_Session.ResendRequestBlockSize=0
FixLayer.FixEngine.Session.Handler_Session.ConfirmingLogonStrategy=RejectLogout
FixLayer.FixEngine.Session.Handler_Session.IncomingMessagesLimit=0
FixLayer.FixEngine.Session.Handler_Session.ReconnectInterval=1000
FixLayer.FixEngine.Session.Handler_Session.CustomSessionType=GENERIC
FixLayer.FixEngine.Session.Handler_Session.CpuAffinity=0
FixLayer.FixEngine.Session.Handler_Session.LogIncomingMessages=true
FixLayer.FixEngine.Session.Handler_Session.Version=FIX42
FixLayer.FixEngine.Session.Handler_Session.OutgoingQueueSizeLimit=0
FixLayer.FixEngine.Session.Handler_Session.StatusGroup=PLANNED
FixLayer.FixEngine.Session.Handler_Session.ForcedReconnect=false
FixLayer.FixEngine.Session.Handler_Session.ReconnectMaxTries=3
FixLayer.FixEngine.Session.Handler_Session.StorageRecoveryStrategy=NONE
FixLayer.FixEngine.Session.Handler_Session.ConfiguredName=Handler_Session
FixLayer.FixEngine.Session.Handler_Session.Validation.IsEnabled=false
FixLayer.FixEngine.Session.Handler_Session.Schedule=Handler_Session
FixLayer.FixEngine.Session.Handler_Session.IgnoreSeqNumTooLowAtLogon=false
FixLayer.FixEngine.Session.Handler_Session.Validation.ProhibitUnknownTags=false
FixLayer.FixEngine.Session.Handler_Session.RecvCpuAffinity=0
FixLayer.FixEngine.Session.Handler_Session.HandleSeqNumAtLogon=false
FixLayer.FixEngine.Session.Handler_Session.Role=ACCEPTOR
FixLayer.FixEngine.Session.Handler_Session.DisableTCPBuffer=false
FixLayer.FixEngine.Session.Handler_Session.SendingTimestampUnit=millisecond
FixLayer.FixEngine.Session.Handler_Session.ForceSeqNumReset=1
FixLayer.FixEngine.Session.Handler_Session.IncomingThroughputLimit=0
FixLayer.FixEngine.Session.Handler_Session.Validation.IgnoreUnknownFields=false
FixLayer.FixEngine.Session.Handler_Session.Validation.CheckRequiredGroupFields=true

Preconfigured schedules

 Click here to expand...

FixLayer.FixEngine.Session.Driven_Session.Schedule=Driven_Session
Schedules.Driven_Session.DisconnectTime=0 50 17 * * 2-6
Schedules.Driven_Session.StartTime=0 45 17 * * 2-6

FixLayer.FixEngine.Session.Handler_Session.Schedule=Handler_Session
Schedules.Handler_Session.ConnectTime=0 0 19 * * 1-5
Schedules.Handler_Session.StartTime=0 55 18 * * 1-5
Schedules.Handler_Session.TerminateTime=0 45 17 * * 2-6
Schedules.Handler_Session.DisconnectTime=0 40 17 * * 2-6

Business layer configuration

 Click here to expand...

<?xml version="1.0" encoding="UTF-8"?>
<FIXEdge>
   <BusinessLayer>
      <Rule Description="Disconnect corresponding Handler_Session session in case Driven_Session session stopped">
         <Condition>
            <EqualField Field="35" Value="C" />
            <MatchMessage Value=".*147=\[.*\] FIXEDGE:Driven_Session (Terminated correctly|Non-gracefully terminated).*" />
         </Condition>
         <Action>
            <DisconnectSession SenderCompID="FIXEDGE" TargetCompID="Handler_Session" />
         </Action>
         <Source>
            <FixSession SenderCompID=".*" TargetCompID=".*" SessionQualifier="" />
         </Source>
      </Rule>
      <Rule Description="Map execution reports from Driven_Session and rout to Handler_Session">
         <Condition>
            <MatchField Value="*" Field="35" />
         </Condition>
         <Action>
            <Send>
               <FixSession SenderCompID="FIXEDGE" TargetCompID="Handler_Session" />
            </Send>
         </Action>
         <Source Name="Driven_Session" />
      </Rule>
      <Rule Description="Re-start corresponding Handler_Session session after Driven_Session session been terminated or disconnected">
         <Condition>
            <EqualField Field="35" Value="C" />
            <MatchMessage Value=".*147=\[.*\] FIXEDGE:Handler_Session (Terminated correctly|Non-gracefully terminated).*" />
         </Condition>
         <Action>
            <Script Language="JavaScript" ScriptName="Start_Handler_Session.js" />
            <DisconnectSession SenderCompID="FIXEDGE" TargetCompID="Driven_Session" />
         </Action>
         <Source>
            <FixSession SenderCompID=".*" TargetCompID=".*" SessionQualifier="" />
         </Source>
      </Rule>
      <OnSessionLevelRejectEvent Description="Route rejects from Driven_Session session to Handler_Session session">
         <Condition>
            <EqualField Field="35" Value="3" />
         </Condition>
         <Action>
            <Send>
               <FixSession SenderCompID="FIXEDGE111" TargetCompID="Handler_Session" />
            </Send>
         </Action>
         <Source Name="Driven_Session" />
      </OnSessionLevelRejectEvent>
      <Rule Description="Start corresponding Driven_Session session after Handler_Session session been established">
         <Condition>
            <EqualField Field="35" Value="C" />
            <MatchMessage Value=".*147=\[.*\] FIXEDGE:Handler_Session Established.*" />
         </Condition>
         <Action>
            <StartSession SenderCompID="FIXEDGE" TargetCompID="Driven_Session" />
         </Action>
         <Source>
            <FixSession SenderCompID=".*" TargetCompID=".*" SessionQualifier="" />
         </Source>
      </Rule>
      <DefaultRule>
         <Action>
            <DoNothing />
         </Action>
      </DefaultRule>
   </BusinessLayer>
</FIXEdge>

JS scripts

 Click here to expand...

function main()
{
    //session schedule in US East time zone
    start_hour = 19;
    start_minute = 0;
    start_days = [1,2,3,4,5]; //Mon-Fri
    stop_hour = 17;
    stop_minute = 45;
    stop_days = [2,3,4,5,6]; //Tue-Sat
    
    //get current date
    date = new Date();
    
    current_day_of_week = date.getDay();
    current_hour = date.getHours();
    current_minute = date.getMinutes();
    
    //get target session
    tar147 = getStringField(147);
    sessionID = tar147.split(' ')[1];
    senderID = sessionID.split(':')[0];
    targetID = sessionID.split(':')[1];
    
    //start session on Mon
    if (current_day_of_week == 1 && current_hour >= start_hour && current_minute >= start_minute)
    {
        startSession(senderID,targetID);
    }
    //start session on Tue-Fri
    else if (start_days.indexOf(current_day_of_week) !== -1 && stop_days.indexOf(current_day_of_week) !== -1 && (current_hour <= stop_hour || current_hour >= start_hour))
    {
        //do not start session after 17:45
        if (current_hour == stop_hour && current_minute >= stop_minute)
        {
            return;
        }
        startSession(senderID,targetID);
    }
    //start session on Sat
    else if (current_day_of_week == 6 && current_hour <= stop_hour && current_minute < stop_minute)
    {
        startSession(senderID,targetID);
    }
    else
    {
        return;
    }
}

main();