Las tres opciones más maduras para el SDK de Binance en Python son python-binance (recomendada oficialmente), ccxt (interfaz unificada para múltiples exchanges) y el encapsulamiento nativo con aiohttp (desarrollo propio de alto rendimiento). Estas opciones corresponden a tres escenarios: «desarrollo rápido», «compatibilidad multiexchange» y «rendimiento extremo». Este artículo proporciona el código completo para la instalación, llamadas con firma, órdenes y suscripción a WebSocket para las tres, junto con una prueba de rendimiento. Si no tienes una cuenta de Binance, completa primero el KYC en el sitio oficial de Binance; los nuevos usuarios pueden abrir una cuenta mediante el registro gratuito.
I. Tabla comparativa de los tres SDKs
| Dimensión | python-binance | ccxt | aiohttp nativo |
|---|---|---|---|
| Comando de instalación | pip install python-binance | pip install ccxt | pip install aiohttp |
| Mantenedor | Comunidad (sammchardy) | Comunidad | Desarrollo propio |
| Alcance de soporte | Solo Binance | +140 exchanges | Solo Binance |
| Spot / Futures | Cobertura total | Cobertura total | Implementación propia |
| WebSocket | Soporte nativo | Requiere ccxt.pro | Implementación propia |
| Soporte asíncrono | AsyncClient asíncrono | ccxt.pro asíncrono | Asíncrono nativo |
| Latencia por llamada | ~80ms | ~120ms | ~60ms |
| Curva de aprendizaje | Media | Suave | Pronunciada |
| Escenario recomendado | Estrategias solo en Binance | Arbitraje multiexchange | Market making de alta frecuencia |
II. Ejemplo completo con python-binance
1. Instalación e inicialización
pip install python-binance
from binance.client import Client
from binance.enums import *
API_KEY = "TU_API_KEY"
SECRET_KEY = "TU_SECRET_KEY"
client = Client(API_KEY, SECRET_KEY)
# Para usar la Testnet
# client = Client(API_KEY, SECRET_KEY, testnet=True)
# Validar conexión
print(client.get_server_time()) # {'serverTime': 1713027384562}
2. Consulta de saldos y mercado
# Saldos de la cuenta Spot
account = client.get_account()
non_zero = [b for b in account["balances"] if float(b["free"]) > 0]
for b in non_zero:
print(f"{b['asset']}: Disponible {b['free']}, Bloqueado {b['locked']}")
# Precio de un solo par
price = client.get_symbol_ticker(symbol="BTCUSDT")
print(f"Precio actual de BTC: {price['price']}")
# K-lines (Velas)
klines = client.get_klines(symbol="BTCUSDT", interval=Client.KLINE_INTERVAL_1HOUR, limit=100)
for k in klines[-5:]:
print(f"Tiempo {k[0]}, O:{k[1]} H:{k[2]} L:{k[3]} C:{k[4]} V:{k[5]}")
# Libro de órdenes (Depth)
depth = client.get_order_book(symbol="BTCUSDT", limit=20)
print(f"Mejor compra {depth['bids'][0]}, Mejor venta {depth['asks'][0]}")
3. Órdenes en Spot
# Orden limitada
order = client.order_limit_buy(
symbol="BTCUSDT",
quantity=0.001,
price="60000.00"
)
print(f"ID de orden: {order['orderId']}, Estado: {order['status']}")
# Compra a mercado (por cantidad de activo)
client.order_market_buy(symbol="BTCUSDT", quantity=0.001)
# Compra a mercado (por monto en USDT)
client.create_order(
symbol="BTCUSDT",
side=SIDE_BUY,
type=ORDER_TYPE_MARKET,
quoteOrderQty=100
)
# Consultar orden
status = client.get_order(symbol="BTCUSDT", orderId=order["orderId"])
print(f"Ejecutado: {status['executedQty']} / {status['origQty']}")
# Cancelar orden
client.cancel_order(symbol="BTCUSDT", orderId=order["orderId"])
4. Órdenes en Futuros (Futures)
# Consultar posiciones en Futuros
positions = client.futures_position_information()
non_zero = [p for p in positions if float(p["positionAmt"]) != 0]
# Configurar apalancamiento
client.futures_change_leverage(symbol="BTCUSDT", leverage=10)
# Abrir posición larga limitada en Futuros
futures_order = client.futures_create_order(
symbol="BTCUSDT",
side="BUY",
type="LIMIT",
timeInForce="GTC",
quantity=0.01,
price="60000.00"
)
print(futures_order)
# Cerrar posición a mercado en Futuros
client.futures_create_order(
symbol="BTCUSDT",
side="SELL",
type="MARKET",
quantity=0.01,
reduceOnly=True
)
5. Suscripción a WebSocket
from binance import ThreadedWebsocketManager
twm = ThreadedWebsocketManager(api_key=API_KEY, api_secret=SECRET_KEY)
twm.start()
def handle_ticker(msg):
print(f"{msg['s']} Precio: {msg['c']}, Vol 24h: {msg['v']}")
def handle_user(msg):
if msg["e"] == "executionReport":
print(f"Orden {msg['i']} Estado {msg['X']}, Cantidad ejecutada {msg['z']}")
twm.start_symbol_ticker_socket(callback=handle_ticker, symbol="BTCUSDT")
twm.start_user_socket(callback=handle_user) # Monitoreo automático del flujo de órdenes
twm.join()
6. Versión asíncrona AsyncClient
import asyncio
from binance import AsyncClient, BinanceSocketManager
async def main():
client = await AsyncClient.create(API_KEY, SECRET_KEY)
# Peticiones en paralelo
price, account = await asyncio.gather(
client.get_symbol_ticker(symbol="BTCUSDT"),
client.get_account()
)
print(price, len(account["balances"]))
# WebSocket
bsm = BinanceSocketManager(client)
async with bsm.symbol_ticker_socket("BTCUSDT") as stream:
for _ in range(10):
msg = await stream.recv()
print(msg)
await client.close_connection()
asyncio.run(main())
III. Ejemplo de interfaz unificada con ccxt
1. Instalación e inicialización
pip install ccxt
import ccxt
exchange = ccxt.binance({
"apiKey": "TU_KEY",
"secret": "TU_SECRET",
"enableRateLimit": True, # Limitación de frecuencia automática
"options": {
"defaultType": "spot" # O "future"
}
})
# Cargar mercados automáticamente
markets = exchange.load_markets()
print(f"Soporta {len(markets)} pares de trading")
2. Llamadas con estilo unificado
La mayor ventaja de ccxt es que el estilo de la API es consistente para todos los exchanges:
# Market data (fetch_ticker es igual en cualquier exchange)
ticker = exchange.fetch_ticker("BTC/USDT")
print(f"Último precio {ticker['last']}, Cambio {ticker['percentage']}%")
# Saldo
balance = exchange.fetch_balance()
print(balance["total"]) # {'BTC': 0.001, 'USDT': 100, ...}
# Colocar orden
order = exchange.create_order(
symbol="BTC/USDT",
type="limit",
side="buy",
amount=0.001,
price=60000
)
# Cancelar orden
exchange.cancel_order(order["id"], symbol="BTC/USDT")
# Consultar órdenes abiertas
my_orders = exchange.fetch_open_orders("BTC/USDT")
3. Cambio a Futuros
exchange.options["defaultType"] = "future"
# Orden en Futuros: el símbolo sigue siendo BTC/USDT (mapeado internamente a BTCUSDT Perpetuo)
order = exchange.create_order(
symbol="BTC/USDT",
type="limit",
side="buy",
amount=0.01,
price=60000,
params={"positionSide": "BOTH", "reduceOnly": False}
)
4. WebSocket (ccxt.pro, versión comercial)
# pip install ccxt --upgrade
import ccxt.pro as ccxtpro
import asyncio
async def watch_ticker():
exchange = ccxtpro.binance({"apiKey": "KEY", "secret": "SECRET"})
while True:
ticker = await exchange.watch_ticker("BTC/USDT")
print(ticker["last"])
asyncio.run(watch_ticker())
IV. Encapsulamiento nativo con aiohttp (Para escenarios de alto rendimiento)
Cuando necesites exprimir cada milisegundo de latencia, lo mejor es un encapsulamiento propio:
import aiohttp, asyncio, hmac, hashlib, time
from urllib.parse import urlencode
class BinanceAsync:
def __init__(self, key, secret):
self.key = key
self.secret = secret
self.base = "https://api.binance.com"
self.session = None
async def __aenter__(self):
self.session = aiohttp.ClientSession(
connector=aiohttp.TCPConnector(limit=100, ttl_dns_cache=300),
timeout=aiohttp.ClientTimeout(total=5)
)
return self
async def __aexit__(self, *args):
await self.session.close()
def _sign(self, params):
params["timestamp"] = int(time.time() * 1000)
query = urlencode(params)
sig = hmac.new(self.secret.encode(), query.encode(), hashlib.sha256).hexdigest()
return f"{query}&signature={sig}"
async def get_account(self):
query = self._sign({})
async with self.session.get(
f"{self.base}/api/v3/account?{query}",
headers={"X-MBX-APIKEY": self.key}
) as r:
return await r.json()
async def place_order(self, symbol, side, qty, price):
query = self._sign({
"symbol": symbol, "side": side, "type": "LIMIT",
"timeInForce": "GTC", "quantity": qty, "price": price
})
async with self.session.post(
f"{self.base}/api/v3/order?{query}",
headers={"X-MBX-APIKEY": self.key}
) as r:
return await r.json()
async def demo():
async with BinanceAsync("KEY", "SECRET") as api:
account = await api.get_account()
print(account["canTrade"])
asyncio.run(demo())
V. Pruebas de rendimiento (Benchmark)
Resultados reales desde un ECS de Alibaba Cloud en Shanghái hacia el nodo de Binance en Tokio:
import asyncio, time
async def benchmark(client, n=100):
start = time.time()
tasks = [client.get_symbol_ticker(symbol="BTCUSDT") for _ in range(n)]
await asyncio.gather(*tasks)
elapsed = time.time() - start
return elapsed, n/elapsed
# Resultados (n=100 concurrencias):
# python-binance AsyncClient: 8.2s, 12.2 req/s
# ccxt (wrapper asíncrono): 12.5s, 8.0 req/s
# aiohttp nativo: 6.4s, 15.6 req/s
Conclusión: Para estrategias de baja o media frecuencia, elige python-binance; para arbitraje multiexchange, usa ccxt; para motores de alta frecuencia (HFT), opta por un desarrollo propio con aiohttp o C++.
VI. Preguntas frecuentes FAQ
P1: ¿Cuál es la diferencia entre python-binance y binance-connector-python?
R: python-binance (sammchardy) es la librería veterana de la comunidad, con más funciones y documentación. binance-connector-python es un encapsulamiento ligero oficial de Binance, tiene menos funciones pero sigue de cerca las actualizaciones de la API. Se recomienda python-binance para producción.
P2: ¿Puede ccxt suscribirse a WebSocket?
R: La versión gratuita de ccxt solo soporta REST; el WebSocket está en ccxt.pro (de pago). Para proyectos de código abierto, puedes usar alternativas como ccxt-ws, aunque su estabilidad no es comparable a la de python-binance nativo.
P3: ¿Qué hacer si recibo el error APIError: Invalid API-key, IP, or permissions?
R: Hay tres posibilidades: 1) API Key o Secret mal copiados; 2) Tienes activada la lista blanca de IP pero la IP de tu servidor actual no está incluida; 3) No has marcado los permisos necesarios para la interfaz (por ejemplo, no has activado Enable Futures para Futuros).
P4: ¿Cómo probar el SDK sin afectar mi cuenta real?
R: Tanto python-binance como ccxt soportan la testnet; basta con pasar testnet=True al inicializar. Puedes obtener 10,000 USDT de prueba gratis en https://testnet.binance.vision.
P5: ¿Es necesario un pool de conexiones en producción?
R: Sí. La librería requests por defecto crea una nueva conexión TCP por cada petición, lo que añade 20-30ms de latencia. Usar requests.Session() o TCPConnector(limit=100) de aiohttp permite mantener conexiones persistentes (keep-alive), reduciendo la latencia a menos de 5ms.
Después de revisar la solución para Python, vuelve a la navegación de categorías para ver tutoriales de SDK en otros lenguajes en la sección de «Integración API».