Skip to content

09 · FIX Protocol Deep Dive: The Common Language of Global Institutional Trading

Domestic futures have CTP; crypto exchanges have REST/WebSocket — but the common language of overseas institutional markets (CME, Interactive Brokers, interbank) is FIX. It is finance's oldest and most widely deployed "text exchange format" — no SDK, no private binary, just a field dictionary and line after line of Tag=Value.

This article explains what FIX is, what messages look like, how the core message types are used, how sessions stay alive and how state stays aligned — ending with selection advice and derivative specs (FAST compression, the crypto exchange landscape).


1. What Is FIX

FIX (Financial Information eXchange) is the de facto standard messaging protocol for global financial trading. Key facts:

FactDetail
NatureA message format standard for trading (a text protocol): it defines "how messages are organized, what fields are called, how state is expressed"
OriginDeveloped in 1992 by Fidelity Investments and Salomon Brothers for equity trading, to escape the coupling of proprietary formats
GovernanceMaintained by FIX Protocol Ltd (FPL, formerly FIX Protocol Organization) together with counterparties
TodayWidely used for institutional direct connectivity in global equities, futures, fixed income, and FX; CME, ICE, LSEG, Interactive Brokers are all FIX members/supporters
VersionsMainstream is FIX 4.2 / 4.4 (Session layer); FIX 5.0+ introduced componentized message catalogs; defer to the version your counterparty actually supports

A widely repeated saying: FIX is not software or an interface library — it is a "dictionary". It specifies how bytes are encoded, how messages are numbered, how state is represented; how you transport them (direct TCP, dedicated lines, authenticated networks) is each firm's own business.

FIX was born in a world where "every bank had its own private format": in the 90s, connecting to N counterparties meant writing N parsers. FIX's ambition was one format with an industry-maintained field dictionary — an idea later inherited by the XML/JSON era, but in low-latency text messaging FIX remains the old master.


2. Where FIX Sits in the Trading Chain

text
Strategy / Order Management System (OMS)
        │ internal order intent

┌───────────────────────────────┐
│      FIX engine (client side)     │  ← owned by the software company / buy-side
│  message assembly / parsing / session management │
│  sequence maintenance / heartbeat / resend       │
└──────────────┬────────────────┘
               │ FIX connection (dedicated line / authenticated network / public internet + encryption)
┌──────────────▼────────────────┐
│      FIX gateway (counterparty side)   │  ← exchange / market maker / bank / clearing house
│  usually they provide the onboarding docs and test environment │
└──────────────┬────────────────┘

     Exchange matching / market maker internals / interbank market

One-line positioning: FIX is the last-mile protocol between your OMS and the counterparty. Inside your own system you can use any stack (message queues, REST, gRPC), but once traffic leaves through institutional channels, the exit is FIX.

Typical users:

RoleWhat they use FIX for
Buy side (hedge funds, asset managers)Connect to sell-side execution channels (brokers/banks): place orders + receive reports
Sell side (market makers, banks)Expose FIX interfaces, accept client orders
Exchanges/clearing houses (CME etc.)Provide FIX/FAST direct access for members and ISVs
Brokers (Interactive Brokers etc.)Institutional clients use FIX instead of desktop terminals

3. FIX Message Structure

3.1 Three Sections: Header / Body / Trailer

Every FIX message has exactly three parts (using FIX 4.x as example):

SectionTagsRole
Header8=BeginString, 35=MsgType, 49=SenderCompID, 56=TargetCompID, 34=MsgSeqNum, 52=SendingTimeIdentifies version, message type, sender/receiver, sequence number, time
BodyMessage-type-specific fields (e.g., 55=Symbol, 54=Side, 44=Price, 38=OrderQty)Business content
Trailer10=CheckSumIntegrity check, must be the very last field

Convention: besides 8 and 35 in the Header, 49/56/34/52 are mandatory Session-layer fields too; 10=CheckSum must be the final field of the entire message — any field appended after it breaks validation.

3.2 Tag=Value Format and a Minimal Readable Example

FIX's encoding rule can be stated in one sentence: each field pair is <Tag>=<Value><SOH>, fields separated by SOH (0x01, ASCII 1). For human reading SOH is usually written as |; when decoding, just split on |.

A minimal readable NewOrderSingle:

text
8=FIX.4.4|35=D|49=SENDER01|56=TARGET01|34=7|52=20260816-10:00:00.000|11=ORD10001|55=ESU6|54=1|60=20260816-10:00:00.000|38=2|40=2|44=4100.50|10=092
TagMeaningValue
8BeginString protocol versionFIX.4.4
35MsgType message typeD (NewOrderSingle)
49 / 56SenderCompID / TargetCompIDBoth parties' CompIDs (the login "username")
34MsgSeqNum message sequence number7 (incremented within this side's session)
52SendingTimeUTC time
11ClOrdID client order IDORD10001 (the key to idempotency)
55Symbol instrumentESU6
54Side1=Buy
60TransactTimeUTC
38OrderQty quantity2
40OrdType order type2=limit
44Price4100.50
10CheckSum092

A very practical engineering point: the | is display-only; on the wire the bytes are \x01 (SOH). A raw SOH must never appear inside string values, and text values must not contain = either (use another separator). The classic rookie mistake is stuffing text containing | into a Value.

3.3 CheckSum

The 10=CheckSum algorithm: sum the ASCII codes of every byte in the whole message (from 8= through the last SOH before the trailer), take modulo 256, format as 3 decimal digits (zero-padded):

text
checksum = sum(all bytes) % 256, output like "092"
  • The calculation excludes 10= itself but includes every field's equals sign and SOH.
  • Compute the checksum before parsing the body — messages failing checksum must be dropped (usually a sign of packet splits/merges or mismatched field dictionaries).

3.4 Session Layer vs Application Layer

FIX splits concerns into two layers, and this is where integrators most often get confused:

LayerGovernsKey tags
Session layerLogin, heartbeats, sequencing, resends, disconnect/reconnect8 / 34 / 35=A / 0 / 1 / 2 / 4
Application layerOrders, cancels/replaces, reports, market data requests35=D / F / G / 8 / W etc.

The two layers must be implemented separately: when the Session layer breaks (sequence mismatch, dead heartbeats), it takes business down with it — so make the Session layer robust first (reconnect, resend, sequence persistence), then talk business logic.

💀 When the Session layer breaks, business goes down with it

When the Session layer breaks (sequence mismatch, dead heartbeats), it takes business down with it. FIX integration demands a robust Session layer first — reconnect, resend, sequence persistence — before any business logic. If order placement and cancellation depend on a fragile Session layer, a single disconnect can make all order state untrustworthy.


4. Core Message Types

MsgType (35=)NameDirectionPurpose
ALogonBoth waysLogin, negotiates heartbeat interval
0HeartbeatBoth waysKeep-alive
1TestRequestBoth waysProbe whether the peer is alive
2ResendRequestBoth waysRequest retransmission of missed messages
4SequenceResetBoth waysSequence reset (Gap Fill)
5LogoutBoth waysLogout
DNewOrderSingleClient → counterpartyPlace order
FOrderCancelRequestClient → counterpartyCancel order
GOrderCancelReplaceRequestClient → counterpartyReplace order (price/quantity)
8ExecutionReportCounterparty → clientOrder status/fill report (the report carrier)
9OrderCancelRejectCounterparty → clientCancel was rejected
WMarketDataSnapshotCounterparty → clientMarket data snapshot
X / PMarketDataIncremental / refreshCounterparty → clientMarket data increments

4.1 35=D NewOrderSingle (Placing an Order)

Required fields for ordering:

TagFieldNotes
11ClOrdIDClient order ID — the sole credential for idempotency: globally unique, never reused
55SymbolInstrument/ticker, per the counterparty's dictionary
54Side1=Buy 2=Sell (market makers have other values like 4/5)
38OrderQtyQuantity
40OrdType1=Market 2=Limit 3=stop-loss etc.
44PriceRequired for limit orders; omitted for market orders
59TimeInForce0=Day 1=GTC 3=IOC 4=FOK etc.
60TransactTimeTransaction time (UTC)

4.2 35=8 ExecutionReport (Fill Report)

The report is FIX's most complex message: every single status change of an order pushes a new 35=8, carrying dual states 39=OrdStatus and 150=ExecType. Key fields:

TagFieldNotes
11ClOrdIDThe matching client order ID (may be linked via 41=OrigClOrdID)
37OrderIDCounterparty order ID
17ExecIDUnique ID of this execution — the basis for idempotent deduplication
39OrdStatusOrder status (see section 6)
150ExecTypeExecution type (see section 6)
151LeavesQtyRemaining unfilled quantity
14CumQtyCumulative filled quantity
31LastPx / 32=LastQtyThis fill's price/quantity (one report per partial fill)
103OrdRejReasonRejection reason code

Engineering iron rule: dedupe reports by 17=ExecID; trust status from 39=OrdStatus. After reconnects and resends the same report may arrive twice; identical ExecID means drop the duplicate.

⚠️ In real markets, believing you canceled when you didn't is far more dangerous than knowing you didn't

ExecType=8 (Rejected) and ExecType=4 (Canceled) must not be conflated — Rejected means "never became an order", Canceled means "became an order and was then canceled". If after sending a cancel request you don't track the 150=6→4 confirmation chain, you may believe the order is gone when it isn't — in real markets that is far more dangerous than knowing for certain it wasn't canceled.

4.3 35=F OrderCancelRequest and 35=G Replace

MessageKey fieldsSemantics
F cancel11=ClOrdID (newly generated), 41=OrigClOrdID (original order ID), 55/54/38Request to cancel the original order; result arrives via 35=8 (success) or 35=9 (failure, e.g., already filled)
G replace11=new order ID, 41=original order ID, new 44/38The exchange processes atomically as "cancel old, place new"; some markets treat price changes as cancel+re-place, possibly losing queue position

4.4 35=A Logon (Login)

The only entry into a Session; required items:

TagFieldNotes
49 / 56SenderCompID / TargetCompIDBoth parties' CompIDs, equivalent to "accounts"
98EncryptMethodEncryption method, usually 0=none (link-layer encryption instead)
108HeartBtIntHeartbeat interval (seconds), negotiated at login
141ResetSeqNumFlagY=reset both sides' sequences (first connection/daily reset)

5. Session Lifecycle

text
       Client                                  Counterparty
         │                                      │
         │──────── 35=A Logon (108=30)────────▶│
         │◀─────── 35=A Logon (with peer seq)─────│
         │                                      │
   ┌─────▼─────┐  normal flow: messages themselves keep alive ┌─▼─────┐
   │   Logged in    │◀────────────────────────────▶│ Logged in │
   │           │  idle > N seconds → send 35=0 heartbeat   │       │
   └─────┬─────┘  no response within peer's 35=0 window →          └─┬─────┘
         │        send 35=1 TestRequest probe        │
         │        still no response → disconnect + reconnect          │
         │                                      │
         │──────── 35=5 Logout (closing)──────────▶│
         │◀─────── 35=5 Logout ──────────────────│
         ▼                                      ▼

Three core mechanisms:

  1. 34=MsgSeqNum (message sequence number): every message increments within the session; both sides track "what I've sent" and "what I expect from you". Receiving 34 larger than expected → send 35=2 ResendRequest; smaller than expected → duplicate message, discard directly or handle as Gap Fill.
  2. Heartbeat interval: negotiated at login via tag 108 (commonly 10s/30s/60s, per counterparty requirements). Send a Heartbeat proactively when idle past the interval; both sides must hear from the other before timeout (any application message counts as a heartbeat), otherwise send TestRequest; if that times out too, declare disconnection.
  3. Logout: at normal close or shutdown, send 35=5 before dropping the connection; an abrupt goodbye leaves a hung Session on the counterparty side, which may reject your reconnect or force a sequence reset.

Sequences are the lifeblood of a FIX session: they must be persisted (to disk/database). After a crash-restart you resume from the previous number, not back to 1 — otherwise the counterparty concludes "messages were lost" and demands a full resend.

💀 Persist sequences, or orders become untraceable after reconnects

Sequences are the lifeblood of a FIX session: they must be persisted (to disk/database); after a crash-restart you resume from the previous number, not back to 1. Otherwise the counterparty concludes "messages were lost" and demands a full resend; overly lenient heartbeat-timeout settings leave you "connected while the market moved on".


6. Order Status and ExecType

Every order change manifests as a 35=8, where 39=OrdStatus and 150=ExecType are two easily confused fields that must be read together:

39=OrdStatusMeaningRelation to 150=ExecType
0 NewAccepted150 also 0 (new order confirmed)
1 PartiallyFilledPartially filled150=1
2 FilledFully filled150=2
4 CanceledCanceled150=4 (or cancel subtypes of 150=6/9)
5 ReplacedReplaced150=5
6 PendingCancelCancel submitted, not yet confirmed150=6
8 RejectedRejected, order does not exist150=8 (carries 103=RejReason)
A PendingNewSubmitted, not yet confirmed150=A
E PendingReplaceReplacement submitted, not yet confirmed150=E

How to read them (one sentence): 39 describes "what the order looks like now"; 150 narrates "which change this message reports". E.g., after sending a cancel you first receive 150=6 PendingCancel, and only when the 39=4 Canceled report follows is the cancel actually successful; if 150=6 is followed by 35=9 OrderCancelReject, the cancel failed and the order lives.

  • ExecType=8 (Rejected) and ExecType=4 (Canceled) must not be conflated: Rejected means "never became an order", Canceled means "became an order and was then canceled".
  • On partial fills, 32/31 (LastQty/LastPx) update per fill and 14/151 (CumQty/LeavesQty) follow — use 14 and 151 for remaining quantity; don't accumulate 32 yourself (resends would double-count).

7. FIX Pros and Cons

7.1 Advantages

AdvantageNotes
StandardizationOne global field dictionary; low cost migrating across markets/counterparties — "know FIX, know them all"
Mature and reliableThirty years of industry hardening; the Session layer (sequencing, resend, heartbeat) is extremely robust
Full-duplex, full-featuredOrders, cancels/replaces, reports, market data, maker quotes — all in one protocol
Rich ecosystemOpen-source engines (QuickFIX/QuickFIXJ, OnixS commercial), test tools, complete dictionaries

7.2 Disadvantages

DisadvantageNotes
ComplexityText protocol + sequencing + resend + heartbeat; the Session layer is far more work than REST; dictionary version management is a standing burden
No built-in securityPlaintext, no auth encryption; security comes from the link layer (dedicated lines/TLS)
InefficientLarge text payloads, slow parsing; high-throughput scenarios need FAST compression (see section 8)
Detail hellEvery firm uses optional fields, subtypes, and error codes differently — same protocol, different counterparties still need per-firm integration testing

7.3 Versus Exchange Proprietary APIs

DimensionFIXExchange proprietary APIs (crypto REST/WS, CTP binary)
GeneralityCross-market, cross-counterpartyEach venue has its own formats and authentication
Ramp-up costHigh (Session layer + dictionary)Low (SDK/docs provided)
LatencyRelatively high for text; FAST helps compressBinary/JSON designed per scenario, generally faster
Status semanticsHighly standardized (39/150)Different enums per venue, needs mapping
Best fitOverseas institutional connectivity, unified cross-market egressSingle-market deep integration, crypto HFT

7.4 When You Actually Need Direct FIX Connectivity

  • The counterparty only offers FIX (CME and other exchanges, most overseas brokers, interbank).
  • You need one codebase for multiple markets: unify the OMS egress over FIX, hide market differences in configuration.
  • You need institution-grade reliability semantics (sequence resend, reconciliation, audit): REST polling can't provide these.
  • Not needed: domestic futures counters only (use CTP), crypto-only (official REST/WS is simpler) — FIX isn't "more advanced", it's "a requirement of a different market".

8. Derivative Specs: FAST and the Crypto Landscape

8.1 FAST (FIX Adapted for STreaming)

  • What it is: a compression encoding spec from the FIX Protocol organization for market data/high-throughput scenarios, using templates (XML describing field encoding) + bitmaps to shrink payloads dramatically — market data volume compressed to a tenth of text FIX or lower.
  • Where it's used: real-time market data direct feeds at CME etc.; order acknowledgments mostly remain plain FIX.
  • Engineering cost: template management, delta encoding (values only sent when changed from prior field), out-of-order recovery are all new complexity — FAST isn't "readable and done"; the decoder must strictly match their templates.
  • Concept check: FAST is an encoding layer inside the same protocol family, not a new protocol; confirm upfront whether the counterparty wants "FIX Session + FAST market data" or plain FIX.

8.2 Crypto Exchanges' Current FIX Support

ExchangeFIX supportNotes (official docs authoritative)
BinanceYesInstitutional-grade FIX interface (with test environment), aimed at makers/institutions
OKXYesOffers a FIX interface for institutional clients
BybitYesOffers a FIX interface
Other mid/small venuesMostly REST/WSFIX mainly appears at top-tier exchanges

Characteristics of crypto FIX:

  • Authentication is usually a variant of "API Key + pre-shared secret/signature", not traditional CompID password pairs — read their docs carefully before integrating.
  • Price precision, tick sizes, and order type enums differ entirely from domestic conventions; field mapping must be done item by item.
  • For most individuals and small/mid teams, official REST/WebSocket remains the better choice; FIX is merely one option on the "institutional channel" menu.

Risk Warning

⚠️ Risk Warning

FIX incidents concentrate in the Session layer: unpersisted sequences leaving orders untraceable after reconnects; overly lenient heartbeat timeouts leaving you "connected while the market moved on"; cancel requests sent without tracking the 150=6→4 confirmation chain, so you believe the order is gone when it isn't. In real markets, "believing you canceled" is far more dangerous than "knowing you didn't". Always remember: persist sequences and order state; on disconnect reconnect first, then resend, then resume ordering; validate every field against the counterparty's dictionary; complete disconnect-injection drills (pulling cables, sequence rollback, duplicate reports) in the counterparty's test environment before launch. Protocol details here defer to official FIX documentation and the counterparty's onboarding specs.

Further Reading

For study and research only — not investment advice. Markets are risky.