# scripts/research/portfolio_backtest.py

"""
Portfolio Backtest Script (50/50 Allocation)

Este script ejecuta un backtest de un portfolio multi-estrategia compuesto por:

- MA_Crossover (EMA 30 / EMA 100)
- TrendFiltered_MA (EMA 30 / EMA 100 + ADX 15)

Cada estrategia opera de forma independiente, pero comparte el riesgo total
mediante una asignación fija 50/50 (0.5% de riesgo por estrategia).

Objetivos principales del script:
- Validar el comportamiento conjunto del portfolio
- Evaluar la reducción de drawdown y volatilidad frente a estrategias individuales
- Calcular métricas de sistema basadas únicamente en la equity curve
  (CAGR, Max Drawdown, Calmar Ratio, Time in Drawdown, Ulcer Index)
- Generar una visualización de la equity del portfolio y su drawdown

Este script representa el último paso cuantitativo antes de:
- Walk-Forward del portfolio
- Paper trading en tiempo real
- Construcción de la UI de monitorización

No modifica parámetros, estrategias ni lógica de ejecución.
Su propósito es exclusivamente de validación y análisis del sistema.
"""

import os
import sys
from pathlib import Path
from dotenv import load_dotenv

import matplotlib.pyplot as plt
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,
    calculate_drawdown_series,
)


# --------------------------------------------------
# CONFIG
# --------------------------------------------------
SYMBOL = "ETH/USDT"
TIMEFRAME = "1h"
INITIAL_CAPITAL = 10_000

STOP = TrailingStop(0.02)

# 50/50 risk split
RISK_A = PercentRiskSizer(0.005)
RISK_B = PercentRiskSizer(0.005)

OUTPUT_DIR = Path(__file__).parent / "output/portfolio_backtest"
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)


# --------------------------------------------------
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():
    data = load_data()

    # -----------------------------
    # Engines
    # -----------------------------
    engines = {
        "MA_Crossover": Engine(
            strategy=MovingAverageCrossover(30, 100, "ema", False),
            initial_capital=INITIAL_CAPITAL,
            position_sizer=RISK_A,
            stop_loss=STOP,
            commission=0.001,
            slippage=0.0005,
        ),
        "TrendFiltered_MA": Engine(
            strategy=TrendFilteredMACrossover(30, 100, "ema", 15),
            initial_capital=INITIAL_CAPITAL,
            position_sizer=RISK_B,
            stop_loss=STOP,
            commission=0.001,
            slippage=0.0005,
        ),
    }

    allocation = Allocation(
        weights={
            "MA_Crossover": 0.5,
            "TrendFiltered_MA": 0.5,
        }
    )

    portfolio = PortfolioEngine(
        engines=engines,
        allocation=allocation,
        initial_capital=INITIAL_CAPITAL,
    )

    # -----------------------------
    # Run portfolio
    # -----------------------------
    result = portfolio.run(data)

    equity = pd.Series(result.equity_curve, index=pd.to_datetime(data.index[:len(result.equity_curve)]))

    # -----------------------------
    # Metrics
    # -----------------------------
    metrics = compute_equity_metrics(
        equity_curve=result.equity_curve,
        timestamps=equity.index.tolist(),
    )

    # -----------------------------
    # Report
    # -----------------------------
    print("\n" + "=" * 80)
    print("📊 PORTFOLIO BACKTEST REPORT (50/50)")
    print("=" * 80)
    print(f"Final Capital:        ${result.final_capital:,.2f}")
    print(f"CAGR:                 {metrics['cagr'] * 100:>8.2f}%")
    print(f"Max Drawdown:         {metrics['max_drawdown'] * 100:>8.2f}%")
    print(f"Calmar Ratio:         {metrics['calmar_ratio']:>8.2f}")
    print(f"Volatility (ann.):    {metrics['volatility'] * 100:>8.2f}%")
    print(f"Time in Drawdown:     {metrics['time_in_drawdown'] * 100:>8.2f}%")
    print(f"Ulcer Index:          {metrics['ulcer_index']:>8.2f}")
    print("=" * 80)

    # -----------------------------
    # Plots
    # -----------------------------
    dd_series = calculate_drawdown_series(equity)

    fig, (ax1, ax2) = plt.subplots(
        2, 1, figsize=(13, 7), sharex=True,
        gridspec_kw={"height_ratios": [3, 1]}
    )

    ax1.plot(equity.index, equity.values, label="Portfolio Equity")
    ax1.set_title("Portfolio Equity Curve (50/50)")
    ax1.set_ylabel("Capital")
    ax1.grid(alpha=0.3)
    ax1.legend()

    ax2.fill_between(dd_series.index, dd_series.values * 100, 0, color="red", alpha=0.3)
    ax2.set_ylabel("Drawdown (%)")
    ax2.set_xlabel("Time")
    ax2.grid(alpha=0.3)

    plt.tight_layout()
    path = OUTPUT_DIR / "portfolio_equity_drawdown.png"
    plt.savefig(path)
    plt.close()

    print(f"\n📈 Saved plot: {path}")


# --------------------------------------------------
if __name__ == "__main__":
    run()
