#!/usr/bin/env python3
"""回测 CLI。

用法:
    python scripts/run_backtest.py --strategy vol_breakout --days 120
    python scripts/run_backtest.py --strategy trend_grid --fee 0.0005 --days 90
"""
import argparse
import logging
import sys
from pathlib import Path

import pandas as pd

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from backtest.engine import BacktestEngine          # noqa: E402
from backtest.report import print_report            # noqa: E402
from scripts.download_data import filename          # noqa: E402

MAJORS = ["BTC/USDT:USDT", "ETH/USDT:USDT", "SOL/USDT:USDT", "BNB/USDT:USDT"]


def load(pair: str, timeframe: str) -> pd.DataFrame:
    path = filename(pair, timeframe)
    if not path.exists():
        sys.exit(f"缺少数据 {path}，先运行 scripts/download_data.py")
    return pd.read_csv(path)


def main() -> None:
    ap = argparse.ArgumentParser()
    ap.add_argument("--strategy", choices=["vol_breakout", "trend_grid"],
                    default="vol_breakout")
    ap.add_argument("--pairs", nargs="+", default=MAJORS)
    ap.add_argument("--timeframe", default="5m")
    ap.add_argument("--days", type=int, default=None, help="只用最近 N 天")
    ap.add_argument("--start", default=None, help="如 2026-01-01")
    ap.add_argument("--end", default=None, help="如 2026-05-01")
    ap.add_argument("--fee", type=float, default=0.00035)
    ap.add_argument("--wallet", type=float, default=1000.0)
    ap.add_argument("--leverage", type=float, default=2.0)
    ap.add_argument("--dual", action="store_true", help="网格多空双开（中性模式）")
    ap.add_argument("-v", "--verbose", action="store_true")
    args = ap.parse_args()

    logging.basicConfig(level=logging.DEBUG if args.verbose else logging.WARNING,
                        format="%(asctime)s %(levelname)s %(message)s")

    data = {p: load(p, args.timeframe) for p in args.pairs}
    if args.start or args.end:
        lo = pd.Timestamp(args.start, tz="UTC").timestamp() if args.start else 0
        hi = pd.Timestamp(args.end, tz="UTC").timestamp() if args.end else 2**62
        data = {p: df[(df["ts"] >= lo) & (df["ts"] < hi)].reset_index(drop=True)
                for p, df in data.items()}
    elif args.days:
        cutoff = max(df["ts"].max() for df in data.values()) - args.days * 86400
        data = {p: df[df["ts"] >= cutoff].reset_index(drop=True) for p, df in data.items()}

    btc_1d = None
    btc_1d_path = filename("BTC/USDT:USDT", "1d")
    if btc_1d_path.exists():
        btc_1d = pd.read_csv(btc_1d_path)
        cutoff_1d = min(df["ts"].min() for df in data.values()) - 250 * 86400
        btc_1d = btc_1d[btc_1d["ts"] >= cutoff_1d].reset_index(drop=True)
    else:
        print("⚠️ 缺少 BTC 1d 数据，200DMA 闸门将恒为 False（只会开空）")

    if args.strategy == "vol_breakout":
        from bot.strategies.volatility_breakout import (
            VolatilityBreakoutController as C,
            VolBreakoutParams as P,
        )
        controller = C(pairs=list(data.keys()), params=P(leverage=args.leverage))
    else:
        from bot.strategies.trend_grid import (
            TrendGridController as C,
            TrendGridParams as P,
        )
        controller = C(pairs=list(data.keys()),
                       params=P(leverage=args.leverage, dual=args.dual))

    engine = BacktestEngine(controller, data, btc_1d=btc_1d,
                            fee_rate=args.fee, wallet=args.wallet)
    engine.run()
    print_report(engine, title=f"{args.strategy} fee={args.fee} "
                 f"lev={args.leverage}x{' dual' if args.dual else ''} "
                 f"[{args.start or '始'}~{args.end or '终'}]")


if __name__ == "__main__":
    main()
