Note: when a crypto exchange decides to enter the institutional market, the first question from clients is the availability of FIX API. Without it, prime brokers and HFT firms won't connect—their robots cannot work with REST. The FIX protocol is the standard for low-latency trading, used on traditional exchanges since the late 20th century. We develop turnkey FIX API, ensuring compatibility with QuickFIX, high throughput (up to 10,000 messages/sec), and a reliable session model with automatic recovery. Our experience includes implementing FIX servers for exchanges with daily trading volumes exceeding $100 million. For such an exchange, switching to FIX API can save up to $200,000 per year in transaction costs. In this article, we will dive into the FIX server architecture, typical integration problems, and stages of work. Order FIX API development—contact us for a consultation.
FIX API: Why Development Is Critical for a Crypto Exchange
FIX is a text-based protocol over TCP. A message is a set of tag=value fields separated by SOH (0x01): 8=FIX.4.4 | 9=178 | 35=D | 49=CLIENT1 | 56=EXCHANGE | 34=123 | 52=20241201-14:30:00.000 | 11=ORDER-001 | 55=BTC/USD | 54=1 | 38=0.1 | 40=2 | 44=42000 | 59=1 | 10=087. Key tags: 35=D (New Order Single), 55 — instrument, 54 — side, 38 — quantity, 40 — order type, 44 — price, 59 — Time in Force.
FIX is preferred over REST for institutions for several reasons. Standard protocol—their systems already know how to work with it. Low latency: microsecond delays vs. millisecond for REST—FIX is 10–50 times faster. Reliable session model with automatic recovery after disconnects and message sequencing.
What Problems Does FIX API Solve During Integration?
Handling Multiple Simultaneous Sessions
Each client connects via a separate FIX session with unique CompID. The server must correctly process thousands of sessions without losing message order. Sequencing (MsgSeqNum) guarantees integrity: on disconnect, the client sends a ResendRequest, and the server retransmits missed messages. Our tests show stable operation with 2000+ concurrent sessions at 5000 orders/sec load.
Recovery After Connection Break
A FIX session supports automatic reconnection with sequence recovery. HeartBtInt (heartbeat) and ReconnectInterval are configured in the config file. If a session is lost, the server sends a SequenceReset to synchronize. We test break scenarios with 1000 concurrent sessions, guaranteeing zero data loss.
Authentication Without Built-in Means
FIX 4.4 has no built-in authentication. We use a combination: IP whitelist + TLS + custom field 96 (RawData) for signed API key. Example validation in FromAdmin.
How We Implement a FIX Server
QuickFIX/Go as Primary Implementation
QuickFIX is the reference implementation of FIX engine with ports for Go, Java, C++, Python. The Go version (quickfixgo) is an excellent base for a production exchange.
import (
"github.com/quickfixgo/quickfix"
"github.com/quickfixgo/quickfix/field"
"github.com/quickfixgo/quickfix/fix44"
"github.com/quickfixgo/quickfix/fix44/newordersingle"
)
type FIXApplication struct {
orderEngine *OrderEngine
sessionManager *SessionManager
}
func (app *FIXApplication) OnCreate(sessionID quickfix.SessionID) {
log.Info("FIX session created", "sessionID", sessionID)
}
func (app *FIXApplication) OnLogon(sessionID quickfix.SessionID) {
log.Info("FIX client logged on", "sessionID", sessionID)
app.sessionManager.SetOnline(sessionID)
}
func (app *FIXApplication) OnLogout(sessionID quickfix.SessionID) {
log.Info("FIX client logged out", "sessionID", sessionID)
app.sessionManager.SetOffline(sessionID)
}
func (app *FIXApplication) FromApp(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, err := msg.Header.GetString(field.NewMsgType())
if err != nil {
return err
}
switch msgType {
case "D": // New Order Single
return app.handleNewOrder(msg, sessionID)
case "F": // Order Cancel Request
return app.handleCancelOrder(msg, sessionID)
case "G": // Order Cancel/Replace Request (amend)
return app.handleAmendOrder(msg, sessionID)
case "H": // Order Status Request
return app.handleStatusRequest(msg, sessionID)
}
return quickfix.NewMessageRejectError("Unknown message type", 35, nil)
}
Handling New Order Single
func (app *FIXApplication) handleNewOrder(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
nos := newordersingle.New(
field.NewClOrdID(""),
field.NewSide(0),
field.NewTransactTime(time.Now()),
field.NewOrdType(0),
)
if err := quickfix.Unmarshal(msg, &nos); err != nil {
return err
}
clOrdID, _ := nos.GetClOrdID()
symbol, _ := nos.GetSymbol()
sideInt, _ := nos.GetSide()
ordType, _ := nos.GetOrdType()
qty, _ := nos.GetOrderQty()
price, _ := nos.GetPrice()
tif, _ := nos.GetTimeInForce()
order := Order{
ClientOrderID: string(clOrdID),
Pair: normalizePair(string(symbol)),
Side: fixSideToInternal(sideInt),
Type: fixOrdTypeToInternal(ordType),
Quantity: decimal.NewFromFloat(float64(qty)),
Price: decimal.NewFromFloat(float64(price)),
TimeInForce: fixTIFToInternal(tif),
}
app.sendExecReport(sessionID, order, ExecTypeNew, OrdStatusPendingNew)
trades, err := app.orderEngine.PlaceOrder(order)
if err != nil {
app.sendExecReport(sessionID, order, ExecTypeRejected, OrdStatusRejected)
return nil
}
for _, trade := range trades {
app.sendFillReport(sessionID, order, trade)
}
if order.RemainingQty().IsPositive() {
status := OrdStatusNew
if len(trades) > 0 {
status = OrdStatusPartiallyFilled
}
app.sendExecReport(sessionID, order, ExecTypeNew, status)
}
return nil
}
Sending Execution Report
func (app *FIXApplication) sendExecReport(sessionID quickfix.SessionID, order Order, execType ExecType, ordStatus OrdStatus) {
report := fix44executionreport.New(
field.NewOrderID(order.ID),
field.NewExecID(generateExecID()),
field.NewExecType(fix44.ExecType(execType)),
field.NewOrdStatus(fix44.OrdStatus(ordStatus)),
field.NewSymbol(denormalizePair(order.Pair)),
field.NewSide(fix44.Side(internalSideToFIX(order.Side))),
field.NewLeavesQty(order.RemainingQty().InexactFloat64(), 8),
field.NewCumQty(order.FilledQty.InexactFloat64(), 8),
field.NewAvgPx(order.AvgPrice().InexactFloat64(), 8),
)
report.SetClOrdID(order.ClientOrderID)
report.SetOrderQty(order.Quantity.InexactFloat64(), 8)
report.SetTransactTime(time.Now())
quickfix.SendToTarget(report.ToMessage(), sessionID)
}
Session Model and Security
A FIX session maintains sequencing: each message has MsgSeqNum (34). On connection break, the client resumes the session with the last known SeqNum. The server can send ResendRequest (2) or SequenceReset (4).
Example FIX session configuration
func createFIXSettings() *quickfix.Settings {
settings := quickfix.NewSettings()
globalSection := quickfix.NewSessionSettings()
globalSection.Set("FileStorePath", "./fix-sessions")
globalSection.Set("FileLogPath", "./fix-logs")
settings.GlobalSettings().SetGlobalSection(globalSection)
sessionSection := quickfix.NewSessionSettings()
sessionSection.Set(quickfix.BeginString, "FIX.4.4")
sessionSection.Set(quickfix.SenderCompID, "EXCHANGE")
sessionSection.Set(quickfix.TargetCompID, "CLIENT1")
sessionSection.Set("HeartBtInt", "30")
sessionSection.Set("ReconnectInterval", "5")
sessionSection.Set("StartTime", "00:00:00")
sessionSection.Set("EndTime", "00:00:00")
return settings
}
FIX 4.4 has no built-in authentication. Standard approaches:
- IP whitelist: only allowed IPs connect to the FIX port.
- TLS: encryption of the connection (FIX over SSL).
- Logon with password: field 96 (RawData) or custom tag for signed API key.
func (app *FIXApplication) FromAdmin(msg *quickfix.Message, sessionID quickfix.SessionID) quickfix.MessageRejectError {
msgType, _ := msg.Header.GetString(field.NewMsgType())
if msgType == "A" { // Logon
apiKey, _ := msg.Body.GetString(9001)
signature, _ := msg.Body.GetString(9002)
timestamp, _ := msg.Body.GetString(9003)
if !app.auth.Verify(apiKey, signature, timestamp) {
return quickfix.NewMessageRejectError("Authentication failed", 58, nil)
}
app.sessionManager.SetAPIKey(sessionID, apiKey)
}
return nil
}
FIX Connection Security: Three Layers of Protection
We guarantee protection at three levels: transport (TLS), network (IP whitelist), and application (signed authentication). Additionally, we implement session auditing and Drop Copy for compliance. This is the standard for exchanges working with institutional clients.
Scope of Work for FIX API Development
- Development of FIX 4.4 server in Go (QuickFIX)
- Implementation of standard messages: New Order, Cancel, Amend, Execution Reports
- Market Data feed (order book and trades subscription)
- Security: TLS, IP whitelist, key authentication
- Drop Copy for compliance
- Documentation and testing (load, regression)
- Team training and support during rollout
Process and Timelines
- Analysis: study your requirements and existing architecture.
- Design: develop session scheme, message sequencing, and security policies.
- Implementation: write code—from message parsing to matching engine interaction.
- Testing: load (1000+ orders/sec) and regression.
- Deployment: rollout, monitoring, and training your team.
Estimated timelines: from 4 weeks for basic integration to 2–3 months for a full production-ready solution.
| Feature | FIX | REST |
|---|---|---|
| Latency | Microseconds (<100 μs) | Milliseconds |
| Reliability | Built-in recovery | More complex |
| Authentication | External (TLS + keys) | API keys |
| Standardization | Single protocol | Different implementations |
| Stage | Duration |
|---|---|
| Analysis and design | 1–2 weeks |
| Basic server development | 3–4 weeks |
| Market Data and Drop Copy | 2–3 weeks |
| Testing (load, regression) | 2 weeks |
| Deployment and training | 1 week |
Typical Mistakes in FIX API Development
Incorrect sequencing: if MsgSeqNum gets out of sync, the session enters a broken state. Use file or database storage for SeqNum, not in-memory. Ignoring HeartBtInt: clients disconnect in the absence of heartbeats. Set HeartBtInt to 30 seconds and handle MissedHeartBeat. Missing ResendRequest: on break, the client must request retransmission. Ensure the server stores all messages for replay.
Get a consultation on FIX API for your exchange—contact us to assess the scope of work. Request a test integration: we will provide access to a FIX server instance for your developers.
FIX protocol specification: FIX protocol







