#!/usr/bin/env python3
"""
Jan 2026 optimization sweep — find the best config for choppy markets.
Tests variations around the baseline to see what works in range-bound conditions.
"""
import sys, os, json, time, importlib, gc
from datetime import datetime

os.chdir(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ".")

try:
    os.nice(10)
except OSError:
    pass

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

PROGRESS_FILE = "backtest_progress.json"

def write_progress(data):
    tmp = PROGRESS_FILE + ".tmp"
    try:
        with open(tmp, "w") as f:
            json.dump(data, f, indent=2, default=str)
        os.replace(tmp, PROGRESS_FILE)
    except Exception:
        pass

def save_snapshot():
    keys = [
        "LOT_SIZE", "MAX_INITIAL_ORDERS", "ENTRY_TP_PIPS", "ENTRY_SL_PIPS",
        "RECOVERY_GRID_STEPS", "RECOVERY_TPS", "THREAD_PROFIT_TARGET",
        "RECOVERY_PROFIT_TARGET", "RECOVERY_LOT_MULTIPLIER",
        "_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,
            "lot": settings.LOT_SIZE,
            "mo": settings.MAX_INITIAL_ORDERS,
            "ttp": settings.THREAD_PROFIT_TARGET,
            "rpt": settings.RECOVERY_PROFIT_TARGET,
            "rlm": settings.RECOVERY_LOT_MULTIPLIER,
            "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)

    print("=" * 70)
    print("  JAN 2026 OPTIMIZATION SWEEP")
    print("  Finding best config for choppy/range markets")
    print("=" * 70)

    print("\nLoading Jan 2026 data...")
    data = load_ticks_to_candles("data/monthly/BTCUSD_202601.csv", timeframe="5min", max_rows=None)
    print(f"Loaded {len(data)} candles\n")

    variants = {
        # Baseline
        "BASELINE: L=0.02 TTP=$15 RTP=$30 MO=10": {
            "LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0,
            "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10,
        },
        # Lot size
        "L=0.01": {"LOT_SIZE": 0.01, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        "L=0.015": {"LOT_SIZE": 0.015, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        "L=0.03": {"LOT_SIZE": 0.03, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        # Thread TP
        "TTP=$10": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 10.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        "TTP=$12": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 12.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        "TTP=$20": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 20.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        "TTP=$25": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 25.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10},
        # Recovery TP
        "RTP=$15": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 15.0, "MAX_INITIAL_ORDERS": 10},
        "RTP=$20": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 20.0, "MAX_INITIAL_ORDERS": 10},
        "RTP=$40": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 40.0, "MAX_INITIAL_ORDERS": 10},
        "RTP=$50": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 50.0, "MAX_INITIAL_ORDERS": 10},
        # Max orders
        "MO=8": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 8},
        "MO=12": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 12},
        "MO=15": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 15},
        # Recovery lot multiplier
        "RLM=0.8": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10, "RECOVERY_LOT_MULTIPLIER": 0.8},
        "RLM=1.2": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10, "RECOVERY_LOT_MULTIPLIER": 1.2},
        "RLM=1.5": {"LOT_SIZE": 0.02, "_REF_THREAD_PROFIT_TARGET": 15.0, "RECOVERY_PROFIT_TARGET": 30.0, "MAX_INITIAL_ORDERS": 10, "RECOVERY_LOT_MULTIPLIER": 1.5},
    }

    results = []
    total = len(variants)
    for i, (name, ov) in enumerate(variants.items()):
        write_progress({"status": "running", "sweep": "jan_optimize", "variant": name,
                        "progress": f"{i+1}/{total}", "updated_at": datetime.now().isoformat()})
        print(f"  [{i+1}/{total}] {name}...", end=" ", flush=True)
        t0 = time.time()
        r = run_one(name, ov, data)
        elapsed = time.time() - t0
        results.append(r)
        print(f"${r['net']:>+10,.0f} ({r['pct']:>+.1f}%)  DD:{r['dd']:.1f}%  PF:{r['pf']:.2f}  RAR:{r['rar']:.1f}  [{elapsed:.0f}s]")
        time.sleep(0.3)

    results.sort(key=lambda x: x["rar"], reverse=True)

    print(f"\n{'=' * 140}")
    print(f"  JAN 2026 SWEEP — RANKED BY RAR")
    print(f"{'=' * 140}")
    print(f"{'#':>2} {'VARIANT':<45} {'Net $':>10} {'Return':>8} {'MaxDD%':>7} {'PF':>5} {'RAR':>7} "
          f"{'Trades':>7} {'Win%':>6} {'Comm$':>10}")
    print("-" * 140)
    for i, r in enumerate(results):
        marker = " <-- BEST" if i == 0 else ""
        print(f"{i+1:>2} {r['name']:<45} ${r['net']:>9,.0f} {r['pct']:>+7.1f}% {r['dd']:>6.1f}% "
              f"{r['pf']:>5.2f} {r['rar']:>7.1f} {r['trades']:>7,} {r['wr']:>5.1f}% "
              f"${r['comm']:>9,.0f}{marker}")

    winner = results[0]
    print(f"\nWINNER: {winner['name']}")
    print(f"  Net: ${winner['net']:,.0f} | DD: {winner['dd']:.1f}% | RAR: {winner['rar']:.1f}")

    # Save
    os.makedirs("results", exist_ok=True)
    with open(f"results/jan_sweep_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json", "w") as f:
        json.dump({"results": results, "winner": winner}, f, indent=2)

    write_progress({"status": "completed", "sweep": "jan_optimize", "winner": winner["name"],
                    "updated_at": datetime.now().isoformat()})

if __name__ == "__main__":
    main()
