◈   ⌘ api · Advanced

Binance FIX API for Institutional Traders: Complete Guide

Master Binance FIX API for institutional crypto trading. Learn authentication, order routing, response parsing, and error handling with Python code examples.

Uncle Solieditor · voc · 05.05.2026 ·views 15
◈   Contents
  1. → What Is FIX API and Why Institutions Use It
  2. → Access Requirements and Account Setup
  3. → Setting Up the FIX Connection and Authentication
  4. → Placing Orders with New Order Single
  5. → Parsing Execution Reports and Handling Errors
  6. → FIX API vs REST API: When to Use Each
  7. → Frequently Asked Questions
  8. → Conclusion

If you're moving serious volume — think hundreds of BTC per day — the standard Binance REST API starts feeling like a garden hose when you need a fire main. That's where FIX API comes in. Financial Information eXchange (FIX) protocol is the backbone of institutional trading in both traditional finance and, increasingly, crypto. Binance's FIX API endpoint gives institutional clients sub-millisecond order routing, dedicated infrastructure, and the kind of reliability that high-frequency desks and market makers actually need.

What Is FIX API and Why Institutions Use It

FIX (Financial Information eXchange) is a messaging protocol developed in the early 1990s for real-time electronic trading. It has been the standard in equities, FX, and derivatives for three decades — and now Binance has brought it to crypto. Unlike REST, which is stateless and HTTP-based, FIX uses persistent TCP connections, meaning your orders travel over a socket that stays open rather than opening and closing with every request. The result is dramatically lower latency and far higher throughput.

Binance FIX API is only available to institutional clients who have completed KYB onboarding. Retail accounts cannot access fix-oe.binance.com. Contact Binance institutional sales if you are processing significant monthly volume and need dedicated infrastructure.

Access Requirements and Account Setup

Before writing a single line of code, you need institutional access. Binance requires a formal application, KYB (Know Your Business) verification, and typically a minimum volume threshold. Once approved, you receive credentials for the Order Entry (OE) endpoint at fix-oe.binance.com and optionally the Market Data (MD) endpoint. Your API key and secret are used to sign the Logon message — Binance does not use traditional API key headers like the REST API does. Platforms like Bybit and OKX have comparable institutional FIX programs worth evaluating during your venue selection phase.

Binance FIX API Endpoints
EndpointHostPortPurpose
Order Entryfix-oe.binance.com9000Place, cancel, query orders
Market Datafix-md.binance.com9000L2 order book, trade stream
Drop Copyfix-dc.binance.com9000Execution report copy feed
Testnet OEfix-oe.testnet.binance.vision9000Testing and staging

Setting Up the FIX Connection and Authentication

Authentication on Binance FIX API uses HMAC-SHA256 signing embedded in the Logon message, similar in concept to REST API signing but formatted as FIX tags. The signature payload combines specific message fields joined by the SOH delimiter. The simplefix library in Python makes building FIX messages significantly easier than rolling your own byte-level implementation. Install it with pip install simplefix before running the examples below.

import simplefix
import socket
import ssl
import hashlib
import hmac
import time

# Binance FIX API credentials
API_KEY = "your_api_key"
API_SECRET = "your_api_secret"
FIX_HOST = "fix-oe.binance.com"
FIX_PORT = 9000
SENDER_COMP_ID = "your_client_id"  # assigned by Binance on onboarding
TARGET_COMP_ID = "BINANCE"

def build_logon(seq_num: int) -> bytes:
    # Create and sign a FIX Logon (MsgType=A) message
    ts = str(int(time.time() * 1000))

    # Signature payload: fields joined with SOH delimiter (\x01)
    raw_data = f"{ts}\x01{SENDER_COMP_ID}\x01{TARGET_COMP_ID}\x01{seq_num}\x01A"
    signature = hmac.new(
        API_SECRET.encode("utf-8"),
        raw_data.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()

    msg = simplefix.FixMessage()
    msg.append_pair(8,   "FIX.4.4")
    msg.append_pair(35,  "A")             # MsgType = Logon
    msg.append_pair(49,  SENDER_COMP_ID)  # SenderCompID
    msg.append_pair(56,  TARGET_COMP_ID)  # TargetCompID
    msg.append_pair(34,  seq_num)         # MsgSeqNum
    msg.append_pair(52,  ts)              # SendingTime
    msg.append_pair(98,  0)               # EncryptMethod = None
    msg.append_pair(108, 30)              # HeartBtInt = 30 seconds
    msg.append_pair(95,  len(signature))  # RawDataLength
    msg.append_pair(96,  signature)       # RawData = HMAC-SHA256 hex
    msg.append_pair(554, API_KEY)         # Password = your API key
    return msg.encode()

# Establish TLS connection to Binance FIX OE endpoint
context = ssl.create_default_context()
raw_sock = socket.create_connection((FIX_HOST, FIX_PORT), timeout=10)
tls_sock = context.wrap_socket(raw_sock, server_hostname=FIX_HOST)

# Send Logon and read acknowledgement
tls_sock.sendall(build_logon(seq_num=1))
response = tls_sock.recv(4096)
print(f"Logon response received: {len(response)} bytes")

Placing Orders with New Order Single

Once logged on, order placement is straightforward. New Order Single (tag 35=D) is the workhorse message for limit and market orders. Every order needs a client-assigned ClOrdID (tag 11) — this is your internal reference that Binance echoes back in all execution reports for that order. Many trading systems use a timestamp-based ID or a UUID. Signal services like VoiceOfChain push trade signals that feed directly into this order pipeline, triggering FIX execution the moment a signal fires rather than waiting for manual action.

def place_limit_order(
    sock: ssl.SSLSocket,
    seq_num: int,
    symbol: str,
    side: str,
    quantity: float,
    price: float
) -> str:
    # Send a New Order Single (D) — returns ClOrdID for tracking
    cl_ord_id = f"VOC-{int(time.time() * 1000)}"
    ts = str(int(time.time() * 1000))
    side_code = "1" if side.upper() == "BUY" else "2"

    msg = simplefix.FixMessage()
    msg.append_pair(8,   "FIX.4.4")
    msg.append_pair(35,  "D")            # MsgType = NewOrderSingle
    msg.append_pair(49,  SENDER_COMP_ID)
    msg.append_pair(56,  TARGET_COMP_ID)
    msg.append_pair(34,  seq_num)        # MsgSeqNum
    msg.append_pair(52,  ts)             # SendingTime
    msg.append_pair(11,  cl_ord_id)      # ClOrdID — your internal order ID
    msg.append_pair(55,  symbol)         # Symbol e.g. "BTCUSDT"
    msg.append_pair(54,  side_code)      # Side: 1=Buy, 2=Sell
    msg.append_pair(60,  ts)             # TransactTime
    msg.append_pair(38,  str(quantity))  # OrderQty
    msg.append_pair(40,  "2")            # OrdType: 2=Limit
    msg.append_pair(44,  str(price))     # Price
    msg.append_pair(59,  "1")            # TimeInForce: 1=GTC

    sock.sendall(msg.encode())
    return cl_ord_id

# Example: Buy 0.5 BTC at $64,500 on Binance institutional OE
ord_id = place_limit_order(
    tls_sock, seq_num=2,
    symbol="BTCUSDT",
    side="BUY",
    quantity=0.5,
    price=64500.0
)
print(f"Order submitted — ClOrdID: {ord_id}")

For market orders, change tag 40 to '1' (Market) and omit the price field (tag 44). For immediate-or-cancel execution, set tag 59 to '3'. Binance FIX also supports Order Cancel Request (MsgType=F) and Order Cancel/Replace Request (MsgType=G) for modifying live orders without cancelling and resubmitting — a significant latency advantage over REST when working within tight execution windows.

Parsing Execution Reports and Handling Errors

Every order action generates an Execution Report (MsgType=8). Reading and acting on these correctly is where most FIX integrations either work well or fail quietly. The key fields are ExecType (tag 150) and OrdStatus (tag 39) — together they tell you exactly what happened to your order. A fill comes back as ExecType=F, a rejection as OrdStatus=8. Build your handler before going live — silent failures on institutional-size positions are very expensive.

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("fix_handler")

EXEC_TYPE_LABELS = {
    b"0": "New",
    b"1": "Partial Fill",
    b"4": "Cancelled",
    b"8": "Rejected",
    b"F": "Trade (fill)",
}

ORD_REJECT_REASONS = {
    b"0": "Broker option",
    b"1": "Unknown symbol",
    b"3": "Order exceeds limit",
    b"6": "Duplicate order",
    b"11": "Insufficient funds",
    b"99": "Other",
}

def handle_execution_report(msg: simplefix.FixMessage) -> dict:
    exec_type = msg.get(150)
    ord_status = msg.get(39)
    result = {
        "cl_ord_id": msg.get(11, b"").decode(),
        "order_id":  msg.get(37, b"").decode(),
        "symbol":    msg.get(55, b"").decode(),
        "exec_type": EXEC_TYPE_LABELS.get(exec_type, str(exec_type)),
        "cum_qty":   float(msg.get(14,  b"0")),
        "leaves_qty":float(msg.get(151, b"0")),
        "avg_px":    float(msg.get(6,   b"0")),
    }

    if ord_status == b"8":  # Rejected
        reason_code = msg.get(103)
        reason = ORD_REJECT_REASONS.get(reason_code, b"Unknown")
        result["error"] = reason.decode() if isinstance(reason, bytes) else reason
        logger.error(f"Order rejected [{result['cl_ord_id']}]: {result['error']}")

    elif exec_type == b"F":  # Full or partial fill
        logger.info(
            f"Fill: {result['cl_ord_id']} | "
            f"filled={result['cum_qty']} @ avg ${result['avg_px']} | "
            f"remaining={result['leaves_qty']}"
        )
    return result

def receive_messages(sock: ssl.SSLSocket):
    parser = simplefix.FixParser()
    while True:
        try:
            data = sock.recv(4096)
            if not data:
                raise ConnectionResetError("Server closed connection")
            parser.append_buffer(data)
            while True:
                msg = parser.get_message()
                if msg is None:
                    break
                msg_type = msg.get(35)
                if msg_type == b"8":    # Execution Report
                    handle_execution_report(msg)
                elif msg_type == b"0": # Heartbeat — must echo
                    logger.debug("Heartbeat received")
                elif msg_type == b"3": # Session-level Reject
                    logger.warning(f"Session reject: {msg.get(58)}")
        except (socket.timeout, ConnectionResetError) as e:
            logger.error(f"Connection lost: {e} — reconnect required")
            break
Always implement a heartbeat handler. Binance will disconnect sessions that fail to respond to Heartbeat (MsgType=0) or TestRequest (MsgType=1) messages within the HeartBtInt specified at logon (recommended: 30 seconds). A silent disconnect with open positions and no reconnect logic is the most dangerous failure mode in any FIX integration.

FIX API vs REST API: When to Use Each

Not every Binance integration needs FIX. If you are running a basic bot trading a few times per hour, the REST API is perfectly adequate. FIX becomes essential when latency and throughput are the real bottleneck. Bybit and OKX both offer FIX for institutional clients, and the message structure is similar enough that a well-architected FIX client can support multiple venues with minimal changes. Gate.io and KuCoin remain REST-only for most institutional clients as of 2025, though WebSocket execution is available on both.

FIX API vs REST API Comparison
FeatureFIX APIREST API
ConnectionPersistent TCP/TLSStateless HTTP
Latency< 1ms typical5–50ms typical
ThroughputThousands of orders/secRate-limited (1200 req/min)
Setup complexityHighLow
AccessInstitutional onlyAll accounts
Execution reportsPushed in real-timeMust poll or use WebSocket
Best forHFT, market making, large desksRetail bots, low-frequency strategies

For algo traders operating somewhere in the middle — a systematic fund running 50–200 orders per day — a hybrid approach often works well. Use REST for account management, balance queries, and non-time-sensitive operations, while routing live order execution through FIX. VoiceOfChain's signal output integrates cleanly at this layer: signals arrive via the platform's API, get validated, then get dispatched to the FIX socket for execution with minimal latency overhead between signal and fill.

Frequently Asked Questions

How do I get access to Binance FIX API?
Binance FIX API requires institutional onboarding — you cannot enable it from standard account settings. Contact Binance's institutional team with your monthly trading volume and use case description. Approval typically takes 3–10 business days and includes dedicated endpoint credentials.
Can I test FIX API without a live account?
Yes. Binance provides a testnet FIX endpoint at fix-oe.testnet.binance.vision on port 9000. You need separate testnet API credentials generated at testnet.binance.vision — they are distinct from mainnet keys. Always validate your full order lifecycle on testnet before connecting to production.
What happens to open orders if my FIX session drops?
Open orders placed via FIX remain active on Binance's side — the session dropping does not cancel them. On reconnect, Binance will resend any execution reports you missed via gap-fill using MsgSeqNum sequencing. You should also query open orders via REST after a disconnect to fully reconcile local state.
Is Binance FIX API available for futures as well as spot?
Binance offers FIX for both spot and USDM futures, though the futures endpoint and some tag mappings differ from spot. Confirm the specific endpoint and any venue-specific tag extensions with your institutional relationship manager before building your futures integration.
What Python library should I use for a FIX client?
simplefix is the most commonly used Python library for constructing and parsing FIX messages — it is lightweight and well-maintained. For production systems with extreme throughput requirements, consider QuickFIX (C++) or QuickFIX/n (C#), as Python will eventually hit GIL-related throughput limits at very high order rates.
How does Binance FIX compare to Bybit or OKX institutional APIs?
All three use FIX 4.4 with HMAC-SHA256 authentication over persistent TLS connections. The tag schemas are mostly compatible with minor venue-specific extensions. Binance generally offers the deepest liquidity on BTC and ETH pairs, while OKX and Bybit sometimes offer advantages on altcoin pairs and perpetual funding rates.

Conclusion

Binance FIX API is not a weekend project — it requires institutional access, solid understanding of the FIX protocol, and careful session management. But for desks handling serious volume, the latency and throughput improvements are decisive. The three code examples above cover the core of what you need: an authenticated session, order submission, and execution report handling with proper error logic. Build on testnet first, validate every message field against Binance's official FIX specification, and implement heartbeat handling before anything else. When paired with a reliable signal source like VoiceOfChain, a FIX-based execution layer gives you the full stack — from signal to fill — with institutional-grade speed.

◈   more on this topic
◉ basics Mastering the ccxt library documentation for crypto traders ⌂ exchanges Mastering the Binance CCXT Library for Crypto Traders ⌬ bots Best Crypto Trading Bots 2025: Profitable AI-Powered Strategies