# scripts/research/compare_systems.py """ Comparación cuantitativa final entre: - MA_Crossover (standalone) - TrendFiltered_MA (standalone) - Portfolio 50/50 Este script cierra la decisión cuantitativa antes de pasar a paper trading. """ import os import sys from pathlib import Path from dotenv import load_dotenv import pandas as pd sys.path.insert(0, str(Path(__file__).parent.parent.parent)) from src.core.engine import Engine from src.data.storage import StorageManager from src.risk.sizing.percent_risk import PercentRiskSizer from src.risk.stops.trailing_stop import TrailingStop from src.strategies.moving_average import MovingAverageCrossover from src.strategies.trend_filtered import TrendFilteredMACrossover from src.portfolio.portfolio_engine import PortfolioEngine from src.portfolio.allocation import Allocation from src.metrics.equity_metrics import compute_equity_metrics # -------------------------------------------------- # CONFIG # -------------------------------------------------- SYMBOL = "BTC/USDT" TIMEFRAME = "1h" INITIAL_CAPITAL = 10_000 STOP = TrailingStop(0.02) # -------------------------------------------------- def load_data(): load_dotenv("config/secrets.env") 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, use_cache=True, ) storage.close() if data.empty: raise RuntimeError("No data loaded") return data def run_engine(engine: Engine, data) -> dict: res = engine.run(data) equity = res["equity_curve"] timestamps = res["timestamps"] metrics = compute_equity_metrics( equity_curve=equity, timestamps=timestamps, ) return { "final_capital": equity[-1], **metrics, } # -------------------------------------------------- def run(): data = load_data() systems = {} # -------------------------------------------------- # MA_Crossover standalone (1% risk) # -------------------------------------------------- systems["MA_Crossover"] = run_engine( Engine( strategy=MovingAverageCrossover(30, 100, "ema", False), initial_capital=INITIAL_CAPITAL, position_sizer=PercentRiskSizer(0.01), stop_loss=STOP, commission=0.001, slippage=0.0005, ), data, ) # -------------------------------------------------- # TrendFiltered_MA standalone (1% risk) # -------------------------------------------------- systems["TrendFiltered_MA"] = run_engine( Engine( strategy=TrendFilteredMACrossover(30, 100, "ema", 15), initial_capital=INITIAL_CAPITAL, position_sizer=PercentRiskSizer(0.01), stop_loss=STOP, commission=0.001, slippage=0.0005, ), data, ) # -------------------------------------------------- # Portfolio 50/50 (0.5% + 0.5%) # -------------------------------------------------- engines = { "MA_Crossover": Engine( strategy=MovingAverageCrossover(30, 100, "ema", False), initial_capital=INITIAL_CAPITAL, position_sizer=PercentRiskSizer(0.005), stop_loss=STOP, commission=0.001, slippage=0.0005, ), "TrendFiltered_MA": Engine( strategy=TrendFilteredMACrossover(30, 100, "ema", 15), initial_capital=INITIAL_CAPITAL, position_sizer=PercentRiskSizer(0.005), stop_loss=STOP, commission=0.001, slippage=0.0005, ), } portfolio = PortfolioEngine( engines=engines, allocation=Allocation( weights={ "MA_Crossover": 0.5, "TrendFiltered_MA": 0.5, } ), initial_capital=INITIAL_CAPITAL, ) portfolio_res = portfolio.run(data) systems["Portfolio_50_50"] = { "final_capital": portfolio_res.final_capital, **compute_equity_metrics( equity_curve=portfolio_res.equity_curve, timestamps=data.index[: len(portfolio_res.equity_curve)], ), } # -------------------------------------------------- # COMPARISON TABLE # -------------------------------------------------- df = pd.DataFrame(systems).T df["final_capital"] = df["final_capital"].round(2) df["cagr"] = (df["cagr"] * 100).round(2) df["max_drawdown"] = (df["max_drawdown"] * 100).round(2) df["volatility"] = (df["volatility"] * 100).round(2) df["time_in_drawdown"] = (df["time_in_drawdown"] * 100).round(2) df["calmar_ratio"] = df["calmar_ratio"].round(2) df["ulcer_index"] = df["ulcer_index"].round(2) print("\n" + "=" * 100) print("📊 SYSTEM COMPARISON (FINAL DECISION)") print("=" * 100) print(df) print("=" * 100) print("\n📌 Interpretación:") print("- El mejor sistema NO es el que tiene mayor capital final.") print("- Prioriza menor drawdown, mejor Calmar y menor Ulcer Index.") print("- Si el portfolio domina en riesgo/retorno → decisión cerrada.\n") # -------------------------------------------------- if __name__ == "__main__": run()