Ejecutar backtesting con datos históricos de Binance

Video
25 min~5 min lectura

Reproductor de video

Concepto clave

El backtesting es el proceso de probar una estrategia de trading utilizando datos históricos para evaluar su rendimiento potencial antes de arriesgar capital real. Imagina que eres un arquitecto que diseña un edificio: primero creas un modelo digital y lo sometes a simulaciones de terremotos, vientos fuertes y otros eventos extremos para ver si se mantendrá en pie. El backtesting es esa simulación para tu estrategia de trading, donde los datos históricos representan esas condiciones extremas del mercado.

En el contexto de Binance, esto significa descargar datos de precios pasados (como velas de 1 minuto, 1 hora, etc.) y ejecutar tu algoritmo sobre ellos para ver cómo habría operado. La clave está en la precisión: debes considerar comisiones, slippage (deslizamiento de precios) y límites de orden para que la simulación sea realista. Un backtesting bien ejecutado te permite identificar debilidades en tu estrategia, como sobreajuste (cuando la estrategia funciona sólo en datos específicos pero falla en nuevos datos) o pérdidas durante eventos de mercado volátiles.

Cómo funciona en la práctica

Para ejecutar un backtesting con datos de Binance, seguimos un flujo estructurado. Primero, obtenemos los datos históricos usando la API de Binance. Por ejemplo, para el par BTC/USDT, descargamos velas de precios con un intervalo específico (como 1h) para un período determinado (ej., últimos 30 días). Luego, procesamos estos datos para calcular indicadores técnicos, como medias móviles o RSI, que nuestra estrategia utilizará para tomar decisiones.

Después, simulamos las operaciones: recorremos cada punto en el tiempo, aplicamos las reglas de la estrategia (ej., comprar cuando la media móvil corta al alza) y registramos cada operación con su precio de entrada, salida y comisiones. Finalmente, generamos métricas de rendimiento como el retorno total, máxima pérdida flotante (drawdown) y ratio de Sharpe para evaluar si la estrategia es viable. Es crucial usar una biblioteca como backtrader o vectorbt para automatizar este proceso y evitar errores manuales.

Código en acción

Aquí tienes un ejemplo básico usando Python y la biblioteca ccxt para obtener datos de Binance, seguido de una simulación simple. Antes de optimizar, así es como podrías empezar:

import ccxt
import pandas as pd
import numpy as np

# Configurar la conexión a Binance
exchange = ccxt.binance({
    'enableRateLimit': True
})

# Descargar datos históricos de BTC/USDT con velas de 1 hora
symbol = 'BTC/USDT'
timeframe = '1h'
since = exchange.parse8601('2023-01-01T00:00:00Z')
ohlcv = exchange.fetch_ohlcv(symbol, timeframe, since, limit=1000)

# Convertir a DataFrame
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
print(df.head())

Después de refactorizar para mejorar la eficiencia y añadir backtesting, integramos una biblioteca especializada. Este código usa backtrader para una simulación más robusta:

import backtrader as bt
import backtrader.feeds as btfeeds

# Definir una estrategia simple de media móvil
class MovingAverageStrategy(bt.Strategy):
    params = (('fast', 10), ('slow', 30))
    
    def __init__(self):
        self.fast_ma = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.fast)
        self.slow_ma = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.slow)
        self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)
    
    def next(self):
        if not self.position:
            if self.crossover > 0:
                self.buy()
        elif self.crossover < 0:
            self.sell()

# Configurar cerebro de backtesting
cerebro = bt.Cerebro()
cerebro.addstrategy(MovingAverageStrategy)

# Cargar datos desde el DataFrame (asumiendo df del ejemplo anterior)
data = btfeeds.PandasData(dataname=df)
cerebro.adddata(data)

# Configurar capital inicial y comisiones
cerebro.broker.setcash(10000.0)
cerebro.broker.setcommission(commission=0.001)  # 0.1% comisión de Binance

# Ejecutar backtesting
print('Capital inicial: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Capital final: %.2f' % cerebro.broker.getvalue())

# Graficar resultados (opcional)
cerebro.plot()

Errores comunes

  • Sobreajuste (Overfitting): Ajustar la estrategia demasiado a datos históricos específicos, haciéndola poco generalizable. Evítalo usando datos de out-of-sample (datos no vistos durante el desarrollo) y validación cruzada.
  • Ignorar comisiones y slippage: No incluir costos de trading puede inflar los resultados. Siempre configura comisiones realistas (ej., 0.1% para Binance) y añade un slippage estimado (ej., 0.05%).
  • Falta de manejo de datos faltantes: Si los datos históricos tienen huecos, puede distorsionar las operaciones. Usa métodos como forward-fill o interpolar para llenar gaps.
  • No considerar límites de liquidez
  • Backtesting en períodos cortos

Checklist de dominio

  1. Puedo descargar datos históricos de Binance usando la API con Python y convertirlos a un formato usable para backtesting.
  2. Sé implementar una estrategia de trading en código, integrando indicadores técnicos y reglas de entrada/salida.
  3. He configurado un entorno de backtesting que incluye comisiones, slippage y capital inicial realista.
  4. Puedo ejecutar un backtesting completo y generar métricas clave como retorno, drawdown y ratio de Sharpe.
  5. Identifico y evito errores comunes como sobreajuste o falta de manejo de datos faltantes en mis simulaciones.
  6. Sé interpretar los resultados del backtesting para decidir si una estrategia es viable o necesita optimización.
  7. Puedo refactorizar código de backtesting para mejorar eficiencia, usando bibliotecas como backtrader o vectorbt.

Implementa y prueba una estrategia de cruce de medias móviles con backtesting en Binance

Sigue estos pasos para crear y evaluar una estrategia de trading algorítmico usando datos reales de Binance:

  1. Descarga datos históricos: Usa la biblioteca ccxt en Python para obtener velas de 1 hora del par ETH/USDT de los últimos 60 días. Guarda los datos en un DataFrame de pandas con columnas para timestamp, open, high, low, close y volume.
  2. Define la estrategia: Crea una clase en Python que implemente una estrategia de cruce de medias móviles. Usa una media rápida de 12 períodos y una media lenta de 26 períodos. La regla es comprar cuando la media rápida cruza por encima de la lenta, y vender cuando cruza por debajo.
  3. Configura el backtesting: Utiliza la biblioteca backtrader para simular las operaciones. Establece un capital inicial de $5000, añade una comisión del 0.1% (típica de Binance) y un slippage del 0.05%. Carga los datos descargados en el backtesting.
  4. Ejecuta y analiza: Corre la simulación y calcula métricas como el retorno total, máxima pérdida flotante (drawdown) y número de operaciones. Genera un gráfico de la evolución del capital y las señales de trading.
  5. Documenta resultados: Escribe un breve informe (en comentarios de código o un archivo de texto) explicando si la estrategia fue rentable, cuáles fueron sus puntos débiles y qué ajustes podrías hacer para mejorarla.
Pistas
  • Asegúrate de manejar los timestamps correctamente al descargar datos; usa exchange.parse8601() para convertir fechas a formato Unix.
  • En backtrader, recuerda que self.position te indica si tienes una posición abierta; ústalo para evitar operaciones duplicadas.
  • Para calcular el drawdown, backtrader ofrece indicadores como bt.analyzers.DrawDown; añádelo con cerebro.addanalyzer().

Evalua tu comprension

Completa el quiz interactivo de arriba para ganar XP.