La diferencia fundamental entre la API de Binance Futures y la API de Spot radica en los dominios base y el conjunto de parámetros: Spot utiliza api.binance.com/api/v3/*, Futures con margen en criptoestable (USDⓈ-M) utiliza fapi.binance.com/fapi/v1/*, y Futures con margen en criptomoneda (COIN-M) utiliza dapi.binance.com/dapi/v1/*. Aunque el algoritmo de firma es el mismo (HMAC-SHA256), los contratos requieren parámetros adicionales como reduceOnly, positionSide y leverage, además de tener reglas de peso distintas. Este artículo presenta una tabla comparativa en 10 dimensiones y código real para ayudarte a migrar tus estrategias de trading cuantitativo de Spot a Futures sin problemas. Si no tienes una cuenta de Binance, por favor completa el registro en el sitio oficial de Binance; los nuevos usuarios pueden abrir una cuenta a través del canal de registro gratuito.
I. Tabla comparativa general
| Dimensión | Spot (Contado) | Futures USDⓈ-M | Futures COIN-M |
|---|---|---|---|
| URL Base | api.binance.com | fapi.binance.com | dapi.binance.com |
| Prefijo de ruta | /api/v3/ | /fapi/v1/ y /fapi/v2/ | /dapi/v1/ |
| Moneda de margen | — | USDT, USDC | BTC, ETH, BNB, etc. |
| Apalancamiento máx. | No compatible (solo margen) | 125x | 125x |
| Posición bidireccional | No compatible | Compatible (modo HEDGE) | Compatible |
| URL de WebSocket | stream.binance.com:9443 | fstream.binance.com | dstream.binance.com |
| Monto mín. de orden | 5 USDT (MIN_NOTIONAL) | 5 USDT | Según valor nominal en cripto |
| Tasa de financiación | No tiene | Cada 8 horas | Cada 8 horas |
| Peso por minuto | 6000 | 2400 | 2400 |
| Validez de listenKey | 60 minutos | 60 minutos | 60 minutos |
Punto clave para recordar: Los endpoints de USDⓈ-M siempre comienzan con fapi, y los de COIN-M con dapi. Nunca intentes usar el código de Spot simplemente cambiando la URL.
II. Sutiles diferencias en el mecanismo de firma
El algoritmo de firma es idéntico (HMAC-SHA256), pero hay dos puntos a tener en cuenta:
1. Valor por defecto de recvWindow
- Spot: Por defecto 5000ms, máximo 60000ms.
- Futures: Por defecto 5000ms, máximo 60000ms, pero se recomienda encarecidamente no exceder los 5000ms.
2. Se recomienda usar strings para parámetros numéricos
La API de Futures es más sensible a la precisión numérica. Al colocar una orden, se recomienda pasar price y quantity como cadenas de texto para evitar errores de tipo -1111 Precision causados por la precisión de punto flotante:
# No recomendado
{"price": 60000.123456789, "quantity": 0.001}
# Recomendado
{"price": "60000.12", "quantity": "0.001"}
III. Diferencias en la interfaz de consulta de saldo y posiciones
Saldo en Spot
# Spot: GET /api/v3/account
# Devuelve el array de balances
{
"balances": [{"asset": "USDT", "free": "1000", "locked": "0"}]
}
Posiciones en Futures USDⓈ-M
import hmac, hashlib, time, requests
from urllib.parse import urlencode
API_KEY = "TU_KEY"
SECRET_KEY = "TU_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():
"""Consulta de posiciones V2: devuelve todas las posiciones no nulas"""
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():
"""Saldo de la cuenta de futuros V2"""
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']}: Cantidad {p['positionAmt']}, Precio entrada {p['entryPrice']}, PNL no realizado {p['unRealizedProfit']}")
IV. Comparativa de parámetros de orden
Colocar una orden en Spot solo requiere 4-5 parámetros; Futures necesita campos adicionales como dirección de la posición, si es solo reducción, protección de auto-trading, etc.:
| Parámetro | Spot | Futures |
|---|---|---|
| symbol | Obligatorio | Obligatorio |
| side | BUY / SELL | BUY / SELL |
| type | LIMIT/MARKET/... | LIMIT/MARKET/STOP/TAKE_PROFIT/TRAILING_STOP_MARKET |
| quantity | Obligatorio | Obligatorio (o usar closePosition) |
| positionSide | — | BOTH (unidireccional) / LONG / SHORT (bidireccional) |
| reduceOnly | — | true indica que solo reduce la posición |
| closePosition | — | true para cierre total con un clic |
| workingType | — | MARK_PRICE / CONTRACT_PRICE |
| newOrderRespType | ACK/RESULT/FULL | ACK/RESULT |
Ejemplo de orden limitada en Futures
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()
# Abrir largo 0.01 BTC, límite 60000
order = place_futures_limit("BTCUSDT", "BUY", 0.01, 60000)
print(order["orderId"])
V. Apalancamiento y configuración del modo de margen
Interfaces exclusivas de Futures:
# Establecer nivel de apalancamiento
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) # Establecer apalancamiento 10x
# Establecer modo de margen: ISOLATED (Aislado) o CROSSED (Cruzado)
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")
Nota: No se puede cambiar el modo de margen si hay posiciones abiertas para ese par; primero hay que cerrar las posiciones.
VI. Tasa de financiación (Funding Rate)
El Funding Rate es un concepto exclusivo de contratos, liquidado cada 8 horas:
# Consultar tasa de financiación actual
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"]
}
# Consultar historial de tasas de financiación
def funding_history(symbol, limit=100):
r = requests.get(f"{FAPI}/fapi/v1/fundingRate",
params={"symbol": symbol, "limit": limit})
return r.json()
Consejo de arbitraje: Cuando fundingRate es positivo, los largos pagan a los cortos; cuando es negativo, ocurre lo contrario. Mantener una posición corta en USDⓈ-M + larga en Spot es una estrategia común de arbitraje de tasas de financiación cuando estas son altas y positivas.
VII. Diferencias en pesos y límites de frecuencia
# Cabeceras de respuesta en Spot
X-MBX-USED-WEIGHT-1m: 45
X-MBX-ORDER-COUNT-10s: 3
# Cabeceras de respuesta en Futures
X-MBX-USED-WEIGHT-1m: 12
X-MBX-ORDER-COUNT-1m: 5
X-MBX-ORDER-COUNT-10s: 3
Futures tiene un límite de órdenes por minuto adicional (por defecto 1200 órdenes/min), que debe monitorearse de cerca en estrategias de alta frecuencia.
VIII. Diferencias en WebSocket
# Suscripción a datos en Spot
import websocket, json
def on_message(ws, msg):
data = json.loads(msg)
print(data["s"], data["c"]) # símbolo, precio de cierre
# Spot
ws_spot = websocket.WebSocketApp(
"wss://stream.binance.com:9443/ws/btcusdt@ticker",
on_message=on_message)
# Futures USDⓈ-M
ws_fut = websocket.WebSocketApp(
"wss://fstream.binance.com/ws/btcusdt@markPrice", # Empuje de precio de marca
on_message=on_message)
Temas de suscripción exclusivos de Futures: @markPrice (precio de marca), @forceOrder (empuje de liquidaciones forzosas), @liquidation.
IX. Código de estrategia para operar Spot + Futures en paralelo
Las estrategias de cobertura a menudo requieren abrir posiciones largas en Spot + cortas en Futures simultáneamente:
import asyncio, aiohttp
async def spot_buy(session, symbol, qty):
# Simplificado: en la práctica requiere firma
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. Preguntas frecuentes (FAQ)
P1: ¿Puedo usar un solo juego de claves API para operar tanto en Spot como en Futures?
R: Sí. En la página de permisos de la API, marca Enable Spot & Margin Trading y Enable Futures respectivamente. Recuerda que para Futures debes activar la cuenta de futuros manualmente en la web y pasar el cuestionario; de lo contrario, la API devolverá el error -2015 Invalid API-key, IP, or permissions.
P2: ¿fapi.binance.com y dapi.binance.com tienen saldos de cuenta independientes?
R: Sí. Los futuros USDⓈ-M usan una billetera independiente de USDT/USDC, los futuros COIN-M usan billeteras independientes de BTC/ETH, y la billetera Spot es completamente aparte. Los fondos deben transferirse entre cuentas usando /sapi/v1/futures/transfer.
P3: ¿Cuál es la diferencia entre Futures V1 y V2?
R: V2 es una versión mejorada que optimiza la precisión y la nomenclatura de los campos. Es obligatorio usar V2 para posiciones y saldos (/fapi/v2/positionRisk, /fapi/v2/balance), mientras que colocar o cancelar órdenes sigue en V1 (/fapi/v1/order).
P4: ¿Tengo que cambiar el código para la Cuenta Unificada (Portfolio Margin)?
R: La cuenta unificada utiliza el dominio independiente papi.binance.com/papi/v1/*. Los endpoints son similares a fapi pero con parámetros ligeramente diferentes. Solo está disponible para cuentas VIP o de alto patrimonio.
P5: ¿Cuál es el monto mínimo de orden para la API de Futures?
R: Para USDⓈ-M, el valor nominal mínimo es generalmente de 5 USDT (por ejemplo, con el BTC a 60,000, la cantidad mínima es de aprox. 0.0001 BTC). Para pares populares como BNBUSDT o ETHUSDT, el mínimo puede bajar a 1 USDT. Consulta el filtro MIN_NOTIONAL en GET /fapi/v1/exchangeInfo para más detalles.
Para más temas especializados sobre la API de contratos, vuelve a la sección «Integración API» en la Navegación de Categorías.