#!/usr/bin/env python3
"""
Focused sweep: find the sweet spot between BASELINE and AGG-3.

Key insight: AGG-3's power comes from bigger lots + higher thread exit,
NOT from tight TPs. So we keep baseline TPs and sweep lot size + thread exit.
"""

import sys, os
os.chdir(os.path.dirname(os.path.abspath(__file__)))

import settings
from run_btc_backtest import load_ticks_to_candles
from backtest import BacktestEngine
from utils import setup_logging
import importlib

CSV_PATH = "BTCUSD.csv"


VARIANTS = {
    # Baseline reference
    "BASE: 0.01 lot, 10thr, $1 exit": {},

    # Isolate thread exit (keep baseline lots + TPs)
    "A: 0.01 lot, 10thr, $3 exit": {
        "_REF_THREAD_PROFIT_TARGET": 3.0,
    },
    "B: 0.01 lot, 10thr, $5 exit": {
        "_REF_THREAD_PROFIT_TARGET": 5.0,
    },
    "C: 0.01 lot, 10thr, $10 exit": {
        "_REF_THREAD_PROFIT_TARGET": 10.0,
    },

    # Now add lot scaling with best thread exits
    "D: 0.02 lot, 10thr, $5 exit": {
        "LOT_SIZE": 0.02,
        "_REF_THREAD_PROFIT_TARGET": 5.0,
    },
    "E: 0.02 lot, 10thr, $10 exit": {
        "LOT_SIZE": 0.02,
        "_REF_THREAD_PROFIT_TARGET": 10.0,
    },
    "F: 0.02 lot, 12thr, $7 exit": {
        "LOT_SIZE": 0.02,
        "MAX_INITIAL_ORDERS": 12,
        "_REF_THREAD_PROFIT_TARGET": 7.0,
    },
    "G: 0.03 lot, 10thr, $10 exit (AGG-3 w/baseline TP)": {
        "LOT_SIZE": 0.03,
        "_REF_THREAD_PROFIT_TARGET": 10.0,
    },
    "H: 0.03 lot, 10thr, $15 exit": {
        "LOT_SIZE": 0.03,
        "_REF_THREAD_PROFIT_TARGET": 15.0,
    },
    "I: 0.02 lot, 10thr, $15 exit": {
        "LOT_SIZE": 0.02,
        "_REF_THREAD_PROFIT_TARGET": 15.0,
    },
}


def save_snapshot():
    keys = [
        "LOT_SIZE", "MAX_INITIAL_ORDERS", "ENTRY_TP_PIPS", "ENTRY_SL_PIPS",
        "RECOVERY_GRID_STEPS", "RECOVERY_TPS", "THREAD_PROFIT_TARGET",
        "_REF_ENTRY_TP_PIPS", "_REF_RECOVERY_TPS", "_REF_THREAD_PROFIT_TARGET",
    ]
    return {k: getattr(settings, k) for k in keys}


def restore(snap):
    for k, v in snap.items():
        setattr(settings, k, v)
    import hedge_recovery_engine
    importlib.reload(hedge_recovery_engine)


def apply_overrides(ov):
    for k, v in ov.items():
        setattr(settings, k, v)
    if any(k.startswith("_REF_") for k in ov):
        norm = settings._normalize_for_pair(settings.SYMBOL)
        settings.ENTRY_TP_PIPS = norm["entry_tp_pips"]
        settings.RECOVERY_GRID_STEPS = norm["grid_steps"]
        settings.RECOVERY_TPS = norm["recovery_tps"]
    if "_REF_THREAD_PROFIT_TARGET" in ov:
        settings.THREAD_PROFIT_TARGET = ov["_REF_THREAD_PROFIT_TARGET"]
    import hedge_recovery_engine
    importlib.reload(hedge_recovery_engine)


def run_one(name, ov, data):
    snap = save_snapshot()
    try:
        apply_overrides(ov)
        engine = BacktestEngine(
            symbol=settings.SYMBOL,
            initial_balance=settings.INITIAL_BALANCE,
            commission_percent=settings.COMMISSION_PERCENT,
            slippage_pips=settings.SLIPPAGE_PIPS,
        )
        r = engine.run(data, progress_callback=None)
        return {
            "name": name,
            "net": r.total_return,
            "pct": r.total_return_percent,
            "trades": r.total_trades,
            "wr": r.win_rate,
            "gp": r.gross_profit,
            "gl": r.gross_loss,
            "comm": r.total_commission,
            "pf": r.gross_profit / r.gross_loss if r.gross_loss > 0 else 999,
            "dd": r.max_drawdown_percent,
            "min_eq": r.min_equity,
            "max_rec": r.max_recovery_level,
            "lot": settings.LOT_SIZE,
            "mo": settings.MAX_INITIAL_ORDERS,
            "ttp": settings.THREAD_PROFIT_TARGET,
            # Risk-adjusted return: return / max_dd
            "rar": r.total_return_percent / r.max_drawdown_percent if r.max_drawdown_percent > 0 else 0,
        }
    finally:
        restore(snap)


def main():
    setup_logging(console=False, file=True)
    max_rows = None
    for arg in sys.argv[1:]:
        if arg.startswith("--max-rows="):
            max_rows = int(arg.split("=")[1])

    print("Loading data...")
    data = load_ticks_to_candles(CSV_PATH, timeframe="5min", max_rows=max_rows)
    print(f"\nRunning {len(VARIANTS)} variants on {len(data)} candles\n")

    results = []
    for i, (name, ov) in enumerate(VARIANTS.items()):
        print(f"[{i+1}/{len(VARIANTS)}] {name}...", end=" ", flush=True)
        r = run_one(name, ov, data)
        results.append(r)
        print(f"${r['net']:>+10,.0f} ({r['pct']:>+.1f}%)  DD:{r['dd']:.1f}%  PF:{r['pf']:.2f}  RAR:{r['rar']:.1f}")

    # Sort by risk-adjusted return
    results.sort(key=lambda x: x["rar"], reverse=True)

    print(f"\n{'=' * 140}")
    print(f"{'#':>2} {'VARIANT':<50} {'Net $':>10} {'Return':>8} {'MaxDD%':>7} {'PF':>5} {'RAR':>6} "
          f"{'Trades':>7} {'Win%':>6} {'MinEq':>10} {'Comm$':>10} {'Lot':>5} {'ThTP$':>6}")
    print("-" * 140)

    for i, r in enumerate(results):
        marker = " <-- BEST RAR" if i == 0 else ""
        print(f"{i+1:>2} {r['name']:<50} ${r['net']:>9,.0f} {r['pct']:>+7.1f}% {r['dd']:>6.1f}% "
              f"{r['pf']:>5.2f} {r['rar']:>6.1f} {r['trades']:>7,} {r['wr']:>5.1f}% "
              f"${r['min_eq']:>9,.0f} ${r['comm']:>9,.0f} {r['lot']:>5.3f} ${r['ttp']:>5.1f}{marker}")

    print(f"\n{'=' * 140}")
    print("RAR = Risk-Adjusted Return (return% / maxDD%). Higher = better risk/reward.")


if __name__ == "__main__":
    main()
