ZagTrader

FIX Session Layer Explained

The session layer makes a FIX connection reliable: every message is numbered, nothing is lost or processed twice, and a connection that dies is detected. It is the same in every FIX version, and from FIX 5.0 it is a separate protocol called FIXT.1.1.

Sessions, initiators and acceptors

  • A session is identified by BeginString (8), SenderCompID (49) and TargetCompID (56). It outlives any single TCP connection: a session can be logged on and off many times a day and keeps its sequence numbers across reconnects.
  • The initiator opens the TCP connection and sends the first Logon, usually the client. The acceptor listens, usually the broker or venue.
  • Seven session (administrative) messages run the session; everything else is an application message.
35MessagePurpose
ALogonStarts the session and agrees the heartbeat interval.
0HeartbeatShows the connection is alive; answers a TestRequest.
1TestRequestAsks the other side for a Heartbeat.
2ResendRequestAsks for missed messages by sequence number.
4SequenceResetSkips sequence numbers (GapFill) or forces a new number (Reset).
3RejectRefuses a message that breaks the FIX rules.
5LogoutEnds the session, with an optional reason.

Logon

The initiator sends Logon (35=A) with EncryptMethod (98) (0) and HeartBtInt (108). The acceptor checks the CompIDs, the sequence number and any credentials, then answers with its own Logon. Only then may application messages flow.

A FIX 4.4 logon with a 30-second heartbeat interval.

  1. 1. Initiator: Logon

    8=FIX.4.4|9=70|35=A|49=BUYSIDE|56=SELLSIDE|34=1|52=20261020-07:00:00.000|98=0|108=30|10=075|
  2. 2. Acceptor: Logon response

    8=FIX.4.4|9=70|35=A|49=SELLSIDE|56=BUYSIDE|34=1|52=20261020-07:00:00.006|98=0|108=30|10=081|

SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.

Open this example in the parser

If the Logon is refused, the acceptor sends a Logout with a reason in Text (58), or simply closes the connection. See Logon rejected.

Heartbeats and TestRequest

  • Each side sends a Heartbeat (35=0) whenever it has sent nothing for HeartBtInt (108) seconds. Any other message resets the timer.
  • If a side hears nothing for a little longer than the interval, it sends a Test Request (35=1) with a TestReqID (112). The answer must be a Heartbeat carrying the same TestReqID.
  • If that answer does not come, the connection is considered dead and is dropped. The session itself is not reset: on reconnect, sequence numbers carry on.

A TestRequest and the Heartbeat that answers it.

  1. 1. Acceptor: TestRequest

    8=FIX.4.4|9=74|35=1|49=SELLSIDE|56=BUYSIDE|34=2|52=20261020-07:01:06.000|112=TEST-070106|10=155|
  2. 2. Initiator: Heartbeat echoing TestReqID

    8=FIX.4.4|9=74|35=0|49=BUYSIDE|56=SELLSIDE|34=2|52=20261020-07:01:06.003|112=TEST-070106|10=157|

SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.

Open this example in the parser

Sequence numbers

  • Every message carries MsgSeqNum (34), counted separately in each direction and starting at 1. Each side stores the next number it will send and the next it expects.
  • A number higher than expected means messages are missing: the receiver asks for them with a ResendRequest.
  • A number lower than expected, without 43=Y, means the sender lost its state. The receiver logs out with "MsgSeqNum too low".
  • Both counters go back to 1 at the agreed reset time, or when a Logon carries 141=Y. From FIX 4.4, NextExpectedMsgSeqNum (789) on the Logon lets each side state what it expects next.

Resend and gap fill

The receiver sends Resend Request (35=2) with BeginSeqNo (7) (first missing number) and EndSeqNo (16) (0 for "to the end"). The sender replays application messages with their original numbers, 43=Y and OrigSendingTime (122), and covers session messages with a Sequence Reset (35=4) in GapFill mode (123=Y).

The initiator reconnects and sees the acceptor's Logon at 9 while it expected 5. Message 5 was an Execution Report; 6 to 8 were heartbeats and 9 is the Logon itself.

  1. 1. Acceptor: Logon with MsgSeqNum 9

    8=FIX.4.4|9=70|35=A|49=SELLSIDE|56=BUYSIDE|34=9|52=20261020-08:00:00.006|98=0|108=30|10=090|
  2. 2. Initiator: ResendRequest from 5

    8=FIX.4.4|9=67|35=2|49=BUYSIDE|56=SELLSIDE|34=4|52=20261020-08:00:00.010|7=5|16=0|10=173|
  3. 3. Acceptor: message 5 replayed

    8=FIX.4.4|9=174|35=8|49=SELLSIDE|56=BUYSIDE|34=5|52=20261020-08:00:00.015|43=Y|122=20261020-07:20:11.402|37=OID-9005|11=ORD-2005|17=EXEC-9005-2|150=4|39=4|55=MSFT|54=1|38=300|151=0|14=0|6=0|10=204|
  4. 4. Acceptor: GapFill over 6 to 9

    8=FIX.4.4|9=101|35=4|49=SELLSIDE|56=BUYSIDE|34=6|52=20261020-08:00:00.016|43=Y|122=20261020-08:00:00.016|123=Y|36=10|10=126|

Heartbeats and the Logon (9) are not replayed: the GapFill covers them and moves the expected number to 10, the next message the acceptor will send.

SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.

Open this example in the parser

Session Reject

A message that breaks the FIX rules (missing required field, bad format, wrong CompID) gets a Reject (35=3) with RefSeqNum (45), RefTagID (371), RefMsgType (372) and SessionRejectReason (373). The rejected message still used its sequence number. Valid messages that the application cannot act on get a Business Message Reject (35=j) instead.

Logout

Either side ends the session by sending Logout (35=5). The other side answers with its own Logout and the initiator closes the connection. A Logout sent because of an error carries the reason in Text (58).

A normal end of day.

  1. 1. Initiator: Logout

    8=FIX.4.4|9=60|35=5|49=BUYSIDE|56=SELLSIDE|34=412|52=20261020-17:00:00.000|10=140|
  2. 2. Acceptor: Logout response

    8=FIX.4.4|9=61|35=5|49=SELLSIDE|56=BUYSIDE|34=1880|52=20261020-17:00:00.004|10=203|

SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.

Open this example in the parser

Questions

Are sequence numbers reset when the TCP connection drops?
No. A session keeps its sequence numbers across reconnects. They are reset only at the agreed schedule or by a Logon with ResetSeqNumFlag (141=Y).
Are heartbeats replayed during a resend?
No. Session messages such as Heartbeat, TestRequest and Logon are covered by a SequenceReset-GapFill instead of being sent again.
Who sends the first Logon?
The initiator, the side that opened the TCP connection. The acceptor answers with its own Logon.

Reference

Related errors

More guides