Sequence number handling

Overview

This article will describe the most common cases, best practices, and configuration properties for sequence number handing and possible related issues.

FIX Antenna-based applications (such as FIXEdge) maintain sequence numbers according to the FIX Standard session layer recommendations. When the FIX Engine detects a gap, it requests missing messages automatically. If the counterparty requested missing messages, it also initiates the retransmission automatically (see: Initial synchronization of messages in a FIX connection).

The FIX Standard recommends using two independent counters for gap detection: one for incoming sequence numbers and a second for outgoing sequence numbers. Along with automatic recovery, the FIX Engine provides a set of options to specify gap handing and sequence reset management strategies for troubleshooting issues related to message sequencing or gaps. The synchronization of sequence numbers on both sides (initiator and acceptor) is critically important because desync can lead to financial loss.

Click the link to see more information about FIXEdge Recovery Time Objective and Recovery Point Objective.

A retransmitted message uses the original MsgSeqNum(34) value with PossDupFlag(43)=Y.

When idle, the FIX engine maintains the integrity of a connection by sending Heartbeat (0) and Test Request (1) messages.

Trading session or trading hours

A FIX endpoint (for example, exchange or venue) can specify the time when the FIX client connection becomes available. More info about trading sessions can be found herehttps://www.fixtrading.org/standards/fix-session-layer-online/#fix-session.

  • In the context of trading sessions, the start of the trading session is called Start of Day (SOD)
  • In the context of trading sessions, the time when the session goes offline is called End of Day (EOD)
  • In some cases, the trading day doesn't have strict bounds or hours. Case details and configuration options are described in this article.

The FIX Standard provides the following recommendations about sequencing during trading hours:

  • Messages from previous trading days can be recovered
  • At the SOD, a client should connect with sequence numbers 1/1
  • Counterparties should maintain incrementing sequences till the EOD
  • On disconnections or on receiving a Logout message, the application can reconnect and continue with sequences from the most recently connected session within the trading day
    • This is common practice and not a strict recommendation 
    • The way the client should behave with sequences upon reconnection is usually described in a specification document or connectivity specification and can vary across different venues
  • After EOD, it is recommended to stop reconnecting and schedule the connection at the next SOD
  • After EOD, sequence numbers can be reset because on the next trading day sequences will be reset to 1/1
  • Usually after EOD, users perform cleanup procedures such as moving FIX logs to an archive if they need to be saved for an audit

Trading session limited by incoming Logout

The EOD can be triggered by an incoming Logout (5) message from a counterparty. The FIX Engine should interpret it as the end of trading hours and start the EOD procedure, such as stop session and reconnection attempts, and resetting sequences because the next logon will be considered a new trading day.

The FIX Engine should be able to distinguish network issues like a disconnection and a Logout. If there are connection problems, the session should reconnect and recover the missing messages; disconnection, in this case, is not considered as the end of the trading session.

FIX Antenna C++

In FIX Antenna C++-based products, users can customize the mode that considers a Logout message as the end of the trading day with the property IntradayLogoutTolerance.

When IntradayLogoutTolerance = false, FIX Antenna changes the session state to "Correctly terminated" after receiving a Logout (5) message and resets the session sequence numbers. FIX Antenna will not continue reconnecting or accept connections if the session is in the "Correctly terminated" state.

FIXEdge

A FIXEdge user can configure the mode that considers a Logout message as the end of the trading day by setting the property FixLayer.FixEngine.Session.Session_Name.RecreateOnLogout = false.

On Logout, FIXEdge notifies to stop the reconnection of FIX sessions and change the state of the sessions to Correctly Terminated.

If reconnection or keeping sequences are not needed, this option should be used in a combination with FixLayer.FixEngine.Session.Session_Name.TerminateOnLogout. For example:

Results with the session object will be removed and FIX logs will be moved to an archive after receiving the Logout (5) message.

For keeping session in memory (don't move logs to archive after Logout), keep sequencing and store outgoing messages the user should specify options: 

The trading day (EOD and SOD times), and hence the time for the next reconnection for the session, is configured with the FIXEdge schedule. Refer to the Cron-Like Session Schedule Properties article for details.

FIXEdge can endlessly recreate the session after the Logout (5) messages if the properties are:

Reset sequences on each logon or logout

There are cases when trading sessions exist only while a session is established. That means that the session state can be recovered after disconnection, can be recovered only within a connection, or sequencing isn't needed for that message flow. For example, in market data scenarios, the session state should be recovered from a snapshot and all messages from the previous connection are obsolete or redundant.

Reset on Logon

Venues recommend resetting sequences on each Logon (A). Sometimes it's required to set ResetSeqNumFlag (141) = Y in the  Logon (A) message.    

This is not a recommended way since every time when sequence numbers are reset, the messages sent by a counterparty or undelivered messages from the user's side will be lost.

The user should be sure that the counterparty supports this functionality before relying on it.

FIX Antenna C++

In FIX Antenna C++-based products, users can force sequence numbers to reset in logon messages (Logon (A)) with the property ForceSeqNumReset.

Valid values for ForceSeqNumReset include:

  • "0" or "false" - Does not reset sequence numbers on Logon. Keeps session sequences from a previous connection.
  • "1" or "true" - Resets sequences at the first session initiation, i.e. when the FIX Engine hasn't detected logs from the previous run.
  • "2" - Resets sequences for every Logon.

FIX Antenna Java

In FIX Antenna Java, users can force sequence numbers to reset in logon messages (Logon (A)) with the property forceSeqNumReset.

Supported values include:

  • Always - session will send logon with 34= 1 and 141=Y every times (during connection and reconnection).
  • OneTime - session will send logon with 34= 1 and 141=Y only one time (during connection).
  • Never - this means that user can sets the 34= 1 and 141=Y from session parameters by hand.

FIXEdge

A FIXEdge user can force sequence numbers to reset in logons for each session individually with the property FixLayer.FixEngine.Session.Session_Name.ForceSeqNumReset.

Valid values for the property include:

  • "0" or "false" - Does not reset sequence numbers on Logon. Keeps session sequences from a previous connection.
  • "1" or "true" - Resets sequences at the first session initiation, i.e. when the FIX Engine hasn't detected logs from the previous run.
  • "2" - Resets sequences for every Logon.

Reset on Logout

In some scenarios, venues recommend resetting sequences on logout or disconnection. In these scenarios, if sequences are reset on logon, messages accumulated after disconnection and before logon will be lost due to the message flag ResetSeqNumFlag (141) being = Y. If the user wants to send the messages accumulated after the disconnection, resetting sequences on logout is preferred to resetting sequences on logon. In the next logon message, the ResetSeqNumFlag (141) should not be present in the Logon (A) message or set to = N.

Messages from previous connections can't be recovered.

The user should be sure that the counterparty supports this functionality before relying on it.

Trading sessions exist only while a session is established.

FIX Antenna C++

In FIX Antenna C++-based products, users can force sequence numbers to reset after disconnection by setting ResetSeqNumOnNonGracefulTermination = true.

ForceSeqNumReset should be set to false to avoid sending ResetSeqNumFlag (141) = Y in the Logon (A) message.

These options should be configured via the engine.properties file.

FIXEdge

A FIXEdge user can force sequence numbers to reset for each session individually with the property FixLayer.FixEngine.Session.Session_Name.ResetSeqNumOnNonGracefulTermination.

FixLayer.FixEngine.Session.Session_Name.ForceSeqNumReset should be set to false to avoid sending ResetSeqNumFlag (141) = Y in the Logon (A) message.

Reset sequences every 24 hours

FIX Engine has an option for a session to reset sequence numbers every 24 hours and send ResetSeqNumFlag (141) = Y in the Logon (A) message.

Successful connection of FIX Session initiates the 24-hour timer. 

The sequences are reset without session disconnection when the session is being established

FIX Antenna C++

FIXEdge

Reset sequences once a week

Some exchanges (like CME Logon Scenarios) uses weekly sessions and resets sequences once a week, using the same sequence counter across multiple days.

FIX Antenna

Sequence reset should be done inside Engine::SessionsScheduleManager::onTradePeriodBegin() callback.

Information about sequence reset scheduling in FIX Antenna C++ can be found here: Scheduler

FIXEdge

The trading session period can be specified with Cron-Like Session Schedule Properties in FIXEdge. 

Sequence number reset and archiving happens at the time specified by Schedules.Schedule_Name.TerminateTime

FIX Antenna Java

In FIX Antenna Java, the user should enable the option to reset sequences by schedule with performResetSeqNumTime and specify the time for resting with resetSequenceTime.

FIX sessions with uninterrupted connections

Sometimes a session cannot be dropped and must be maintained forever. In other words, the session should be connected 24/7/365.

For this type of connection, the operation of resetting sequence numbers has some limitations. The reason for resetting sequence numbers in this scenario is that counters can be overblown and the behavior of the FIX Engine for these cases is undefined. Usually, it is not recommended to do this type of sequence reset under high load.

The FIX Standard recommends:

Counterparties must agree to support the reset of a FIX session during FIX connection establishment.

Please note that messages received before sequences reset are not able to recover with the standard resend request mechanism despite the session not being disconnected.

There is no option to enable this behavior in our products. The functionality for sequence reset should be implemented by the user or counterparty.

Sequence numbers recovery during Logon

The counterparty can notify the initiator about an expected incoming sequence number in the confirming Logon (A) message with the NextExpectedMsgSeqNum (789) tag.

In this case, some venues expect the initiator to adjust sequences to the expected number or send the missing messages to the counterparty. No additional explicit Resend Request (2) message is required for triggering sequence synchronization.

FIX products support this FIX Standard recommendation: Using NextExpectedMsgSeqNum(789) to synchronize a FIX session

FIX Antenna

In FIX Antenna C++-based products, users can enable this sequence numbers handing mechanism by setting the session parameter HandleSeqNumAtLogon to true.

FIX Antenna Java

In FIX Antenna Java, users can enable this sequence numbers handing mechanism by setting the session parameter handleSeqNumAtLogon to true.

FIXEdge

In FIXEdge C++, users can enable this sequence numbers handing mechanism by setting the session parameter FixLayer.FixEngine.Session.Session_Name.HandleSeqNumAtLogon to true.

The sequence number is too low on Logon

FIX Engine will not accept the session if it detects that a counterparty connects with a sequence lower than expected and ResetSeqNumFlag (141) is not set.This behavior is recommended by the FIX Standard as a serious problem. For example, it identifies the issue that messages on both sides are inconsistent and this may lead to financial losses.

One of the common reasons for this behavior is the wrong sequence reset schedule resulting in the wrong session state. One party has reset sequences but another is not.  The user should verify if the session state is handled correctly and sequence reset rules correspond each other on the both sides.

FIX Engine allows users to ignore this restriction with the option IgnoreSeqNumTooLowAtLogon.

FIX Antenna

In FIX Antenna C++-based products, users can accept sessions with sequences that are lower than expected by setting the session parameter IgnoreSeqNumTooLowAtLogon to true.

FIX Antenna Java

In FIX Antenna Java, users can accept sessions with sequences that are lower than expected by setting the session parameter ignoreSeqNumTooLowAtLogon to true.

FIXEdge

In FIXEdge C++ users can accept sessions with sequences lower than is expected by setting the session parameter FixLayer.FixEngine.Session.Session_Name.IgnoreSeqNumTooLowAtLogon to true.

It is important to understand the consequences of violating FIX Protocol recommendations in order to make a more stable connection with undefined behavior.

More sequence number recovery cases

The FIX Standard recommendations can be found here: Synchronization after successful logon.

This behavior is automated in the EPAM FIX product however a user can compose the Resend Request (2) message and send it manually. 

For manual requests, the user should compose the Resend Request (2) message with tags specifying the range for requested messages with tags BeginSeqNo (7) and EndSeqNo (16).

Requesting a single message

To request a single message: Both BeginSeqNo (7) and EndSeqNo (16) are set of the missing message.

Requesting a range of messages

To request a range of messages should be equal to the first message of range, should be equal to the last message of the range.

Requesting all messages from a specific sequence number

This approach is recommended to recover from out of sequence conditions as it allows for faster recovery in the presence of certain race conditions when both sides are simultaneously attempting to recover a gap.

Setting EndSeqNo(16) to 0 has been the recommended approach since FIX.4.2.

Negative case: Resend request with a correct BeginSeqNo and wrong EndSeqNo

In cases when the counterparty sends EndSeqNo (16) greater than the current counter of outgoing sequence numbers, FIX Antenna sends all messages from BeginSeqNo (7) to the last known message with the current outgoing sequence number.

For example, there is a request is for 1-100 but FIX Engine has only 10 messages so FIX Engine will send messages with sequence from 1 to 10.

Negative case: Resend request with a wrong BeginSeqNo

In cases when the counterparty sends invalid or greater than expected BeginSeqNo (7), the FIX Engine treats it as unexpected and sends back a reject message.

If endSeqNo is greater than the maximum sequence number supported by FIX Antenna, we use maxStorageSeqNo and post warning message into the log that is correct as well.

Example

out: 8=FIX.4.4|9=80|35=2|49=TEST001|56=FIXEDGE|34=96|52=20210809-14:28:52.055|7=2147483647|16=10000|10=000|
in: 8=FIX.4.4|9=146|35=3|49=FIXEDGE|56=TEST001|34=77|52=20210809-14:28:49.080|45=96|58=Invalid Resend Request: BeginSeqNo (2147483647) is greater than expected (76).|10=035|

The maximum possible value of BeginSeqNo (7) for requesting is signed int 32: 2147483647. The values higher then this will be rejected with reason: "Invalid Resend Request: BeginSeqNo <= 0".

Example

out: 8=FIX.4.4|9=80|35=2|49=TEST001|56=FIXEDGE|34=97|52=20210809-14:28:55.787|7=2147483648|16=10000|10=017|
in: 8=FIX.4.4|9=108|35=3|49=FIXEDGE|56=TEST001|34=78|52=20210809-14:28:52.813|45=97|58=Invalid Resend Request: BeginSeqNo <= 0.|10=106|

QuickFIX Behavior

  • If BeginSeqNo is greater than expected, QuickFIX doesn’t reject it but sends a Sequence Reset (4) message with NewSeqNo(36) equal to the next expected sequence number expected by the counterparty and doesn’t resend messages. 
  • If BeginSeqNo is greater than int32, then QuickFIX treats it as a negative integer (-2147483648), sends Sequence Reset message with 34=-2147483648 and 36=2, and then resends all messages.

Modify Sequence Numbers Manually

FIX Antenna C++

Sequences can be modified via API methods Session::InSeqNum and Session::OutSeqNum

FIXEdge C++

Sequences can be modified via FIXEdge Admin REST API functions

Sequences can be reset  via FIXEdge Admin REST API functions

FIXICC

FIXICC administrative UI tool provides users a way to update sequences. See details in Manage Sequence Numbers.

FEJ

The way to modify sequences is described here: FIXEdge Java Administration

Limiting the number of messages in the resend request response from FIXEdge

This option is available starting with FIXEdge version 6.3.0.

Large resend requests for several thousand messages in a row are a resource-consuming operation for FIXEdge. It might take a long time to prepare a response on a resend request, especially if there are several million messages in a log and it is required to iterate across them.

During resend request preparation, a FIX session is blocked and doesn't send any real-time messages, including heartbeats. Sometimes, depending on heartbeat interval and the volume of requested data, it can also lead a FIX session to be considered lost by the counterparty.

There are two mechanisms for increasing the efficiency of this process and limit resource consumption:

  1. Ignoring duplicate resend requests with the option FixLayer.FixEngine.Session.Session_Name.IgnoreDuplicateResendRequests.
    If the option is enabled, FIXEdge will 
    ignore Resend Request (2) duplicates. This option should be used the property DuplicateResendRequestLimit > 0.

    Ignoring resend requests is not compliant with the FIX Standard Protocol.

  2. Limiting the volume of messages that can be sent back as a reply on the each resend request

The option FixLayer.FixEngine.Session.Session_Name.ResendMessagesLimit defines the maximum number of messages in the FIXEdge response. If a counterparty requests a large volume of response messages, FIXEdge only responds to the first ResendMessagesLimit from the block and then sends a Test Request (1) message notifying that synchronization has been finished. The client should adjust the resend requesting gap according to the new BeginSeqNo (7) value.

This behavior is beyond the FIX Standard. However, it allows the user to have quick and resource efficient message recovery. It is recommended under high load for systems with multiple sessions. 

Before enabling it the user should be sure that the counterparty is ready for this.

The values available for ResendMessagesLimit include:

  • "-1" - disabled, default
  • "0" - does not resend real messages, replies with GapFill
  • any positive number - the maximum number of messages in the FIXEdge response

If the option is not disabled, FIXEdge will ignore the duplicates of resend requests.

How to use the ResendMessagesBlockSize parameter

ResendMessagesBlockSize specifies the number of messages that would be processed during logon preparation in one storage reading iteration. This option is used for performance tuning.

By knowing the average message size and cache size, the user can fine-tune this parameter for the best resend request preparation performance. The optimal value can be determined experimentally. The best value can be found experimentally. The blocks should be fit in a single MFU.

Default value: 1000

This option is important when there is a need to optimize time spent on resending request processing and there are multiple resend requests.

  • Lowering the value reduces the time between getting a request and sending the response to the counterparty but increases the time for overall resend request processing when resending big volumes.

    This option is preferable if memory resources are limited, and storage is slow

  • Raising the value increases the time between getting a request and sending the response to the counterparty but reduces the time for overall resend request processing when resending big volumes.

    This option is preferable if there is a lot of free RAM and disk storage is fast.

How to use the ResendRequestBlockSize parameter

The ResendRequestBlockSize parameters limit the number of messages that will be requested in a resend request at once when a gap is detected by FIX Engine.

If the gap is more than the specified value, FIX Engine will request only the specified value of messages and will start to wait for the counterparty's response. FIX Engine will request the next part of the missing messages automatically after receiving a response from the counterparty that the batch of messages from the previous resend request has been received.

If the parameter is set to -1, FIX Engine will request all missing messages from the gap.

Default value: -1