The fundamental differences between the Binance Futures API and Spot API lie in the base domain names and the parameter sets: Spot uses api.binance.com/api/v3/*, USDⓈ-M Futures use fapi.binance.com/fapi/v1/*, and COIN-M Futures use dapi.binance.com/dapi/v1/*. Although the signing algorithm remains HMAC-SHA256 for both, Futures require additional parameters such as reduceOnly, positionSide, and leverage, and they operate under different weight rules. This article provides a 10-dimensional comparison table and real code examples to help you smoothly migrate your spot quantitative strategies to futures. If you don't have a Binance account, please complete your registration at the Binance Official Website first; new users can open an account via the Register for Free channel.
I. General Comparison Overview
| Dimension | Spot | USDⓈ-M Futures | COIN-M Futures |
|---|---|---|---|
| Base URL | api.binance.com | fapi.binance.com | dapi.binance.com |
| Path Prefix | /api/v3/ | /fapi/v1/ & /fapi/v2/ | /dapi/v1/ |
| Margin Asset | — | USDT, USDC | BTC, ETH, BNB, etc. |
| Max Leverage | N/A (Margin only) | 125x | 125x |
| Dual-Side Position | Not Supported | Supported (HEDGE mode) | Supported |
| WebSocket URL | stream.binance.com:9443 | fstream.binance.com | dstream.binance.com |
| Min Order Amount | 5 USDT (MIN_NOTIONAL) | 5 USDT | Based on notional value |
| Funding Rate | N/A | Every 8 Hours | Every 8 Hours |
| Weight per Min | 6000 | 2400 | 2400 |
| listenKey Validity | 60 Minutes | 60 Minutes | 60 Minutes |
Key takeaway: Endpoints for USDⓈ-M always start with fapi, and COIN-M start with dapi. Never attempt to use Spot code simply by changing the URL.
II. Subtle Differences in Signing Mechanisms
While the signing algorithm is identical (HMAC-SHA256), two points require attention:
1. Different Default recvWindow Values
- Spot: Default 5000ms, max 60000ms.
- Futures: Default 5000ms, max 60000ms, but officials strongly recommend not exceeding 5000ms.
2. Numerical Parameters as Strings
The Futures API is more sensitive to numerical precision. When placing orders, it is recommended to pass price and quantity as strings to avoid -1111 Precision errors caused by floating-point precision:
# Not recommended
{"price": 60000.123456789, "quantity": 0.001}
# Recommended
{"price": "60000.12", "quantity": "0.001"}
III. Differences in Position and Balance Query Interfaces
Spot Balance
# Spot: GET /api/v3/account
# Returns a balances array
{
"balances": [{"asset": "USDT", "free": "1000", "locked": "0"}]
}
USDⓈ-M Futures Positions
import hmac, hashlib, time, requests
from urllib.parse import urlencode
API_KEY = "YOUR_KEY"
SECRET_KEY = "YOUR_SECRET"
FAPI = "https://fapi.binance.com"
def _sign(params):
params["timestamp"] = int(time.time() * 1000)
query = urlencode(params)
params["signature"] = hmac.new(SECRET_KEY.encode(), query.encode(), hashlib.sha256).hexdigest()
return params
def get_positions():
"""V2 Position Query: Returns all non-zero positions"""
params = _sign({})
r = requests.get(f"{FAPI}/fapi/v2/positionRisk", params=params,
headers={"X-MBX-APIKEY": API_KEY})
return [p for p in r.json() if float(p["positionAmt"]) != 0]
def get_futures_balance():
"""V2 Futures Account Balance"""
params = _sign({})
r = requests.get(f"{FAPI}/fapi/v2/balance", params=params,
headers={"X-MBX-APIKEY": API_KEY})
return r.json()
positions = get_positions()
for p in positions:
print(f"{p['symbol']}: Qty {p['positionAmt']}, Entry {p['entryPrice']}, UnPnL {p['unRealizedProfit']}")
IV. Comparison of Order Parameters
Placing a Spot order requires only 4-5 parameters; Futures requires additional fields like position side, reduce-only, and self-trade prevention:
| Parameter | Spot | Futures |
|---|---|---|
| symbol | Mandatory | Mandatory |
| side | BUY / SELL | BUY / SELL |
| type | LIMIT/MARKET/... | LIMIT/MARKET/STOP/TAKE_PROFIT/TRAILING_STOP_MARKET |
| quantity | Mandatory | Mandatory (or use closePosition) |
| positionSide | — | BOTH (One-way) / LONG / SHORT (Hedge) |
| reduceOnly | — | true for reduce-only orders |
| closePosition | — | true for one-click liquidation |
| workingType | — | MARK_PRICE / CONTRACT_PRICE |
| newOrderRespType | ACK/RESULT/FULL | ACK/RESULT |
Futures Limit Order Example
def place_futures_limit(symbol, side, quantity, price, position_side="BOTH"):
params = _sign({
"symbol": symbol,
"side": side,
"type": "LIMIT",
"timeInForce": "GTC",
"quantity": str(quantity),
"price": str(price),
"positionSide": position_side,
})
r = requests.post(f"{FAPI}/fapi/v1/order", params=params,
headers={"X-MBX-APIKEY": API_KEY})
return r.json()
# Open Long 0.01 BTC, Limit 60000
order = place_futures_limit("BTCUSDT", "BUY", 0.01, 60000)
print(order["orderId"])
V. Leverage and Margin Mode Settings
Two interfaces unique to Futures:
# Set Leverage Multiplier
def set_leverage(symbol: str, leverage: int):
params = _sign({"symbol": symbol, "leverage": leverage})
r = requests.post(f"{FAPI}/fapi/v1/leverage", params=params,
headers={"X-MBX-APIKEY": API_KEY})
return r.json()
set_leverage("BTCUSDT", 10) # Set 10x leverage
# Set Margin Mode: ISOLATED or CROSSED
def set_margin_type(symbol: str, margin_type: str):
params = _sign({"symbol": symbol, "marginType": margin_type})
r = requests.post(f"{FAPI}/fapi/v1/marginType", params=params,
headers={"X-MBX-APIKEY": API_KEY})
return r.json()
set_margin_type("BTCUSDT", "ISOLATED")
Note: You cannot switch margin modes while a position exists for the same symbol; you must close the position first.
VI. Funding Rate
The Funding Rate is a concept unique to contracts, settled every 8 hours:
# Query Latest Funding Rate
def get_funding_rate(symbol="BTCUSDT"):
r = requests.get(f"{FAPI}/fapi/v1/premiumIndex",
params={"symbol": symbol})
data = r.json()
return {
"markPrice": data["markPrice"],
"fundingRate": data["lastFundingRate"],
"nextFundingTime": data["nextFundingTime"]
}
# Query Historical Funding Rate
def funding_history(symbol, limit=100):
r = requests.get(f"{FAPI}/fapi/v1/fundingRate",
params={"symbol": symbol, "limit": limit})
return r.json()
Arbitrage Tip: When fundingRate is positive, longs pay shorts; when negative, the opposite applies. A common strategy when rates remain highly positive for days is to short USDⓈ-M futures while going long on the spot market.
VII. Differences in Weights and Rate Limits
# Spot Response Headers
X-MBX-USED-WEIGHT-1m: 45
X-MBX-ORDER-COUNT-10s: 3
# Futures Response Headers
X-MBX-USED-WEIGHT-1m: 12
X-MBX-ORDER-COUNT-1m: 5
X-MBX-ORDER-COUNT-10s: 3
Futures adds a 1-minute order limit (default 1200 orders/minute), which must be monitored in high-frequency strategies.
VIII. WebSocket Differences
# Spot Subscription
import websocket, json
def on_message(ws, msg):
data = json.loads(msg)
print(data["s"], data["c"]) # symbol, close price
# Spot
ws_spot = websocket.WebSocketApp(
"wss://stream.binance.com:9443/ws/btcusdt@ticker",
on_message=on_message)
# USDⓈ-M Futures
ws_fut = websocket.WebSocketApp(
"wss://fstream.binance.com/ws/btcusdt@markPrice", # Mark Price Push
on_message=on_message)
Unique Futures subscription topics include: @markPrice, @forceOrder (Liquidation Push), and @liquidation.
IX. Strategy Code for Parallel Spot + Futures Operations
Hedging strategies often require opening a Spot long position and a Futures short position simultaneously:
import asyncio, aiohttp
async def spot_buy(session, symbol, qty):
# Simplified: Needs signing in practice
async with session.post("https://api.binance.com/api/v3/order",
params={"symbol": symbol, "side": "BUY",
"type": "MARKET", "quantity": qty}) as r:
return await r.json()
async def futures_short(session, symbol, qty):
async with session.post("https://fapi.binance.com/fapi/v1/order",
params={"symbol": symbol, "side": "SELL",
"type": "MARKET", "quantity": qty}) as r:
return await r.json()
async def hedge():
async with aiohttp.ClientSession() as s:
results = await asyncio.gather(
spot_buy(s, "BTCUSDT", 0.01),
futures_short(s, "BTCUSDT", 0.01)
)
print(results)
asyncio.run(hedge())
X. FAQ
Q1: Can I use one set of API Keys to operate both Spot and Futures?
A: Yes. In the API Key permission settings, check both Enable Spot & Margin Trading and Enable Futures. Remember that Futures accounts must be opened separately on the web portal and pass a knowledge test, otherwise, API calls will return -2015 Invalid API-key, IP, or permissions.
Q2: Are the balances for fapi.binance.com and dapi.binance.com independent?
A: Yes. USDⓈ-M Futures use independent USDT/USDC wallets, COIN-M Futures use independent BTC/ETH wallets, and the Spot wallet is entirely separate. Funds must be moved between accounts via /sapi/v1/futures/transfer.
Q3: What is the difference between Futures v1 and v2?
A: V2 is an enhanced version with optimized precision and field naming. Positions and balances MUST use v2 (/fapi/v2/positionRisk, /fapi/v2/balance), while placing or canceling orders remains in v1 (/fapi/v1/order).
Q4: Do I need to change my code for Portfolio Margin accounts?
A: Portfolio Margin uses a separate domain papi.binance.com/papi/v1/*. The endpoints are similar to fapi but with slight parameter differences. This only applies to VIP or high-net-worth accounts.
Q5: What is the minimum order amount for Futures API?
A: For USDⓈ-M, it's typically 5 USDT notional value (e.g., about 0.0001 BTC if the price is 60,000); popular pairs like BNBUSDT and ETHUSDT may go down to 1 USDT. Check the MIN_NOTIONAL filter via GET /fapi/v1/exchangeInfo for specifics.
For more Futures API topics, return to the Categories and select the "API Integration" section.