Files
Trading-Bot/backtest.py
DaM f85c522f22 feat: finalize portfolio system and quantitative validation- Finalized MA_Crossover(30,100) and TrendFiltered_MA(30,100,ADX=15)
- Implemented portfolio engine with risk-based allocation (50/50)
- Added equity-based metrics for system-level evaluation
- Validated portfolio against standalone strategies
- Reduced max drawdown and volatility at system level
- Quantitative decision closed before paper trading phase
2026-02-02 14:38:05 +01:00

209 lines
6.1 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.core.engine import Engine
from src.core.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'
log.info(f"\n📊 Configuración:")
log.info(f" Símbolo: {symbol}")
log.info(f" Timeframe: {timeframe}")
# 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 TODOS los datos desde PostgreSQL...")
data = storage.load_ohlcv(
symbol=symbol,
timeframe=timeframe,
start_date=None,
end_date=None,
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.min()}")
log.info(f" Hasta: {data.index.max()}")
log.info(f" Total días: {(data.index.max() - data.index.min()).days}")
# Crear estrategia
strategy = MovingAverageCrossover(
fast_period=10,
slow_period=30,
ma_type='sma'
)
# Crear motor de backtesting
engine = Engine(
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'
# 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'),
)
data = storage.load_ohlcv(
symbol=symbol,
timeframe=timeframe,
start_date=None,
end_date=None,
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 = Engine(
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.core.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")