Files
Trading-Bot/backtest.py
DaM 9b34de3127 feat: Backtesting engine completo + documentación (Semanas 3-4)
 Motor de backtesting:
- BacktestEngine con simulación de trades
- Sistema de Trade y Position
- Gestión de capital y comisiones
- Slippage simulado

 Estrategias implementadas:
- MovingAverageCrossover (SMA/EMA configurable)
- RSIStrategy (umbrales personalizables)
- BuyAndHold (baseline)

 Métricas de performance:
- Sharpe Ratio, Sortino Ratio, Calmar Ratio
- Max Drawdown, Win Rate, Profit Factor
- Expectancy, Risk/Reward Ratio

 Scripts:
- backtest.py: Ejecutar backtests individuales
- backtest.py compare: Comparar múltiples estrategias

 Documentación:
- README actualizado con sección de backtesting
- Ejemplos de uso programático
- Estructura de proyecto actualizada
2026-01-27 21:37:39 +01:00

210 lines
6.3 KiB
Python

# backtest.py
"""
Script principal para ejecutar backtests
"""
import os
from dotenv import load_dotenv
from pathlib import Path
from datetime import datetime, timedelta
from src.utils.logger import log
from src.data.storage import StorageManager
from src.backtest.engine import BacktestEngine
from src.backtest.metrics import print_backtest_report, calculate_all_metrics
from src.strategies import MovingAverageCrossover, BuyAndHold, RSIStrategy
def setup_environment():
"""Carga variables de entorno"""
env_path = Path(__file__).parent / 'config' / 'secrets.env'
load_dotenv(dotenv_path=env_path)
log.success("✓ Variables de entorno cargadas")
def run_backtest_demo():
"""
Demo de backtesting con estrategia simple
"""
log.info("="*70)
log.info("🧪 BACKTESTING - DEMO")
log.info("="*70)
# Setup
setup_environment()
# Configuración del backtest
symbol = 'BTC/USDT'
timeframe = '1h'
days_back = 60 # 2 meses de datos
log.info(f"\n📊 Configuración:")
log.info(f" Símbolo: {symbol}")
log.info(f" Timeframe: {timeframe}")
log.info(f" Periodo: {days_back} días")
# Conectar a base de datos
storage = StorageManager(
db_host=os.getenv('DB_HOST'),
db_port=int(os.getenv('DB_PORT', 5432)),
db_name=os.getenv('DB_NAME'),
db_user=os.getenv('DB_USER'),
db_password=os.getenv('DB_PASSWORD'),
)
# Cargar datos
log.info("\n📥 Cargando datos desde PostgreSQL...")
end_date = datetime.now()
start_date = end_date - timedelta(days=days_back)
data = storage.load_ohlcv(
symbol=symbol,
timeframe=timeframe,
start_date=start_date,
end_date=end_date,
use_cache=False
)
if data.empty:
log.error(f"❌ No hay datos disponibles para {symbol} {timeframe}")
log.info("💡 Ejecuta primero: python download_data.py")
return
log.success(f"✓ Datos cargados: {len(data)} velas")
log.info(f" Desde: {data.index[0]}")
log.info(f" Hasta: {data.index[-1]}")
# Crear estrategia
strategy = MovingAverageCrossover(
fast_period=10,
slow_period=30,
ma_type='sma'
)
# Crear motor de backtesting
engine = BacktestEngine(
strategy=strategy,
initial_capital=10000,
commission=0.001, # 0.1%
slippage=0.0005, # 0.05%
position_size=0.95 # Usar 95% del capital
)
# Ejecutar backtest
log.info("\n🚀 Ejecutando backtest...")
results = engine.run(data)
# Mostrar resultados
print_backtest_report(results)
# Calcular métricas adicionales
additional_metrics = calculate_all_metrics(results)
if additional_metrics:
print("\n📈 MÉTRICAS ADICIONALES:")
print(f" Sortino Ratio: {additional_metrics['sortino_ratio']:>12.2f}")
print(f" Calmar Ratio: {additional_metrics['calmar_ratio']:>12.2f}")
print(f" Expectancy: ${additional_metrics['expectancy']:>12,.2f}")
print(f" Risk/Reward: {additional_metrics['risk_reward_ratio']:>12.2f}")
print(f" Recovery Factor: {additional_metrics['recovery_factor']:>12.2f}")
# Mostrar algunos trades de ejemplo
if results['trades']:
print(f"\n📋 TRADES (primeros 5):")
for i, trade in enumerate(results['trades'][:5], 1):
print(f"\n Trade #{i}:")
print(f" Entrada: {trade.entry_time} @ ${trade.entry_price:.2f}")
print(f" Salida: {trade.exit_time} @ ${trade.exit_price:.2f}")
print(f" PnL: ${trade.pnl:>10.2f} ({trade.pnl_percentage:>6.2f}%)")
print(f" Duración: {trade.duration:.1f}h")
# Cleanup
storage.close()
log.info("\n" + "="*70)
log.success("✅ DEMO COMPLETADO")
log.info("="*70)
return results
def compare_strategies_demo():
"""
Compara múltiples estrategias sobre los mismos datos
"""
log.info("="*70)
log.info("🔍 COMPARACIÓN DE ESTRATEGIAS")
log.info("="*70)
setup_environment()
# Configuración
symbol = 'BTC/USDT'
timeframe = '1h'
days_back = 60
# Conectar a base de datos y cargar datos
storage = StorageManager(
db_host=os.getenv('DB_HOST'),
db_port=int(os.getenv('DB_PORT', 5432)),
db_name=os.getenv('DB_NAME'),
db_user=os.getenv('DB_USER'),
db_password=os.getenv('DB_PASSWORD'),
)
end_date = datetime.now()
start_date = end_date - timedelta(days=days_back)
data = storage.load_ohlcv(symbol, timeframe, start_date, end_date, use_cache=False)
if data.empty:
log.error(f"❌ No hay datos disponibles")
return
log.success(f"✓ Datos cargados: {len(data)} velas")
# Definir estrategias a comparar
strategies = [
('Buy & Hold', BuyAndHold()),
('MA Cross (10/30 SMA)', MovingAverageCrossover(10, 30, 'sma')),
('MA Cross (20/50 EMA)', MovingAverageCrossover(20, 50, 'ema')),
('RSI (30/70)', RSIStrategy(14, 30, 70)),
]
# Ejecutar backtest para cada estrategia
all_results = {}
for name, strategy in strategies:
log.info(f"\n🧪 Testeando: {name}")
engine = BacktestEngine(
strategy=strategy,
initial_capital=10000,
commission=0.001,
position_size=0.95
)
results = engine.run(data)
all_results[name] = results
log.info(f" Retorno: {results['total_return_pct']:.2f}%")
log.info(f" Trades: {results['total_trades']}")
log.info(f" Win Rate: {results['win_rate_pct']:.2f}%")
# Comparar resultados
from src.backtest.metrics import compare_strategies
compare_strategies(all_results)
storage.close()
log.success("✅ COMPARACIÓN COMPLETADA")
return all_results
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == 'compare':
# Modo comparación
compare_strategies_demo()
else:
# Modo demo simple
run_backtest_demo()
print("\n💡 TIP: Para comparar estrategias usa: python backtest.py compare")