Binance

September 27, 2026 · View on GitHub

Founded in 2017, Binance is one of the largest cryptocurrency exchanges in terms of daily trading volume, and open interest of crypto assets and crypto derivative products.

NautilusTrader provides Binance integration for live market data and execution. The adapter is implemented in Rust and exposed to Python through the same public configurations, factories, and data types.

Supported products:

  • Binance Spot (including Binance US)
  • Binance USDT-Margined Futures (crypto and TradFi perpetuals; current and next monthly and quarterly delivery contracts)
  • Binance Coin-Margined Futures (perpetuals and current or next quarterly delivery contracts)

Examples

Overview

The adapter exposes these public components:

  • BinanceDataClientConfig and BinanceExecutionClientConfig: Live client configuration.
  • BinanceInstrumentProviderConfig: Instrument selection, filtering, and warning policy.
  • BinanceDataClientFactory and BinanceExecutionClientFactory: Trading node client factories.
  • load_binance_instruments: Standalone configured instrument discovery.
  • load_binance_order_book_deltas: Rust-backed Binance depth CSV loading for order book wrangling.
  • BINANCE, BINANCE_CLIENT_ID, BINANCE_VENUE, and the client-order-ID decoders: Public identifiers and decoding utilities.

:::note Most users need only the configs and factories, wired into a live trading node as shown under Live node configuration. The remaining components serve standalone loading and offline decoding. :::

Low-level HTTP and WebSocket clients, their caches, and product-specific instrument provider objects are not exposed through the Python API. Use the live configs and factories, or the standalone instrument loader, instead of depending on those internals.

For standalone discovery, pass the same data-client and provider configuration used by a live client:

import asyncio

from nautilus_trader.adapters.binance import BinanceDataClientConfig
from nautilus_trader.adapters.binance import BinanceInstrumentProviderConfig
from nautilus_trader.adapters.binance import BinanceProductType
from nautilus_trader.adapters.binance import load_binance_instruments

config = BinanceDataClientConfig(
    product_type=BinanceProductType.USD_M,
    instrument_provider=BinanceInstrumentProviderConfig(
        load_all=False,
        load_ids=["BTCUSDT-PERP.BINANCE"],
    ),
)
instruments = asyncio.run(load_binance_instruments(config))

This function supports Spot, USD-M, and COIN-M. It uses the configured environment, URLs, proxy, receive window, Binance US mode, filters, warning policy, and commission policy. Margin is not a supported Binance product and is rejected.

For Binance depth CSV data, call the stateless loader directly:

from nautilus_trader.adapters.binance import load_binance_order_book_deltas

df = load_binance_order_book_deltas(path, nrows=1_000_000)

The loader preserves the source values and column order. File-open failures and invalid numeric or side values raise RuntimeError.

Product support

Product TypeSupportedNotes
Spot Markets (incl. Binance US)✓
Margin Accounts (Cross & Isolated)-Not implemented.
USDT-Margined Futures (PERP & Delivery)✓Monthly and quarterly delivery contracts.
Coin-Margined Futures (PERP & Delivery)✓Quarterly delivery contracts.

:::note Margin account features such as borrow, repay, and isolated margin management are not implemented. :::

:::info Each Binance client instance handles one product type. The configs use a singular product_type field, and the live factories create one data or execution client from one config. To run Spot and Futures in the same node, configure separate clients with distinct IDs such as BINANCE_SPOT and BINANCE_FUTURES, then pass the matching client_id when a strategy subscribes or submits orders. When using both execution clients, configure an explicit BINANCE venue route or a default client as described in Execution client routing. See the current Python examples for complete client setup. :::

Data types

The integration includes several custom data types:

  • BinanceSpotTicker: Spot 24-hour ticker data including prices, volumes, and trade statistics.
  • BinanceFuturesTicker: Futures 24-hour ticker data including price and statistics.
  • BinanceBar: Bar data with additional volume metrics for historical and real-time use.
  • BinanceFuturesMarkPriceUpdate: Futures mark data including the estimated settlement price.
  • BinanceFuturesLiquidation: Futures liquidation events from the forceOrder stream.
  • BinanceFuturesOpenInterest: Current Futures open interest snapshot (request only).
  • BinanceFuturesOpenInterestHist: Futures open interest history for a period (request only).

See the Binance API Reference for full definitions.

BinanceBar, BinanceFuturesTicker, BinanceFuturesOpenInterest, and BinanceFuturesLiquidation support Arrow/Parquet catalog persistence under data/custom/{TypeName}/{identifier}. Rust builds need the nautilus-binance arrow feature flag for this persistence. Reads also discover the legacy Python-written data/custom_<snake_case> layout (for example data/custom_binance_bar); migrate the catalog with nautilus catalog migrate-parquet to move legacy files to the canonical layout.

Symbology

Native Binance symbols are used where possible for spot and futures contracts. Because NautilusTrader supports multi-venue trading, it must distinguish between BTCUSDT the spot pair and BTCUSDT the perpetual futures contract (Binance uses the same symbol for both).

Nautilus appends -PERP to USD-M perpetual symbols. For example, the Binance USD-M BTCUSDT perpetual becomes BTCUSDT-PERP. USD-M TRADIFI_PERPETUAL listings use the same suffix, so XAUUSDT becomes XAUUSDT-PERP.

The adapter maps TRADIFI_PERPETUAL listings to PerpetualContract and derives their asset class from Binance's underlyingType:

Binance underlyingTypeNautilus asset class
EQUITY, CN_EQUITY, KR_EQUITY, HK_EQUITY, PREMARKETEquity
COMMODITYCommodity

Listings with other or missing values are skipped with a warning.

The adapter preserves Binance's native _PERP suffix for COIN-M perpetuals, so BTCUSD_PERP remains unchanged.

Delivery symbols keep Binance's _YYMMDD suffix. For example, BTCUSDT_260925 and BTCUSD_260925 remain unchanged within Nautilus. USD-M supports the documented CURRENT_MONTH, NEXT_MONTH, CURRENT_QUARTER, and NEXT_QUARTER contract types. COIN-M supports CURRENT_QUARTER and NEXT_QUARTER. Contract availability varies by environment and listing cycle.

USD-M delivery instruments are linear and settle in the margin asset. COIN-M delivery instruments are inverse, settle in the margin asset (the base currency), and use Binance's contractSize as the instrument multiplier. Both use onboardDate and deliveryDate for activation and expiration. See Binance's official USD-M common definitions and COIN-M common definitions.

The Rust Futures data tester accepts a delivery instrument without source edits:

BINANCE_FUTURES_INSTRUMENT_ID=BTCUSDT_260925.BINANCE \
  cargo run -p nautilus-binance --example binance-futures-data-tester --features examples

Spot notional constraints

Spot instruments loaded through SBE or JSON populate the dedicated min_notional and max_notional fields from MIN_NOTIONAL and NOTIONAL filters. When both filters are present, the parser uses the strictest bounds. These fields hold quote-currency Money values at the currency's precision.

The risk engine checks these instrument fields using its price estimates. Instrument info is metadata for downstream actors and strategies and does not affect risk decisions. Binance applies its market-order flags and reference-price rules when validating orders at the venue.

PostgreSQL preserves instrument metadata when restoring instruments. After upgrading an existing database, run nautilus database init --schema "$PWD/schema/sql" from the repository root to add metadata storage. Previously discarded metadata requires reloading instrument definitions.

Order capability

The following tables detail order types, execution instructions, and time-in-force options across the supported Binance products.

Order types

Order TypeSpotUSDT FuturesCoin FuturesNotes
MARKET✓✓✓Quote quantity support: Spot only.
LIMIT✓✓✓
STOP_MARKET✓✓✓Spot sends Binance STOP_LOSS.
STOP_LIMIT✓✓✓Spot sends Binance STOP_LOSS_LIMIT.
MARKET_IF_TOUCHED✓✓✓Spot sends Binance TAKE_PROFIT.
LIMIT_IF_TOUCHED✓✓✓Spot sends Binance TAKE_PROFIT_LIMIT.
TRAILING_STOP_MARKET-✓✓Futures only.

Binance Spot publishes a supported order-type set per symbol in exchangeInfo. The adapter does not filter on it, so a conditional Spot order for a type the symbol does not support is rejected by the venue rather than locally.

Execution instructions

InstructionSpotUSDT FuturesCoin FuturesNotes
post_only✓✓✓See restrictions below.
reduce_only-✓✓Futures only; translated to positionSide in Hedge Mode.

In One-way Mode, the adapter sends Binance's reduceOnly field. Binance does not accept that field in Hedge Mode, so the adapter instead selects the closing positionSide. This keeps the order on the identified leg and prevents it from opening the opposite leg. See Binance's New Order API for the wire restrictions.

Post-only restrictions

Only limit order types support post_only.

Order TypeSpotUSDT FuturesCoin FuturesNotes
LIMIT✓✓✓Uses LIMIT_MAKER for Spot, GTX TIF for Futures.
STOP_LIMIT-✓✓Futures only.

Time in force

Time in forceSpotUSDT FuturesCoin FuturesNotes
GTC✓✓✓Good Till Canceled.
GTD✓*✓✓**Non-default local mapping through GTC.
FOK✓✓✓Fill or Kill.
IOC✓✓✓Immediate or Cancel.

GTD policy

Binance Spot time-in-force values are GTC, IOC, and FOK; Spot has no native GTD or goodTillDate. USD-M supports native GTD for LIMIT and the limit forms of STOP and TAKE_PROFIT. The adapter routes regular orders through HTTP or WebSocket trading, independent batches through HTTP batchOrders, and conditional algo orders through HTTP algoOrder. The current Binance WebSocket algo schema includes goodTillDate but does not include GTD in its timeInForce enum, so the adapter does not route GTD algo orders through that endpoint. COIN-M has no native GTD value or goodTillDate parameter in its documented order APIs. See the official USD-M trade API and COIN-M common definitions.

USD-M goodTillDate is an epoch timestamp in milliseconds, but Binance ignores any sub-second part. Nautilus rejects an expiry that is not on a whole-second boundary rather than silently rounding it. The expiry must be strictly greater than the current time plus 600 seconds and strictly less than 253402300799000. Native GTD also rejects market and post-only orders and any order without an expiry.

use_gtd=True is the default. It uses native USD-M GTD and rejects native GTD on Spot and COIN-M. Set use_gtd=False only when the submitting strategy has manage_gtd_expiry=True. The adapter then warns and sends GTC, while Nautilus cancels the order at its local expiry.

Advanced order features

FeatureSpotUSDT FuturesCoin FuturesNotes
Order Modification✓✓✓Price and quantity for LIMIT orders only.
OCO Orders✓--Spot OCO submitted via orderList/oco.
Bracket Orders---Planned. Currently denied at submission.
Iceberg Orders✓--Spot icebergQty from display_qty.

Batch operations

OperationSpotUSDT FuturesCoin FuturesNotes
Batch Submit✓✓✓Spot OCO or Futures batchOrders.
Batch Modify---Not implemented.
Batch Cancel-*✓✓*Spot falls back to individual cancels.

Cancel all orders behavior

By default, Strategy.cancel_all_orders() sends individual cancels for orders associated with that strategy. When strategy_only=False is used, the strategy sends a broad CancelAllOrders command to the adapter. The adapter includes orders in both open and inflight (SUBMITTED) states so that it also cancels orders not yet acknowledged by Binance.

Multi-strategy safety: When multiple strategies trade the same instrument, the adapter compares orders associated with the requesting strategy against all orders for that instrument. If all orders are associated with the strategy, a single cancel-all API call is used. Otherwise, per-strategy cancels are sent (batch for regular orders, individual for algo orders) to avoid affecting other strategies.

Side filter: A CancelAllOrders command with order_side set cancels only open orders on that side for the instrument. Spot sends one cancel per matching order, while Futures batches regular orders and cancels algo orders individually. A side-filtered request selects from open orders only, so an inflight (SUBMITTED) order not yet acknowledged by Binance survives one; use an unfiltered cancel-all to include it.

Futures algo orders: Conditional order types (STOP_MARKET, STOP_LIMIT, TAKE_PROFIT, TAKE_PROFIT_MARKET, TRAILING_STOP_MARKET) require a different cancel endpoint. The adapter routes these through the correct endpoint automatically. Once an algo order triggers and becomes a regular order, it uses the standard cancel endpoint.

Endpoints used:

ProductRegular OrdersAlgo Orders (batch)Algo Orders (individual)
SpotDELETE /api/v3/openOrdersN/AN/A
USDT FuturesDELETE /fapi/v1/allOpenOrdersDELETE /fapi/v1/algoOpenOrdersDELETE /fapi/v1/algoOrder
Coin FuturesDELETE /dapi/v1/allOpenOrdersDELETE /dapi/v1/algoOpenOrdersDELETE /dapi/v1/algoOrder

Submit, modify, and cancel retry policy

The execution clients send each submit, modify, or cancel command once. They do not blindly retry a command after a timeout, network failure, or Binance unknown-status response because the first request may have reached the matching engine. Retrying could create a duplicate order or apply a second amendment.

  • Local submit validation emits OrderDenied before submission; local modify validation emits OrderModifyRejected. A definitive venue rejection emits the matching rejection event.
  • An ambiguous transport result remains inflight and is resolved by the private stream or REST reconciliation. The adapter does not emit a false rejection while the venue outcome is unknown.
  • A Futures algo cancel may fall back from the pre-trigger algo endpoint to the regular-order endpoint. This changes endpoint after the order triggers; it does not resend the same cancel to the same endpoint.
  • Strategy code must not resubmit a command while its result is ambiguous. Wait for reconciliation or query the order by its client order ID.

BinanceDataClientConfig and BinanceExecutionClientConfig expose max_retries, retry_delay_initial_ms, and retry_delay_max_ms for HTTP GET requests. Transient read failures retry with bounded exponential backoff and fresh authentication fields. A venue Retry-After header sets the minimum delay, which can exceed retry_delay_max_ms. The fixed total retry budget is 180 seconds. When a required delay exceeds the remaining budget, the request returns the venue error without waiting.

These settings do not retry order commands because resending an ambiguous command could duplicate an order or amendment.

Position management

FeatureSpotUSDT FuturesCoin FuturesNotes
Query positions-✓✓Real-time position updates.
Position mode-✓✓One-Way vs Hedge mode (position IDs).
Leverage control-✓✓Dynamic leverage adjustment per symbol.
Margin mode-✓✓Cross vs Isolated margin per symbol.

Binance Futures logs out-of-scope position symbols at debug and drops them before parsing. For the remaining rows, position report generation warns when an amount cannot be parsed. After flat positions are removed, unresolved instruments and other conversion failures also warn. If any position fails, generate_position_status_reports returns an error with the failure count instead of an incomplete report set. See instrument availability.

Risk events

FeatureSpotUSDT FuturesCoin FuturesNotes
Liquidation handling-✓✓Exchange-forced position closures.
ADL handling-✓✓Auto-Deleveraging events.

Binance Futures can trigger exchange-generated orders in response to risk events:

  • Liquidations: When insufficient margin exists to maintain a position, Binance forcibly closes it at the bankruptcy price. These orders have client IDs starting with autoclose-.
  • ADL (Auto-Deleveraging): When the insurance fund is depleted, Binance closes profitable positions to cover losses. These orders use client ID prefix adl_autoclose.
  • Settlements (USD-M): Funding and margin settlement orders use client IDs starting with settlement_autoclose-.
  • Deliveries (COIN-M): Expiring delivery contracts auto-close with client IDs starting with delivery_autoclose-.
  • Insurance fund: Takeover by the insurance fund uses status NEW_INSURANCE (deprecated on the public changelog but still observed on the wire).

The adapter detects these special order types via their client ID patterns (checked before the execution type), then:

  1. Logs a warning with order details for monitoring.
  2. Generates a FillReport with correct fill details and TAKER liquidity side.
  3. Generates an OrderStatusReport for reconciliation.

Upstream references:

The execution engine creates external orders from runtime status reports when the order is not already in cache. This covers first-seen exchange-generated orders (the typical case for a live liquidation or ADL event). The engine assigns the order through the instrument's active external order claim, configured initially with external_order_instrument_ids, or to the EXTERNAL strategy by default.

:::note The status report and fill report are emitted bundled as a single OrderWithFills execution report. The engine creates the external order from the status report and then applies the real fill, preserving the venue's trade_id and commission. Any residual quantity not covered by the bundled fills is closed with an inferred fill from the status report's avg_px. :::

Commission estimation

When Binance omits the commission fields (N/n) from the fill event, the adapter estimates commission as default_taker_fee * qty * price using the quote currency. This applies to USD-M linear contracts only. COIN-M inverse contracts use zero commission as a fallback because the linear formula does not account for contract size. Configure default_taker_fee on BinanceExecutionClientConfig to match your fee tier (default: 0.0004 / 0.04%).

Order querying

FeatureSpotUSDT FuturesCoin FuturesNotes
Query open orders✓✓✓List all active orders.
Query order history✓✓✓Historical order data.
Order status updates✓✓✓Real-time order state changes.
Trade history✓✓✓Execution and fill reports.

Futures trade-history retention

Binance retains USD-M and COIN-M account trades for the past three months. Because Binance does not define whether this means calendar months or a fixed duration, the adapter treats the most recent 88 days as its complete Futures fill-history window.

generate_fill_reports rejects an explicit start before that window. The boundary uses the command's ts_init, capped so it can trail the current client time by no more than 12 hours. An end time also requires a start time.

For mass status, an unset reconciliation_lookback_mins or a value longer than the complete window applies that window. The returned ExecutionMassStatus sets lookback_start to the applied boundary and reports_complete to false; see the mass-status history contract. Binance Spot is unaffected. See the Binance Futures change log.

Contingent orders

FeatureSpotUSDT FuturesCoin FuturesNotes
Order lists✓✓✓Spot OCO lists; Futures independent batches.
OCO orders✓--Spot only, via orderList/oco.
Bracket orders---Planned. Currently denied at submission.
Conditional orders✓✓✓Stop and market-if-touched orders.

Order parameters

Customize individual orders by supplying a params dictionary when calling Strategy.submit_order (Python) or setting Params on a SubmitOrder command (Rust). The Binance execution clients recognize:

ParameterTypeProductsPurposeRestrictions
price_matchstrUSDT/COIN FuturesDelegate price selection to Binance.LIMIT only; not with post_only.
close_positionboolUSDT/COIN FuturesClose the whole position when the trigger fires.StopMarket and MarketIfTouched only; requires reduce_only=true; not in order lists.
rpiboolUSDT FuturesSubmit a Retail Price Improvement order.LIMIT only; requires post_only=true; individual orders only.

See Price match, RPI, and Close position for the full behavior.

Price match

Binance Futures supports BBO (Best Bid/Offer) price matching via the priceMatch parameter, which delegates price selection to the exchange. Limit orders dynamically join the order book at optimal prices without specifying an exact price level.

When using price_match, you submit a limit order with a reference price (for local risk checks), and Binance determines the actual working price based on the current market state and price match mode.

Valid price match values

ValueBehavior
OPPONENTJoin the best price on the opposing side of the book.
OPPONENT_5Join the opposing side price but allow up to a 5-tick offset.
OPPONENT_10Join the opposing side price but allow up to a 10-tick offset.
OPPONENT_20Join the opposing side price but allow up to a 20-tick offset.
QUEUEJoin the best price on the same side (stay maker).
QUEUE_5Join the same-side queue but offset up to 5 ticks.
QUEUE_10Join the same-side queue but offset up to 10 ticks.
QUEUE_20Join the same-side queue but offset up to 20 ticks.

:::info For more details, see the official documentation. :::

Event sequence

When an order is submitted with price_match:

  1. Nautilus sends the order with the priceMatch parameter and omits the limit price from the API request.
  2. Binance accepts the order and determines the actual working price.
  3. Nautilus generates an OrderAccepted event.
  4. If the Binance-accepted price differs from the reference price, Nautilus generates an OrderUpdated event with the actual working price.
  5. The order price in the Nautilus cache now matches the Binance-accepted price.

Example

order = strategy.order_factory.limit(
    instrument_id=InstrumentId.from_str("BTCUSDT-PERP.BINANCE"),
    order_side=OrderSide.BUY,
    quantity=Quantity.from_int(1),
    price=Price.from_str("65000"),  # Reference price for local risk checks
)

strategy.submit_order(
    order,
    params={"price_match": "QUEUE"},
)

:::note If Binance accepts the order at a different price (e.g. 64,995.50), you receive an OrderAccepted event followed by an OrderUpdated event with the new price. :::

RPI

Binance RPI (Retail Price Improvement) uses timeInForce=RPI. It is post-only and only matches eligible retail orders from the Binance App or Web. Nautilus exposes it through the Binance-specific rpi parameter; use it only with a USD-M LIMIT order whose post_only=true. It is supported only for individual SubmitOrder commands; SubmitOrderList is denied. Without rpi, regular post-only orders continue to use GTX. See Binance's USD-M Futures API definitions for venue details.

RPI is available only for symbols whose permissionSets contains RPI in the GET /fapi/v1/exchangeInfo response. Check symbol eligibility before submitting an RPI order; see Binance's RPI guide.

The Rust example assumes order is a post-only LIMIT order for an eligible symbol. For Python, set instrument_id to an eligible instrument and choose quantity (Quantity) and price (Price) that meet its trading rules.

use nautilus_core::params::Params;

let mut params = Params::new();
params.insert("rpi".to_string(), true.into());
self.submit_order(order, None, None, Some(params))?;
order = strategy.order_factory.limit(
    instrument_id=instrument_id,
    order_side=OrderSide.BUY,
    quantity=quantity,
    price=price,
    post_only=True,
)

strategy.submit_order(order, params={"rpi": True})

Close position

Binance Futures conditional orders support closePosition, which closes the entire position when the trigger fires. Binance resolves the quantity server-side from the current position size at trigger time. See the official USD-M Algo Service API and COIN-M Algo Service API.

Unlike reduce_only, closePosition adapts to position size changes, and Binance auto-cancels the order when the position is closed by other means.

Set reduce_only=true on the Nautilus StopMarket or MarketIfTouched order, then pass close_position=true in its params. The reduce-only flag records the order's closing intent and is required for the order to pass while the trading state is REDUCING. The adapter translates this combination into Binance's close-all instruction and rejects close_position in order lists.

Allow Binance whole-position exits in the risk engine configuration:

from nautilus_trader.adapters.binance import BINANCE_VENUE
from nautilus_trader.config import LiveRiskEngineConfig

risk_engine = LiveRiskEngineConfig(
    full_position_exit_venues=[BINANCE_VENUE],
)

The allowlist defaults to empty. Without this entry, the placeholder quantity receives the same minimum quantity, maximum quantity, and notional checks as an ordinary order. Pass the open position ID when submitting the order so the risk engine can verify that the exit reduces it.

let params = Params::from([("close_position", true.into())]);
self.submit_order(order, Some(position.id), None, Some(params))?;
strategy.submit_order(
    order,
    position_id=position.id,
    params={"close_position": True},
)

:::info The Nautilus order must set reduce_only=true, but Binance does not permit its reduceOnly field with closePosition=true. The adapter therefore sends closePosition=true while omitting quantity and reduceOnly from the Binance request. In Hedge Mode, it also sends the closing positionSide.

For an allowlisted venue, the risk engine still validates quantity precision and positivity, the trigger price, the order shape and side, and the linked open position. It does not apply minimum or maximum quantity and notional bounds to the placeholder quantity. :::

:::warning Only add a venue when its configured execution client enforces whole-position closing semantics. An execution client that does not interpret close_position may submit only the placeholder quantity through its standard reduce-only path instead of closing the whole position. :::

Trailing stops

For trailing stop market orders on Binance:

  • Use activation_price (optional) to specify when the trailing mechanism activates.
  • When omitted, Binance uses the current market price at submission time.
  • Use trailing_offset for the callback rate, with TrailingOffsetType.BASIS_POINTS. The adapter rejects any other offset type, and rejects a callback rate outside Binance's 0.1% to 10% range.

:::warning Do not use trigger_price for trailing stop orders: it will fail with an error. Use activation_price instead. :::

The adapter prefixes supported client order IDs with the NautilusTrader integration ID for Binance's Link and Trade program. No user configuration is required.

The adapter compresses outgoing ClientOrderId values to fit Binance's 36-character limit and decodes incoming events before they reach strategies. Supported formats include numeric factory IDs, UUIDs, and hyphenated factory IDs with a short alphanumeric trader or strategy tag, such as O-20260922-160119-V2-000-8.

The short-tag format supports one or two ASCII letters or digits in one tag. The other tag must be a numeric value in [0, 1023], padded to at least three digits. Its count supports [0, 4194303] without leading zeros, and timestamps span [2020-01-01 00:00:00, 2156-02-07 06:28:15] UTC. Enabling use_uuid_client_order_ids is optional.

Custom IDs of at most 24 bytes need no compression. For longer unsupported IDs, the adapter logs a warning and sends the original ID without a prefix. Binance's length and character restrictions still apply.

Existing orders after an upgrade

Existing numeric, UUID, and raw-prefixed encodings remain unchanged. The decoder also accepts historical unprefixed IDs. When an existing-order operation has a short-tag ID but no venue order ID, the adapter queries both its encoded form and the historical unprefixed form. If these identify separate orders, it rejects the operation as ambiguous.

Modifications and cancellations use the recovered venue order ID. Spot cancel-replace retains the existing wire client order ID when replacing the same logical order, including orders submitted with a historical unprefixed ID. These lookups also apply when the mutation uses WebSocket transport.

Decoding client order IDs

When querying Binance directly (REST API, web UI, or your own HTTP code), the clientOrderId field contains the encoded form. Two utility functions recover the original Nautilus ClientOrderId:

from nautilus_trader.adapters.binance import (
    decode_binance_futures_client_order_id,
    decode_binance_spot_client_order_id,
)

# Encoded ID from a Binance REST response or the web UI
encoded = "x-TD67BGP9-T0000000000000"
original = decode_binance_spot_client_order_id(encoded)
# Returns "O-20200101-000000-000-000-0"

# Futures equivalent
encoded_futures = "x-aHRE4BCj-T0000000000000"
original_futures = decode_binance_futures_client_order_id(encoded_futures)
# Returns "O-20200101-000000-000-000-0"

Strings without the broker prefix pass through unchanged, so these are safe to call on any clientOrderId value.

:::note The adapter decodes automatically wherever it returns Nautilus types such as OrderStatusReport. Manual decoding is only needed when working outside the adapter: direct REST queries, the Binance web UI, or raw venue payloads. :::

Order books

Order books can be maintained at full or partial depths. The diff-depth stream and its update rate differ by product and Spot transport:

Product / transportDiff-depth streamUpdate rate
Spot SBE<symbol>@depth25ms
Spot JSON<symbol>@depth1000ms (default)
Futures<symbol>@depth@0msUnthrottled

Book subscriptions emit snapshots, whether seeded from REST or received as partial-depth frames, with these flags:

  • Every snapshot delta carries F_SNAPSHOT, and the final delta carries F_SNAPSHOT | F_LAST.
  • A snapshot without levels is a lone Clear that empties the book.

Futures L2 subscriptions

The L2_MBP subscription depth selects the stream:

DepthStreamBook source
5, 10, or 20<symbol>@depth<levels>@100msSnapshot in each message
None, 50, 100, 500, or 1000<symbol>@depth@0msREST snapshot, then diffs
Any otherNoneRejected
  • Partial depth: Binance provides partial-depth streams only at 5, 10, and 20 levels. Each message is a snapshot of both sides, emitted as a Clear delta followed by the snapshot levels, so it removes absent prices and keeps at most the requested number of levels per side. These subscriptions never request a REST snapshot, including after reconnects.
  • Diff depth: The depth limits the initial, reconnect, and recovery REST snapshots, not the maintained book; omitting it selects a 1000-level snapshot. Later updates can add levels beyond that depth.

The OrderBook.bids(depth=...) and OrderBook.asks(depth=...) accessors limit their returned results without removing stored levels. Unsubscribe before changing an instrument's subscription depth.

Spot L2 subscriptions

Spot partial-depth subscriptions deliver self-contained top-N snapshots. The supported depths depend on the Spot market data mode:

DepthJSONSBE
5 or 10<symbol>@depth<levels>Rejected; use JSON
20<symbol>@depth20<symbol>@depth20
None (diff depth)<symbol>@depth<symbol>@depth
Any other, including 50, 100, 500, 1000RejectedRejected
  • Rejected depths fail before subscription; in JSON mode the error lists the valid depths.
  • Diff-depth subscriptions are seeded by a 5000-level REST snapshot.
  • Unsubscribe before changing an instrument's subscription depth; a new partial-depth subscription does not remove the previous stream.

L1 top-of-book subscriptions

L1_MBP subscriptions require depth 1 and use the Spot bestBidAsk or bookTicker stream and the Futures bookTicker stream. Each update emits the normal QuoteTick and a two-sided OrderBookDeltas batch with F_MBP flags so a managed L1 book receives the same top-of-book state.

Quote and L1 subscriptions share the venue stream through reference counting. The client rejects concurrent L1 and L2 subscriptions for the same instrument.

Snapshot requests

Explicit order-book snapshot requests are supported separately from subscription synchronization:

  • Spot: Depths in [1, 5000].
  • Futures: Depths 5, 10, 20, 50, 100, 500, or 1000.

Snapshot synchronization and recovery

Futures diff-depth subscriptions and Spot L2_MBP subscriptions without an explicit depth keep the diff-depth stream subscribed and seed the book from a REST snapshot, using the shared book recovery machinery.

Synchronization

Synchronization starts at the first diff after a subscription or data WebSocket reconnect:

  1. Diffs are buffered and a REST snapshot is requested.
  2. Buffered diffs covered by the snapshot's lastUpdateId are dropped.
  3. The remaining diffs must continue from the snapshot; otherwise another snapshot is requested.
  4. The snapshot is sent to the DataEngine, followed by the remaining buffered diffs.
  5. Each later diff is validated against the previous one before it is sent.

Each diff must continue from the snapshot or the previous diff:

ProductFirst diff after the snapshotLater diffs
SpotU <= lastUpdateId + 1U <= previous u + 1
FuturesU <= lastUpdateId <= upu == previous u

A diff that breaks these rules is a sequence gap: book output stops, diffs are buffered, and a fresh snapshot is requested without resubscribing. A diff that fails to parse surfaces as a gap on the next diff.

Recovery limits

  • Snapshot timeout: book_snapshot_timeout_secs (default 10 seconds) bounds each snapshot request. Set it to 0 to leave requests to the HTTP client timeout.
  • Retry budget: Each recovery makes up to eight snapshot attempts within 180 seconds, with exponential backoff and jitter, then continues at an interval that doubles from one minute to fifteen minutes. A permanent request failure moves straight to that interval.
  • Reconnects: A reconnect restarts synchronization from the new stream and keeps a running recovery with its remaining budget. A recovery waiting between attempts after its budget retries at once. That recovery's next snapshot can seed the book before the new stream delivers a diff; the first diff must then continue from the snapshot.
  • Persistent failures: Recovery continues until a snapshot bridges the buffered diffs or the book is unsubscribed. Other books continue independently.

Snapshot pacing

Snapshot requests draw on a per-client share of the venue request-weight budget, so a burst of resyncs, such as after a reconnect, waits for budget instead of exceeding it:

ProductSnapshot budgetBurst (half the budget)Full snapshot cost
Spot3,000 per minute1,500250 (5000 levels)
Futures1,200 per minute60020 (1000 levels)
  • Queueing for the first snapshot does not consume the recovery's attempts or 180-second budget.
  • Explicit snapshot requests draw on the same budget.
  • The HTTP client's retries of a failed snapshot request are not paced.

Live recovery validation

The binance-book-stress harness is a development tool for changes to book synchronization and recovery. It connects to the selected product's market data, submits no orders, and checks emitted books against the book stream contract and two independent oracles: the venue's <symbol>@depth20@100ms stream at matching update IDs, and a reference book rebuilt from raw diffs and forwarded REST snapshots.

The harness drops diffs to force gaps, fails, delays, and rejects REST snapshots, cuts and freezes connections, requests reconnects, and churns subscriptions. Its REST proxy refuses snapshot requests before venue request weight nears its limit, and a run fails if the venue throttles it.

From the repository root, run:

CARGO_BUILD_JOBS=16 bash scripts/strip-adapter-env.bash \
  cargo test -p nautilus-binance --features examples --test binance-book-stress -- --product futures

--product selects the venue:

ProductVenue
spot (default)Spot mainnet JSON streams.
spot-sbeSpot mainnet SBE streams; reads BINANCE_API_KEY and BINANCE_API_SECRET.
futuresUSD-M testnet.
coinmCOIN-M testnet.

Run spot-sbe without strip-adapter-env.bash, which unsets the API key it needs.

--scenario selects the run:

  • churn (default): rotates gap, reconnect, subscription churn, cut, and freeze faults.
  • boundaries: probes snapshot deadlines, retry exhaustion into the retry ceiling, and a permanent rejection.
  • resubscribe: races an unsubscribe with an immediate resubscribe once per round.
  • quiet: watches thinly traded books, one round per minute.
  • crowd: subscribes liquid books and reconnects once per round so snapshot pacing engages.

--timeout sets the snapshot timeout in seconds, where 0 disables snapshot deadlines, and --rounds sets the number of rounds (14 by default). --books sets how many books quiet and crowd select by 24-hour trade count (4 by default).

The harness requires access to the selected product's REST API and WebSocket market data streams. Automated book lifecycle tests use local mock servers. See Stress harnesses for the shared flags and output format.

Quote timestamps

The ts_event field on QuoteTick differs between transports. Spot SBE uses the microsecond event timestamp. Spot public JSON bookTicker messages can omit an event timestamp, in which case the adapter uses ts_init. Futures uses the transaction time.

Bars and historical market data

Spot supports one-second klines for subscriptions and historical requests. Real-time Spot kline subscriptions require spot_market_data_mode=Json because Binance does not publish kline or ticker streams over Spot SBE. Binance Futures rejects second-level klines because the Futures API does not offer them.

Closed venue klines emit a core Bar and a BinanceBar custom-data event. BinanceBar retains quote volume, trade count, taker-buy base volume, and taker-buy quote volume. Historical core bar requests return Bar; request BinanceBar custom data with bar_type metadata to retain the extended fields in historical responses.

Real-time trade subscriptions use the <symbol>@aggTrade stream on Futures, because Binance only publishes aggregated trades on the Futures WebSocket, and the individual <symbol>@trade stream on Spot.

Historical trade requests without bounds use the recent-trades endpoint. A request with time bounds uses aggregate trades and accepts at most 1000 records, so the source follows the request rather than a config option. Spot passes the supplied bounds to /api/v3/aggTrades. Futures accepts either bound within the last 24 hours; when both are supplied, the range must be shorter than one hour.

Historical core bar requests accept externally aggregated time bars and use the corresponding venue kline endpoint. Internally aggregated bars are built by the DataEngine from raw trade, quote, or source-bar responses through the bar_types request parameter; the Binance data client does not aggregate them.

Binance specific data

Bars, mark prices, index prices, and funding rates are subscribed to in the normal way. The custom data types below expose additional venue-specific fields that the core data types do not carry.

Binance Futures mark-price payloads preserve the venue P estimated settlement price in BinanceFuturesMarkPriceUpdate. Nautilus also emits standard mark-price, index-price, and funding-rate updates from the same stream. The optional USD-M ap moving-average field is parsed at the transport boundary but is not exposed as domain or custom data.

BinanceSpotTicker

Spot 24-hour ticker custom data requires public JSON market-data mode and an instrument_id metadata value:

from nautilus_trader.adapters.binance import BinanceSpotTicker
from nautilus_trader.model import ClientId
from nautilus_trader.model import DataType

self.subscribe_data(
    data_type=DataType(
        BinanceSpotTicker.__name__,
        metadata={"instrument_id": "BTCUSDT.BINANCE"},
    ),
    client_id=ClientId.from_str("BINANCE"),
)

The adapter subscribes to the instrument @ticker stream. SBE mode rejects this subscription because Binance Spot SBE does not provide the stream.

BinanceFuturesTicker

Subscribe to 24-hour ticker statistics for a specific Futures instrument:

from nautilus_trader.adapters.binance import BinanceFuturesTicker
from nautilus_trader.model import ClientId
from nautilus_trader.model import DataType

client_id = ClientId.from_str("BINANCE")

self.subscribe_data(
    data_type=DataType(
        BinanceFuturesTicker.__name__,
        metadata={"instrument_id": "BTCUSDT-PERP.BINANCE"},
    ),
    client_id=client_id,
)

The adapter subscribes to the instrument @ticker stream and emits BinanceFuturesTicker custom data with metadata={"instrument_id": "<instrument_id>"}. Ticker custom data requires instrument_id; all-market ticker subscriptions are not supported.

BinanceFuturesMarkPriceUpdate

Subscribe to BinanceFuturesMarkPriceUpdate (including funding rate info) from your actor or strategy:

from nautilus_trader.adapters.binance import BinanceFuturesMarkPriceUpdate
from nautilus_trader.model import DataType
from nautilus_trader.model import ClientId

# In your `on_start` method
self.subscribe_data(
    data_type=DataType(
        BinanceFuturesMarkPriceUpdate.__name__, metadata={"instrument_id": self.instrument.id}
    ),
    client_id=ClientId("BINANCE"),
)

Received BinanceFuturesMarkPriceUpdate objects are passed to your on_data method. Check the type, as this method handles all custom/generic data.

def on_data(self, data):
    # First check the type of data
    if isinstance(data, BinanceFuturesMarkPriceUpdate):
        # Do something with the data

BinanceFuturesLiquidation

Subscribe to liquidation updates for either:

  • a specific instrument (<symbol>@forceOrder), or
  • all symbols (!forceOrder@arr) by omitting instrument_id.
from nautilus_trader.adapters.binance import BinanceFuturesLiquidation
from nautilus_trader.model import ClientId
from nautilus_trader.model import DataType

client_id = ClientId.from_str("BINANCE")

# Instrument-specific
self.subscribe_data(
    data_type=DataType(
        BinanceFuturesLiquidation.__name__,
        metadata={"instrument_id": "BTCUSDT-PERP.BINANCE"},
    ),
    client_id=client_id,
)

# All-market (no instrument_id metadata)
self.subscribe_data(
    data_type=DataType(BinanceFuturesLiquidation.__name__),
    client_id=client_id,
)

For instrument-specific subscriptions, CustomData.data_type includes metadata={"instrument_id": "<instrument_id>"}. For all-market subscriptions, the data type has no metadata.

When both modes are subscribed concurrently, all-market takes precedence. The adapter suspends per-symbol liquidation streams while all-market is active, and restores active per-symbol streams after all-market is unsubscribed.

Futures open interest

Open interest is request-only; the Futures data client has no open interest subscription. Both types require instrument_id metadata, and BinanceFuturesOpenInterestHist also requires a Binance period string such as "5m":

from nautilus_trader.adapters.binance import BinanceFuturesOpenInterest
from nautilus_trader.adapters.binance import BinanceFuturesOpenInterestHist
from nautilus_trader.model import ClientId
from nautilus_trader.model import DataType

client_id = ClientId.from_str("BINANCE")

# Current open interest snapshot
self.request_data(
    data_type=DataType(
        BinanceFuturesOpenInterest.__name__,
        metadata={"instrument_id": "BTCUSDT-PERP.BINANCE"},
    ),
    client_id=client_id,
)

# Historical open interest series
self.request_data(
    data_type=DataType(
        BinanceFuturesOpenInterestHist.__name__,
        metadata={"instrument_id": "BTCUSDT-PERP.BINANCE", "period": "5m"},
    ),
    client_id=client_id,
)

BinanceFuturesOpenInterestHist returns a batch of points, each carrying the summed open interest and its notional value for one bucket. COIN-M history is keyed by pair and contract type, which the adapter derives from the symbol for perpetuals and from the cached instrument definition for delivery contracts.

Funding rates

The adapter emits FundingRateUpdate as a first-class data type through subscribe_funding_rates. The data comes from the Mark Price Stream WebSocket endpoint, which provides the current funding rate and next funding time alongside mark and index prices. All three subscriptions (subscribe_mark_prices, subscribe_index_prices, subscribe_funding_rates) share a single @markPrice@1s stream with ref-counted subscription management.

Historical funding rates are available through request_funding_rates, which queries the Get Funding Rate History REST endpoint (GET /fapi/v1/fundingRate for USD-M, GET /dapi/v1/fundingRate for COIN-M). Each history row maps to a FundingRateUpdate with ts_event set to the funding time. The next_funding_ns field is None for historical rows because the endpoint does not provide it.

The adapter also exposes the venue payload through BinanceFuturesMarkPriceUpdate custom data subscriptions (see Binance specific data).

The interval field on FundingRateUpdate is None for Binance because the Mark Price Stream and the funding rate history endpoint do not include a funding interval field. Binance exposes fundingIntervalHours through the Get Funding Rate Info REST endpoint, but the adapter does not consume it.

Instrument status polling

The data clients periodically poll Binance exchangeInfo to detect changes in instrument trading status. When a symbol transitions between states (e.g. Trading to Halt, or Trading to Delivering for a futures contract approaching expiry), the adapter emits an InstrumentStatus event.

The polling interval defaults to 3,600 seconds (60 minutes) and is configurable via instrument_status_poll_secs in the data client config. Set to 0 to disable polling entirely.

On initial connect, the adapter seeds its status cache from the exchange info response without emitting events. Only subsequent polls that detect a status change emit InstrumentStatus events. If a symbol disappears from exchange info (e.g. after delisting or contract expiry), the adapter emits NotAvailableForTrading.

Status polling does not reload instrument definitions. The separate instrument_refresh_interval_secs task performs a complete filtered catalog load, atomically replaces the data-client and WebSocket lookup maps, sends the refreshed instruments to the data engine, and updates the status snapshot. It also refreshes the execution client precision cache. The default full refresh interval is 3,600 seconds; set it to 0 to disable it. Disconnect cancels the task, and reconnect starts one replacement task with a new cancellation token.

Status mapping

Spot

Binance statusMarketStatusAction
TradingTrading
EndOfDayClose
HaltHalt
BreakPause
CancelOnlyHalt
NonRepresentableNotAvailableForTrading

Binance US polls the public JSON exchange info instead, which maps TRADING to Trading, BREAK to Pause, and every other value to NotAvailableForTrading.

Futures (USD-M)

Binance statusMarketStatusAction
TradingTrading
PendingTradingPreOpen
PreTradingPreOpen
PostTradingPostClose
EndOfDayClose
HaltHalt
AuctionMatchCross
BreakPause
PreDeliveringPreClose
DeliveringClose
DeliveredClose
PreSettlePreClose
SettlingClose
CloseClose
TradingHaltHalt
TradingCancelOnlyHalt

Futures (COIN-M)

Binance statusMarketStatusAction
TradingTrading
PendingTradingPreOpen
PreDeliveringPreClose
DeliveringClose
DeliveredClose
PreSettlePreClose
SettlingClose
CloseClose
PreDelistingPreClose
DelistingSuspend
DownNotAvailableForTrading
TradingHaltHalt
TradingCancelOnlyHalt

Unknown or undocumented Futures status values map to NotAvailableForTrading.

:::note Only instruments that are in a tradable state at connect time are tracked. Symbols that start in a non-trading state (e.g. halted at connect) do not appear in the instruments cache, so status transitions for them are not monitored. :::

Rate limiting

Binance uses an interval-based rate limiting system where request weight is tracked per fixed time window (every minute, resetting at :00 seconds). Each API endpoint has an assigned weight cost, and total weight usage is tracked per IP address.

Venue weight limits

Binance's own per-IP weight allowance, which the endpoint costs below draw from:

ProductWeight limitInterval
Spot/Margin6,0001 minute
Futures2,4001 minute

Endpoint weight costs

Binance charges these weights per request:

EndpointWeightNotes
/api/v3/order1Spot order placement.
/api/v3/allOrders20Spot historical orders (expensive).
/api/v3/klines2+Scales with limit parameter.
/api/v3/depth5+Scales with limit; 250 at 5000.
/fapi/v1/order1Futures order placement.
/fapi/v1/algoOrder0Uses order-count limits.
/fapi/v1/allOrders20Futures historical orders (expensive).
/fapi/v1/commissionRate20Futures commission rate query.
/fapi/v1/klines5+Scales with limit parameter.
/fapi/v1/depth2+Scales with limit; 20 at 1000.

USD-M Futures POST /fapi/v1/algoOrder consumes 1 from both X-MBX-ORDER-COUNT-10S and X-MBX-ORDER-COUNT-1M. Binance charges no IP request weight for this endpoint; the adapter still queues it through the global bucket as part of its local pacing model.

WebSocket API limits

The WebSocket API (used for order entry and user data streams) shares the same weight quota as the REST API:

Limit TypeValueNotes
Request weightSharedCounts against REST API weight quota.
Handshake5Weight cost per connection attempt.
Ping/pong frames5/secMaximum ping/pong rate.

Adapter pacing

The adapter runs its own token bucket limiters ahead of the venue's accounting. Every HTTP request draws one token from a per-product request bucket, and every order operation draws an additional token from the order-count buckets:

ProductRequestsOrder operations
Spot1,200/minute10/second, 100,000/day
Futures (USD-M and COIN-M)2,400/minute300/10 seconds, 1,200/minute

The order-count buckets cover every order operation the product supports, not just placement: submit, OCO submit, batch submit, algo submit, modify (Spot modifies through cancel-replace), batch modify, cancel, cancel-all, batch cancel, and algo cancel. Cancel-heavy and modify-heavy strategies are throttled by these buckets as well. Non-order authenticated requests, such as leverage and margin-type changes and listen-key keepalives, draw from the request bucket alone.

The request bucket counts calls rather than weight, so it does not mirror the venue's weight accounting. A run of high-weight or dynamic-weight endpoints (/api/v3/allOrders at weight 20, or /klines scaling with limit) spends venue weight faster than the local bucket accounts for. Large history requests may need manual pacing. Monitor the X-MBX-USED-WEIGHT-* response headers to track actual venue usage. Order book snapshot requests also wait on a weight-aware budget; see Snapshot pacing.

:::warning Binance returns HTTP 429 when you exceed the allowed weight. Repeated violations trigger temporary IP bans (escalating from 2 minutes to 3 days for repeat offenders). :::

:::info For the latest rate limits, query /api/v3/exchangeInfo (Spot) or /fapi/v1/exchangeInfo (Futures), or see:

:::

Configuration

Data client

OptionDefaultDescription
product_typeSpotOne of Spot, UsdM, or CoinM.
environmentLiveOne of Live, Testnet, or Demo.
base_url_httpNoneOptional HTTP endpoint override.
base_url_wsNoneOptional market WebSocket endpoint override.
api_key / api_secretNoneRequired for Spot SBE; optional for public JSON and Futures data.
spot_market_data_modeSbeJson keeps the credential-free Global Spot path. Binance US requires Json.
instrument_providerdefaultLoading, filters, parser-warning, and commission policy.
instrument_refresh_interval_secs3,600Full catalog refresh interval; 0 disables it.
instrument_status_poll_secs3,600Status-only exchange-info poll interval; 0 disables it.
book_snapshot_timeout_secs10Deadline for each diff-depth REST snapshot request; 0 disables it.
proxy_urlNoneProxy applied to HTTP and every market WebSocket connection.
recv_window_ms5,000Signed HTTP receive window, inclusive range 1..=60000.
max_retries3Maximum retries for HTTP GET requests.
retry_delay_initial_ms1,000Initial HTTP read retry delay in milliseconds.
retry_delay_max_ms10,000Maximum exponential delay; a venue minimum can exceed it.
usFalseRoute a live Spot JSON client to Binance US.
transport_backendSockudoWebSocket transport backend.

Execution client

OptionDefaultDescription
account_idRequiredNautilus account identity.
product_typeSpotOne of Spot, UsdM, or CoinM.
environmentLiveOne of Live, Testnet, or Demo.
base_url_httpNoneOptional HTTP endpoint override.
base_url_wsNoneOptional private stream override.
base_url_ws_tradingNoneOptional Global Spot or USD-M WebSocket trading override.
use_ws_tradingTrueUse Global WebSocket order entry where supported; Binance US uses HTTP.
ws_trading_setup_timeout_ms10,000WebSocket trading authentication and setup timeout.
instrument_providerdefaultLoading, filters, parser-warning, and commission policy.
instrument_refresh_interval_secs3,600Execution precision-cache refresh interval; 0 disables it.
proxy_urlNoneProxy applied to HTTP, private streams, and WebSocket trading.
recv_window_ms5,000Signed HTTP and WebSocket receive window, inclusive range 1..=60000.
max_retries3Maximum retries for HTTP GET requests.
retry_delay_initial_ms1,000Initial HTTP read retry delay in milliseconds.
retry_delay_max_ms10,000Maximum exponential delay; a venue minimum can exceed it.
usFalseRoute a live Spot execution client to Binance US.
api_key / api_secretNoneGlobal uses Ed25519 WebSocket auth; Binance US uses HMAC HTTP signing.
use_gtdTrueUse native USD-M GTD; see GTD policy.
use_position_idsTrueExpose Futures IDs on order, fill, and hedge REST reports.
oms_typeNoneNone selects Futures netting; use Hedging for dual-side mode.
default_taker_fee0.0004Fallback for exchange-generated Futures fills.
futures_leveragesNoneInitial leverage by Futures symbol.
futures_margin_typesNoneInitial margin type by Futures symbol.
treat_expired_as_canceledFalseMap EXPIRED execution events to canceled events.
use_trade_liteFalseUse the lower-latency USD-M trade-lite fill stream.
bnfcr_currencyUSDTCurrency used to resolve BNFCR balances and fees.
transport_backendSockudoWebSocket transport backend.

Live node configuration

Use BinanceDataClientConfig with BinanceDataClientFactory and BinanceExecutionClientConfig with BinanceExecutionClientFactory. The current Python examples show the complete LiveNode.builder(...) configuration for data and execution clients.

Futures Credits Trading Mode (BNFCR)

Binance Futures Credits Trading Mode is an EU regulatory mode in which the USD-M futures wallet, margin, PnL, and fees are denominated in BNFCR: an internal credit unit pegged 1:1 to USD that replaces stablecoin balances. Because BNFCR is not a tradable asset, the adapter maps it to the bnfcr_currency execution config option (default USDT) so account balances and commissions reconcile against the stablecoin the traded contracts settle in. Set bnfcr_currency to USDC when trading USDC-margined perpetuals. Any other unrecognized futures asset is registered as a generic crypto currency rather than failing.

Spot market data mode

spot_market_data_mode on BinanceDataClientConfig selects the Spot data transport. It affects Spot only; Futures is unchanged.

ModeCredentialsQuotes
SbeEd25519 (required)bestBidAsk
JsonNone (public)bookTicker

Sbe (default) uses Binance Simple Binary Encoding streams and requires Ed25519 keys (see Key types); the client refuses to connect without them. Json uses public streams with no credentials.

Full Spot BookDeltas subscriptions use the <symbol>@depth diff-depth stream on the selected transport, with REST snapshot synchronization. Explicit depth subscriptions use partial-book snapshots (see Order books).

:::note Exposed to Python as BinanceSpotMarketDataMode on nautilus_trader.adapters.binance. :::

Key types

The adapter signs with Ed25519 or HMAC-SHA256, auto-detecting the key type from your API secret format, so no configuration is needed. A secret that parses as a PKCS#8 Ed25519 private key signs with Ed25519; anything else is treated as an HMAC secret.

Ed25519 is strongly recommended. Binance recommends Ed25519 for its superior performance and security. A future version of NautilusTrader will require Ed25519 exclusively.

Key TypeData ClientsExecution ClientsStatus
Ed25519✓✓Recommended
HMAC✓✓Deprecated, will be removed in a future version.
RSA--Not supported; register an Ed25519 key instead.

:::tip Switch to Ed25519 keys now. Generate an Ed25519 keypair and register it with Binance. See Generating Ed25519 keys below. :::

:::note Ed25519 keys must be provided in unencrypted PEM format (base64-encoded ASN.1/DER). The implementation automatically extracts the 32-byte seed from the DER structure. Encrypted (password-protected) PEM keys are not supported. If your key is encrypted, decrypt it first: openssl pkey -in encrypted.pem -out decrypted.pem :::

Generating Ed25519 keys

Option 1: OpenSSL (recommended)

# Generate private key (PKCS#8 PEM format)
openssl genpkey -algorithm ed25519 -out binance_ed25519_private.pem

# Extract public key
openssl pkey -in binance_ed25519_private.pem -pubout -out binance_ed25519_public.pem

Option 2: Binance Key Generator

Download the Binance Asymmetric Key Generator from the releases page and run it to generate a keypair.

Registering with Binance

  1. Log in to Binance and go to Profile -> API Management.
  2. Click Create API and select Self-generated.
  3. Paste the contents of your public key file, including the -----BEGIN PUBLIC KEY----- header and footer.
  4. Configure permissions (Enable Spot & Margin Trading, etc.).

Using with NautilusTrader

Set the private key as your API secret:

export BINANCE_API_KEY="your-api-key-from-binance"
export BINANCE_API_SECRET="$(cat binance_ed25519_private.pem)"

Or pass the PEM content directly in your configuration.

:::warning Keep your private key secure. Never share it or commit it to version control. :::

API credentials

Pass credentials directly to the configuration objects, or set the appropriate environment variables (see Environments for per-environment variables).

:::tip Use Ed25519 keys for all clients. HMAC keys still work for both data and execution clients, but Ed25519 offers better performance and will become the only supported key type in a future version. See Key types. :::

:::warning The BINANCE_ED25519_* and BINANCE_*_ED25519_* environment variables have been removed for Spot; a client that finds one logs an error and treats the credential as missing. For Futures they are deprecated, still honored with a warning, and will be removed in a future version. Rename them to BINANCE_API_KEY / BINANCE_API_SECRET (Ed25519 keys are now auto-detected). :::

When the trading node starts, you receive confirmation of whether your credentials are valid and have trading permissions.

Product type

Configs select one supported product with the product_type field and BinanceProductType enum:

  • SPOT
  • USD_M (USDT, USDC, or BNFCR collateral)
  • COIN_M (cryptocurrency collateral)

:::note Margin trading is not implemented. Other enum variants are rejected by the live clients and the standalone instrument loader. See Product support. :::

Base URL overrides

Override the default base URLs for both HTTP REST and WebSocket APIs. This is useful for configuring API clusters or when Binance has provided specialized endpoints.

Binance US

Set us=True on the config for first-class Binance US Spot routing. Binance US is not a custom-URL alias: the switch selects api.binance.us, the public JSON stream, HMAC-signed HTTP execution, and the port 443 listen-key private stream with periodic keepalive.

See the official Binance US REST API, market streams, and user data stream documentation for the venue contracts behind this routing.

The supported combinations are deliberate:

  • Data: product_type=Spot, environment=Live, spot_market_data_mode=Json.
  • Execution: product_type=Spot, environment=Live; order entry uses HTTP and private events use the listen-key stream.
  • Futures, Testnet, Demo, and Spot SBE configurations with us=True fail validation.

Binance US public JSON covers live market data, depth snapshots, recent and aggregate trade history, and kline history. It uses account-wide maker and taker rates. Global Binance keeps its existing credential-free Spot JSON behavior with us=False and spot_market_data_mode=Json.

Environments

Binance provides three trading environments, each with separate API credentials and endpoints. The environment config option selects which to use.

EnvironmentConfig valueDescription
LiveBinanceEnvironment.LIVEProduction trading with real funds (default).
DemoBinanceEnvironment.DEMODemo Trading with simulated Spot and Futures funds.
TestnetBinanceEnvironment.TESTNETLegacy Spot and Futures test network.

Live (production)

The default environment for live trading with real funds. Uses your main Binance account credentials.

config = BinanceExecutionClientConfig(
    account_id=AccountId.from_str("BINANCE-001"),
    api_key="YOUR_API_KEY",
    api_secret="YOUR_API_SECRET",
    product_type=BinanceProductType.SPOT,
    # environment=BinanceEnvironment.LIVE (default)
)
VariableDescription
BINANCE_API_KEYLive API key.
BINANCE_API_SECRETLive API secret.

Demo trading

Practice trading with simulated funds on production infrastructure. Demo accounts use the same Binance login as your live account but trade with virtual balances.

How to get demo credentials:

  1. Log in at binance.com/en/demo-trading.
  2. Go to API Management and create a demo API key.
  3. Demo keys work for Spot and Futures demo endpoints.
EndpointURL
Spot HTTPdemo-api.binance.com
Spot WSdemo-stream.binance.com
USD-M HTTPdemo-fapi.binance.com
USD-M WSdemo-fstream.binance.com
COIN-M HTTPdemo-dapi.binance.com
COIN-M WSdemo-dstream.binance.com
config = BinanceExecutionClientConfig(
    account_id=AccountId.from_str("BINANCE-001"),
    api_key="YOUR_DEMO_API_KEY",
    api_secret="YOUR_DEMO_API_SECRET",
    product_type=BinanceProductType.SPOT,
    environment=BinanceEnvironment.DEMO,
)
VariableDescription
BINANCE_DEMO_API_KEYDemo API key.
BINANCE_DEMO_API_SECRETDemo API secret.

Testnet

A legacy test network with its own user accounts, balances, and order books. Prefer environment=BinanceEnvironment.DEMO for new simulated trading setups. Spot testnet remains at testnet.binance.vision; futures testnet endpoints may route through the Demo Trading infrastructure.

How to get Spot testnet credentials:

  1. Go to testnet.binance.vision.
  2. Log in with GitHub.
  3. Generate an Ed25519 or HMAC API key (the adapter does not support RSA keys).

Futures testnet: Existing configs with BinanceEnvironment.TESTNET continue to work, but new Futures testing should use BinanceEnvironment.DEMO.

config = BinanceExecutionClientConfig(
    account_id=AccountId.from_str("BINANCE-001"),
    api_key="YOUR_TESTNET_API_KEY",
    api_secret="YOUR_TESTNET_API_SECRET",
    product_type=BinanceProductType.SPOT,
    environment=BinanceEnvironment.TESTNET,
)
VariableDescription
BINANCE_TESTNET_API_KEYSpot testnet API key.
BINANCE_TESTNET_API_SECRETSpot testnet API secret.
BINANCE_FUTURES_TESTNET_API_KEYFutures testnet API key.
BINANCE_FUTURES_TESTNET_API_SECRETFutures testnet API secret.

:::note Testnet credentials are completely separate from your live account. Market data and liquidity differ from production. :::

Instrument loading

The instrument provider controls selection and filters:

from nautilus_trader.adapters.binance import BinanceInstrumentProviderConfig

instrument_provider = BinanceInstrumentProviderConfig(
    load_all=False,
    load_ids=["BTCUSDT.BINANCE", "ETHUSDT.BINANCE"],
    filters={"quotes": ["USDT"], "bases": ["BTC", "ETH"]},
    log_warnings=True,
    query_commission_rates=True,
)

load_all=False selects only load_ids; venue filters then apply as an intersection. Supported filters are symbols, bases, and quotes, plus contract_types for Futures. Values are a string or non-empty list of strings, and matching is case-insensitive. The adapter rejects filter_callable; use the supported declarative filters.

Parsed instruments do not carry maker or taker fee rates. query_commission_rates does not copy account commission onto instruments.

Parser warnings

Some Binance instruments cannot be parsed into Nautilus objects if they contain field values beyond what the platform handles. These instruments are skipped with a warning.

Non-trading symbols are skipped with a debug log during bulk loads. They still warn when explicitly selected through load_ids or the symbols filter.

To suppress these warnings:

from nautilus_trader.adapters.binance import BinanceInstrumentProviderConfig

instrument_provider = BinanceInstrumentProviderConfig(
    load_all=True,
    log_warnings=False,
)

Futures hedge mode

Binance Futures Hedge mode allows holding both long and short positions on the same instrument simultaneously.

When use_position_ids is enabled (default), Futures order and fill reports include a venue_position_id derived from the instrument and Binance position side. Hedge-mode REST position reports use the same IDs, such as ETHUSDT-PERP.BINANCE-LONG. This identity is preserved through REST history, user stream updates, stream recovery, exchange-generated fills, and tracked TRADE_LITE fills.

One-way BOTH positions, orders, and fills remain unkeyed and use netting reconciliation. Set use_position_ids to false only for virtual positions with OmsType.HEDGING, where the engine manages position identity. With use_position_ids=True, the adapter rejects a submitted custom position ID that differs from the canonical Binance hedge-leg ID before sending the order.

To use hedge mode, configure it on Binance, set oms_type=OmsType.HEDGING on BinanceExecutionClientConfig, and keep use_position_ids=True to track both venue position sides:

from nautilus_trader.adapters.binance import BinanceExecutionClientConfig
from nautilus_trader.adapters.binance import BinanceProductType
from nautilus_trader.model import AccountId
from nautilus_trader.model import OmsType

config = BinanceExecutionClientConfig(
    account_id=AccountId.from_str("BINANCE-001"),
    product_type=BinanceProductType.USD_M,
    oms_type=OmsType.HEDGING,
    use_position_ids=True,
)

This configuration is required for startup reconciliation to retain the LONG and SHORT legs separately.

If the cache contains an open Binance hedge position under a different locally generated ID, the adapter rejects that position row and reports both the cached and expected IDs. Reconcile the cached state before retrying startup. The adapter does not alias the old ID or create a duplicate venue position.

COIN-M / USD-M architecture

Binance COIN-M Futures (CM / DAPI) and USD-M Futures (UM / FAPI) share a unified architecture. This section covers the implications for the adapter.

See the Important CM-UM Integration Notice for the full details.

WebSocket streams

Market-data stream payloads include st (symbol type: 1 = UM, 2 = CM) on <symbol>@aggTrade, <symbol>@ticker, <symbol>@bookTicker, <symbol>@depth<levels>, <symbol>@miniTicker, and all !*@arr streams. UM-side single-symbol streams also include ps (pair symbol) on <symbol>@bookTicker, <symbol>@depth<levels>, <symbol>@miniTicker, and <symbol>@rpiDepth.

The adapter decodes JSON with serde, which ignores unknown fields by default, so these fields are silently dropped.

All-market array streams (!ticker@arr, !miniTicker@arr, !bookTicker, !forceOrder@arr, !contractInfo) deliver merged UM + CM content on both fstream and dstream.

REST and WebSocket API

  • Order placement and modification acknowledgement responses do not include avgPrice / cumQuote / cumBase. The adapter sources fills from the user data stream. Query endpoints (GET /{f,d}api/v1/order, userTrades) still return these fields.
  • PUT /dapi/v1/order (COIN-M modify) requires both price and quantity. The adapter always sends both fields, falling back to the cached order's values for whichever the modify command omits.
  • COIN-M conditional orders (STOP, TAKE_PROFIT, etc.) use the /dapi/v1/algoOrder endpoint. The adapter routes all futures conditional orders through the algo order API.
  • GET /dapi/v1/openOrders with an invalid symbol returns error -1121.

Rate-limit pools

UM and CM share Binance rate-limit pools: 2400 weight/min per IP, plus 1200 orders/min and 300 orders/10s per account. Rust futures HTTP clients in the same process share request-weight state across UM and CM for the same environment or custom endpoint scope and configured egress path. They share order-count state across UM and CM when authenticated with the same API key, regardless of egress path.

Live, testnet, demo, and unrelated custom endpoint scopes remain isolated. Different configured egress paths have separate request-weight state, while different API keys have separate order-count state. Separate processes and multiple API keys for one Binance account still require external coordination.

dualSidePosition

UM and CM share the same dualSidePosition setting. Changing it on either side affects both. Ensure both UM and CM have no open orders or positions before flipping the setting.

Contributing

:::info To contribute to the Binance adapter, see the contributing guide. :::