Cómo obtener el historial de velas (K-lines) de Binance vía API y evitar la pérdida de datos
Para realizar backtesting de estrategias con API, es necesario paginar y eliminar duplicados en los datos de velas. Este artículo presenta el estándar para obtener el historial correctamente.
Cualquier estrategia de backtesting requiere un historial de velas (K-lines). Primero, crea una API Key de solo lectura en la web oficial de Binance y utiliza la app oficial de Binance (para iOS, consulta el tutorial de instalación en iOS).
El Endpoint
GET /api/v3/klines
Parámetros: symbol, interval, startTime, endTime, limit
El parámetro limit tiene un máximo de 1000 registros por solicitud.
Obtener todo el historial de una vez
No es posible obtenerlo en una única llamada debido al límite de 1000 registros. Es necesario implementar una paginación.
Paradigma de paginación
import time
all_klines = []
end = int(time.time() * 1000)
start = end - 365 * 24 * 3600 * 1000 # Hace 1 año
while start < end:
klines = client.get_klines(
symbol='BTCUSDT',
interval='1h',
startTime=start,
limit=1000
)
if not klines:
break
all_klines.extend(klines)
start = klines[-1][0] + 1 # El siguiente lote empieza en el último timestamp + 1ms
time.sleep(0.5) # Protección de límite de velocidad
Eliminación de duplicados
Las velas en los límites de cada lote podrían duplicarse. Al sumar 1ms al final de cada lote evitamos esto.
Alternativamente, puedes usar Pandas:
import pandas as pd
df = pd.DataFrame(all_klines)
df = df.drop_duplicates(subset=[0]) # Eliminar duplicados por timestamp
Formato de la vela (K-line)
Cada vela es un array con el siguiente formato:
[
open_time, # Timestamp de apertura en ms
open, # Precio de apertura
high, # Máximo
low, # Mínimo
close, # Precio de cierre
volume, # Volumen
close_time, # Timestamp de cierre
quote_volume, # Volumen en la moneda de cotización
trades, # Número de operaciones
taker_buy_base,
taker_buy_quote,
ignore
]
Conversión a DataFrame
df = pd.DataFrame(all_klines, columns=[
'open_time','open','high','low','close','volume',
'close_time','quote_volume','trades',
'taker_buy_base','taker_buy_quote','ignore'
])
df['open_time'] = pd.to_datetime(df['open_time'], unit='ms')
df.set_index('open_time', inplace=True)
df = df.astype({'open': float, 'high': float, 'low': float, 'close': float, 'volume': float})
A partir de aquí, puedes usarlo con Pandas, Numpy o cualquier librería de backtesting.
Periodos y volumen de datos
| Periodo | Velas por 1 año |
|---|---|
| 1m | 525,600 |
| 5m | 105,120 |
| 15m | 35,040 |
| 1h | 8,760 |
| 4h | 2,190 |
| 1d | 365 |
Solicitando lotes de 1000 registros:
- 1 año en 1m = 526 peticiones = 4-5 minutos.
- 1 año en 1h = 9 peticiones = pocos segundos.
Concurrencia de varios símbolos
import concurrent.futures
symbols = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT']
def fetch(s):
return get_history(s, '1h', 365)
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
results = list(ex.map(fetch, symbols))
Usa concurrencia pero vigila no exceder el límite de peso (weight) de la API.
Público vs. Autenticado
Los datos históricos de velas son públicos. Puedes obtenerlos incluso sin una API Key:
import requests
url = 'https://api.binance.com/api/v3/klines'
params = {'symbol': 'BTCUSDT', 'interval': '1h', 'limit': 1000}
r = requests.get(url, params=params)
Sin embargo, usar una API Key autenticada suele permitir límites de peso superiores.
Datos anuales completos
Binance ofrece descarga de datos históricos masivos en formato ZIP/CSV:
- data.binance.vision/
Están organizados por meses y tipo de velas. Es mucho más rápido que usar la API para grandes volúmenes.
Actualización continua
Tras el backtest, para operar en real necesitas actualizar las velas en tiempo real. Hay dos formas:
1. Sondeo periódico (Polling)
Solicitas las últimas 5 velas cada minuto para actualizar tu base de datos local.
2. WebSocket
Te suscribes al flujo (stream) de velas vía WS:
wss://stream.binance.com:9443/ws/btcusdt@kline_1h
Recibirás actualizaciones en tiempo real conforme la vela evoluciona. Los WebSockets son ideales para tiempo real; REST es mejor para completar el historial.
Calidad de los datos
Ten en cuenta:
- Micro-cortes de red pueden hacer que pierdas un lote.
- Verifica los timestamps (son milisegundos, no segundos).
- La vela actual (la más reciente) aún no está cerrada y su precio de cierre variará.
Al hacer backtesting, excluye la vela más reciente que aún no se ha cerrado.
Persistencia
Almacena los datos descargados en:
- CSV: Sencillo.
- Parquet: Compresión eficiente.
- SQLite: Consultas fáciles.
- DuckDB: Análisis rápido.
- Bases de datos de series temporales (TimescaleDB): Para volúmenes masivos.
Para volúmenes medios, Parquet es la mejor opción.
Historial de derivados
Endpoints para contratos:
- Margen USDT (U-based):
/fapi/v1/klines - Margen Cripto (Coin-based):
/dapi/v1/klines
Los parámetros y el formato de respuesta son idénticos a los de Spot v3.
Historial de tasas de financiación
GET /fapi/v1/fundingRate?symbol=BTCUSDT&limit=1000
Se genera un registro cada 8 horas. Un máximo de 1000 registros equivale a unos 333 días.
Preguntas frecuentes
P: ¿Me pueden limitar la velocidad por descargar el historial? R: Sí. Asegúrate de incluir tiempos de espera (sleep) entre peticiones.
P: ¿Puedo descargar el historial de todas las monedas? R: Sí, aunque el historial de monedas que han sido deslistadas puede ser limitado.
P: ¿Cuánto ocupa el historial de 1m? R: Un año de velas de 1m son aproximadamente 50MB en CSV. Para muchas monedas, el volumen total puede ser considerable.
P: ¿El historial incluye deslizamiento (slippage)? R: No. Deberás añadir un modelo de deslizamiento propio en tu backtest.
P: ¿Puedo usar estos datos para fines comerciales? R: Para tus propias estrategias, sí. Para republicarlos, consulta los términos de servicio de Binance.
Lecturas recomendadas
El historial de velas es el combustible del backtesting. Aprender a descargar, limpiar y almacenar estos datos es el primer paso hacia el éxito en el trading cuantitativo.