10 KiB
🧪 Backtesting Engine - Guía de Uso
📋 Descripción
El motor de backtesting permite simular estrategias de trading sobre datos históricos para evaluar su performance antes de arriesgar capital real.
🚀 Uso Rápido
Demo Simple
python backtest.py
Esto ejecuta un backtest con:
- Estrategia: Moving Average Crossover (10/30)
- Símbolo: BTC/USDT
- Periodo: 60 días
- Capital inicial: $10,000
Comparar Estrategias
python backtest.py compare
Compara 4 estrategias diferentes sobre los mismos datos.
📊 Estrategias Disponibles
1. Moving Average Crossover
Cruces de medias móviles:
from src.strategies import MovingAverageCrossover
strategy = MovingAverageCrossover(
fast_period=10, # Periodo media rápida
slow_period=30, # Periodo media lenta
ma_type='sma' # 'sma' o 'ema'
)
Señales:
- BUY: Media rápida cruza por encima de media lenta
- SELL: Media rápida cruza por debajo de media lenta
2. RSI Strategy
Basada en niveles de RSI:
from src.strategies import RSIStrategy
strategy = RSIStrategy(
rsi_period=14, # Periodo del RSI
oversold_threshold=30, # Umbral de sobreventa
overbought_threshold=70 # Umbral de sobrecompra
)
Señales:
- BUY: RSI < 30 (sobrevendido)
- SELL: RSI > 70 (sobrecomprado)
3. Buy and Hold
Estrategia base para comparación:
from src.strategies import BuyAndHold
strategy = BuyAndHold()
Compra al inicio y mantiene hasta el final.
🛠️ Uso Programático
Backtest Básico
from src.data.storage import StorageManager
from src.backtest import BacktestEngine
from src.strategies import MovingAverageCrossover
# Cargar datos
storage = StorageManager(...)
data = storage.load_ohlcv('BTC/USDT', '1h')
# Crear estrategia
strategy = MovingAverageCrossover(fast_period=10, slow_period=30)
# Crear motor de backtesting
engine = BacktestEngine(
strategy=strategy,
initial_capital=10000,
commission=0.001, # 0.1% por trade
slippage=0.0005, # 0.05% de slippage
position_size=0.95 # Usar 95% del capital
)
# Ejecutar
results = engine.run(data)
# Ver resultados
from src.backtest.metrics import print_backtest_report
print_backtest_report(results)
Crear Tu Propia Estrategia
from src.backtest.strategy import Strategy, Signal
import pandas as pd
class MiEstrategia(Strategy):
def __init__(self):
super().__init__(name="Mi Estrategia", params={})
def init_indicators(self, data: pd.DataFrame) -> pd.DataFrame:
"""
Calcula tus indicadores aquí
"""
# Ejemplo: añadir SMA
data['sma_20'] = data['close'].rolling(20).mean()
return data
def generate_signal(self, idx: int) -> Signal:
"""
Lógica de tu estrategia
"""
current_price = self.data.iloc[idx]['close']
sma = self.data.iloc[idx]['sma_20']
# Ejemplo: comprar si precio > SMA
if current_price > sma and self.current_position == 0:
return Signal.BUY
# Vender si precio < SMA y tenemos posición
elif current_price < sma and self.current_position > 0:
return Signal.SELL
return Signal.HOLD
# Usar tu estrategia
strategy = MiEstrategia()
engine = BacktestEngine(strategy, initial_capital=10000)
results = engine.run(data)
📈 Métricas Disponibles
Básicas
- Total Return: Retorno total del periodo
- Total Trades: Número de trades ejecutados
- Win Rate: Porcentaje de trades ganadores
- Profit Factor: Ganancia bruta / Pérdida bruta
Avanzadas
- Sharpe Ratio: Retorno ajustado por riesgo
- Sortino Ratio: Como Sharpe pero solo penaliza volatilidad a la baja
- Max Drawdown: Máxima caída desde un pico
- Calmar Ratio: Retorno anualizado / Max Drawdown
- Expectancy: Ganancia esperada por trade
- Recovery Factor: Net Profit / Max Drawdown
🎯 Estructura de Resultados
results = {
# Capital
'initial_capital': 10000,
'final_equity': 12500,
'total_return': 0.25,
'total_return_pct': 25.0,
'total_pnl': 2500,
# Trades
'total_trades': 15,
'winning_trades': 9,
'losing_trades': 6,
'win_rate': 0.6,
'win_rate_pct': 60.0,
# Performance
'gross_profit': 3000,
'gross_loss': 500,
'profit_factor': 6.0,
'avg_trade': 166.67,
'avg_win': 333.33,
'avg_loss': -83.33,
# Riesgo
'max_drawdown': -0.15,
'max_drawdown_pct': -15.0,
'sharpe_ratio': 1.8,
# Para análisis
'equity_curve': [...],
'timestamps': [...],
'trades': [Trade(...), Trade(...), ...]
}
💡 Mejores Prácticas
1. Periodo de Backtest
- Mínimo: 1 año de datos
- Recomendado: 3-5 años
- Ideal: Múltiples ciclos de mercado
2. Comisiones y Slippage
- Siempre incluir comisiones realistas
- Incluir slippage (0.05% - 0.1%)
- No optimizar en exceso (overfitting)
3. Position Sizing
- No usar 100% del capital por trade
- Recomendado: 50-95% del capital disponible
- Considerar gestión de riesgo
4. Validación
- In-sample: Periodo de entrenamiento/optimización
- Out-of-sample: Periodo de validación (datos no vistos)
- Walk-forward: Validación continua
5. Métricas Importantes
- No solo mirar retorno total
- Sharpe Ratio > 1.0 es bueno, > 2.0 es excelente
- Max Drawdown < 20% es aceptable
- Win Rate: >50% es bueno, pero no es lo único importante
- Profit Factor > 1.5 es bueno, > 2.0 es excelente
⚠️ Advertencias
Limitaciones del Backtesting
- Look-ahead bias: No usar información futura
- Survivorship bias: Incluir activos que ya no existen
- Overfitting: Optimizar demasiado para datos históricos
- Market conditions: Pasado no garantiza futuro
- Ejecución perfecta: Backtesting asume ejecución instantánea
Realismo
El backtest asume:
- ✅ Comisiones y slippage incluidos
- ✅ No hay look-ahead bias
- ❌ Liquidez infinita (órdenes siempre se ejecutan)
- ❌ No considera impacto de mercado
- ❌ No simula rechazo de órdenes
📊 Ejemplos de Resultados
Estrategia Exitosa
Retorno Total: 45.2%
Sharpe Ratio: 2.1
Max Drawdown: -12.3%
Win Rate: 58%
Profit Factor: 2.4
Estrategia Problemática
Retorno Total: 15.2%
Sharpe Ratio: 0.4
Max Drawdown: -35.8%
Win Rate: 45%
Profit Factor: 1.1
🔁 Walk-Forward Validation (Out-of-Sample)
📌 ¿Qué es Walk-Forward Validation?
El walk-forward validation es una técnica avanzada de validación que simula cómo se comportaría una estrategia en condiciones reales:
- Los parámetros se optimizan solo en datos pasados (TRAIN)
- La estrategia se ejecuta en datos futuros no vistos (TEST)
- El proceso se repite de forma deslizante a lo largo del tiempo
Esto evita:
- Look-ahead bias
- Overfitting clásico
- Optimismo artificial en backtests
Es el estándar en quant research profesional.
🧠 Metodología aplicada en este proyecto
Para cada ventana temporal:
-
TRAIN
- Periodo fijo de entrenamiento
- Optimización por grid search
- Selección de parámetros según métrica objetivo (Sharpe Ratio)
-
TEST (Out-of-Sample)
- Backtest con los mejores parámetros del TRAIN
- Sin reoptimización
- Métricas registradas de forma independiente
-
Desplazamiento
- La ventana avanza en el tiempo
- Se repite el proceso hasta agotar los datos
⏱️ Configuración utilizada
- Activo: BTC/USDT
- Timeframe: 1h
- Ventana TRAIN: 365 días
- Ventana TEST: 90 días
- Step: 90 días
- Capital inicial: $10,000
- Comisión: 0.1%
- Slippage: 0.05%
Estrategia base:
- Moving Average Crossover
- Filtro de tendencia con ADX
📊 Resultados por ventana (TEST – Out-of-Sample)
| Window | Return % | Sharpe | Max DD % | Trades | Parámetros |
|---|---|---|---|---|---|
| 1 | +38.00 | 0.75 | -11.93 | 3 | MA(15/50) + ADX 25 |
| 2 | +3.62 | 0.10 | -23.67 | 2 | MA(15/50) + ADX 30 |
| 3 | +8.54 | 0.22 | -10.28 | 2 | MA(15/50) + ADX 30 |
| 4 | 0.00 | 0.00 | 0.00 | 0 | Sin trades |
| 5 | +9.71 | 0.26 | -10.57 | 2 | MA(15/50) + ADX 30 |
| 6 | 0.00 | 0.00 | 0.00 | 0 | Sin trades |
| 7 | -2.25 | -0.06 | -12.42 | 2 | MA(15/50) + ADX 30 |
| 8 | -2.27 | -0.13 | -5.46 | 2 | MA(15/30) + ADX 30 |
📈 Métricas agregadas (Out-of-Sample)
- Ventanas evaluadas: 8
- Retorno medio: +6.92%
- Sharpe medio: 0.14
- Max Drawdown medio: -9.29%
🧩 Interpretación de resultados
- La estrategia no es sobreoptimizada
- Existen ventanas sin operaciones → el sistema sabe no operar
- Las pérdidas están controladas
- No hay colapsos en mercados adversos
- El rendimiento depende claramente del régimen de mercado
Este comportamiento es consistente con una estrategia:
- Tendencial
- Conservadora
- Apta para mejoras vía position sizing y portfolio diversification
✅ Decisiones tomadas tras Walk-Forward
- NO modificar la lógica de entrada
- NO optimizar más los parámetros base
- Mantener el filtro ADX como componente estructural
- Avanzar hacia mejoras de:
- Position sizing
- Stops dinámicos
- Portfolio multi-asset
El walk-forward valida que la señal base es estable y explotable, aunque no espectacular por sí sola.
🔄 Próximos Pasos
Después del backtesting:
- ✅ Si resultados son buenos → Paper trading
- ✅ Validar en out-of-sample
- ✅ Optimizar parámetros (con cuidado)
- ✅ Añadir gestión de riesgo
- ✅ Testear en diferentes condiciones de mercado
📝 Notas
- Siempre testea en datos out-of-sample
- Un buen backtest no garantiza éxito futuro
- Considera paper trading antes de dinero real
- Mantén expectativas realistas
- El mercado puede cambiar
Para dudas o problemas, consulta el README principal del proyecto.