# scripts/research/compare_stops.py import os import sys from pathlib import Path from dotenv import load_dotenv from datetime import datetime, timedelta import pandas as pd import matplotlib.pyplot as plt from loguru import logger # Añadir raíz del proyecto al path sys.path.insert(0, str(Path(__file__).parent.parent.parent)) from src.utils.logger import log from src.data.storage import StorageManager from src.core.engine import Engine from src.strategies import MovingAverageCrossover from src.risk.sizing.fixed import FixedPositionSizer from src.risk.stops.fixed_stop import FixedStop from src.risk.stops.trailing_stop import TrailingStop from src.risk.stops.atr_stop import ATRStop # -------------------------------------------------- # Configuración común # -------------------------------------------------- SYMBOL = "BTC/USDT" TIMEFRAME = "1d" DAYS_BACK = 180 INITIAL_CAPITAL = 10_000 COMISSION = 0.001 SLIPPAGE = 0.0005 # Estrategia STRATEGY = MovingAverageCrossover( fast_period=10, slow_period=30, ma_type='ema', use_adx=False, adx_threshold=20 ) # Position sizing fijo (para aislar el efecto del stop) POSITION_SIZER = FixedPositionSizer(0.95) # Stops a comparar STOPS = { "Fixed 2%": FixedStop(0.02), "Trailing 2%": TrailingStop(0.02), "ATR 14 x 2.0": ATRStop(atr_period=14, multiplier=2.0), } def setup_environment(): """Carga variables de entorno""" env_path = Path(__file__).parent.parent.parent / 'config' / 'secrets.env' load_dotenv(dotenv_path=env_path) def load_data(): """ Carga datos desde la base de datos """ # Setup setup_environment() # 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_BACK) data = storage.load_ohlcv( symbol=SYMBOL, timeframe=TIMEFRAME, start_date=None, end_date=None, use_cache=False, ) storage.close() if data.empty: raise RuntimeError("No se cargaron datos") return data def run(): log.info("=" * 80) log.info("🧪 COMPARACIÓN DE STOPS (Research)") log.info("=" * 80) data = load_data() log.info(f"Símbolo: {SYMBOL}") log.info(f"Timeframe: {TIMEFRAME}") log.info(f"Velas: {len(data)}") log.info(f"Periodo: {data.index[0]} → {data.index[-1]}") print() results = {} # -------------------------------------------------- # Ejecutar backtest por cada stop # -------------------------------------------------- for name, stop in STOPS.items(): log.info(f"▶️ Ejecutando con stop: {name}") # Silenciar logs del engine (solo warnings o errores) logger.disable("src.backtest.engine") engine = Engine( strategy=STRATEGY, initial_capital=INITIAL_CAPITAL, commission=COMISSION, slippage=SLIPPAGE, position_sizer=POSITION_SIZER, stop_loss=stop, ) res = engine.run(data) results[name] = res logger.enable("src.backtest.engine") log.info( f"Trades: {res['total_trades']:>4} | " f"Max DD: {res['max_drawdown_pct']:>7.2f}% | " f"Return: {res['total_return_pct']:>7.2f}%" ) print() print("\n" + "=" * 70) print("📊 RESUMEN COMPARATIVO DE STOPS") print("=" * 70) for name, res in results.items(): print( f"{name:<15} | " f"Trades: {res['total_trades']:>4} | " f"Max DD: {res['max_drawdown_pct']:>7.2f}% | " f"Return: {res['total_return_pct']:>7.2f}%" ) print("=" * 70) # -------------------------------------------------- # Plot equity curves (comparativa visual) # -------------------------------------------------- plt.figure(figsize=(14, 7)) for name, res in results.items(): plt.plot( res["timestamps"], res["equity_curve"], label=name, ) plt.title(f"Equity Curve Comparison – {SYMBOL} {TIMEFRAME}") plt.xlabel("Time") plt.ylabel("Equity") plt.legend() plt.grid(alpha=0.3) plt.tight_layout() # -------------------------------------------------- # Guardar gráfico # -------------------------------------------------- output_dir = Path(__file__).parent / "output" output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / f"equity_comparison_{SYMBOL.replace('/', '_')}_{TIMEFRAME}.png" plt.savefig(output_path, dpi=150) plt.close() log.success(f"📈 Equity curve guardada en: {output_path}") if __name__ == "__main__": run()