"""
策略深度优化 — 成交量确认 + 时间止损 + 参数扫描

优化点 v3：
  1. 成交量确认：金叉当日成交量 > 前20根均量 × 1.3，过滤缩量假突破
  2. 时间止损：持仓超过48根K线自动平仓，避免死扛
  3. 参数扫描：对 EMA(fast, slow) 组合做网格搜索，每个币种找最优参数

用法：
    source .venv/bin/activate && python example/strategy_optimize2.py
"""

import asyncio
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

_project_root = Path(__file__).resolve().parent.parent.parent
if str(_project_root) not in sys.path:
    sys.path.insert(0, str(_project_root))

from engine.common.base import BaseStrategy, Signal, StrategyConfig
from engine.common.models import Kline
from engine.common.config import config
from engine.backtest import BacktestEngine, BacktestConfig, BacktestResult
from engine.indicators import ema, atr


# ════════════════════════════════════════════════════════
# EMA v3: 趋势 + ATR止损 + 时间止损 + 成交量确认
# ════════════════════════════════════════════════════════


class EmaV3Config(StrategyConfig):
    fast: int = 20
    slow: int = 50
    atr_period: int = 14
    atr_stop_mult: float = 3.0
    time_stop_bars: int = 48   # 时间止损（30m下48根=1天，4h下48根=8天）
    vol_factor: float = 1.3    # 成交量确认倍数


class EmaV3Strategy(BaseStrategy):
    """EMA v3: 金叉+放量买入，ATR止损+时间止损出场"""

    strategy_type = "ema_v3"

    def __init__(self, c: EmaV3Config):
        super().__init__(c)
        self.cfg = c
        self._closes: list[float] = []
        self._highs: list[float] = []
        self._lows: list[float] = []
        self._volumes: list[float] = []
        self._highest_since_entry: float = 0.0
        self._bars_held: int = 0
        self._in_position = False

    async def on_kline(self, k: Kline) -> Optional[Signal]:
        self._closes.append(k.close)
        self._highs.append(k.high)
        self._lows.append(k.low)
        self._volumes.append(k.volume)
        n = len(self._closes)
        if n < self.cfg.slow + 20:
            return None

        fast = ema(self._closes, self.cfg.fast)
        slow = ema(self._closes, self.cfg.slow)
        atr_vals = atr(self._highs, self._lows, self._closes, self.cfg.atr_period)
        cur_f, cur_s, cur_atr = fast[-1], slow[-1], atr_vals[-1]
        if cur_f == 0 or cur_s == 0 or cur_atr == 0:
            return None

        # 成交量确认：最近bar成交量 > 前20根均量 × factor
        avg_vol = sum(self._volumes[-21:-1]) / 20 if n > 21 else 0
        vol_confirmed = k.volume > avg_vol * self.cfg.vol_factor if avg_vol > 0 else True

        if self._in_position:
            self._bars_held += 1
            self._highest_since_entry = max(self._highest_since_entry, k.high)
            stop_price = self._highest_since_entry - self.cfg.atr_stop_mult * cur_atr
            death_cross = fast[-2] >= slow[-2] and cur_f < cur_s
            time_up = self._bars_held >= self.cfg.time_stop_bars

            if k.close < stop_price:
                self._in_position = False
                return Signal(symbol=self.cfg.symbol, side="SELL", reason=f"ATR止损", timestamp=k.open_time)
            if death_cross:
                self._in_position = False
                return Signal(symbol=self.cfg.symbol, side="SELL", reason=f"EMA死叉", timestamp=k.open_time)
            if time_up:
                self._in_position = False
                return Signal(symbol=self.cfg.symbol, side="SELL", reason=f"时间止损({self._bars_held}bar)", timestamp=k.open_time)

        if not self._in_position:
            golden = fast[-2] <= slow[-2] and cur_f > cur_s
            if golden and vol_confirmed:
                self._in_position = True
                self._entry_price = k.close
                self._highest_since_entry = k.close
                self._bars_held = 0
                return Signal(symbol=self.cfg.symbol, side="BUY",
                              reason=f"金叉+放量{'✓' if vol_confirmed else ''} V={k.volume:.0f}",
                              timestamp=k.open_time)

        return None


# ════════════════════════════════════════════════════════
# 参数扫描 + 对比
# ════════════════════════════════════════════════════════

SYMBOLS = ["BTCUSDT", "ETHUSDT", "BNBUSDT", "SOLUSDT"]

PARAM_GRID = [
    # (fast, slow)
    (10, 40), (10, 50), (10, 75),
    (20, 40), (20, 50), (20, 75),
    (30, 40), (30, 50), (30, 75),
]

# 原始 v1 基线
BASELINE = {
    "BTCUSDT":  (20, 50, 45.5, 0.74, -31.6),
    "ETHUSDT":  (20, 50, 24.4, 0.47, -54.8),
    "BNBUSDT":  (20, 50, 52.0, 0.71, -39.8),
    "SOLUSDT":  (20, 50, 27.8, 0.49, -39.5),
}


async def scan_one(symbol: str, fast: int, slow: int) -> dict:
    """单次参数扫描"""
    bt = BacktestConfig(
        symbol=symbol, interval="4h",
        start_time=datetime(2024, 1, 1), end_time=datetime(2026, 1, 1),
        initial_capital=10_000.0,
    )
    sc = EmaV3Config(symbol=symbol, fast=fast, slow=slow)
    engine = BacktestEngine(bt, db_config=config.db)
    r = await engine.run(EmaV3Strategy, sc)
    m = r.metrics
    return {"fast": fast, "slow": slow, "return": m.total_return_pct,
            "sharpe": m.sharpe_ratio, "dd": m.max_drawdown_pct,
            "trades": m.total_trades, "wr": m.win_rate}


async def main():
    print()
    print("═" * 105)
    print("  EMA v3 深度优化 — 成交量+时间止损+参数扫描 | 4h 周期 | 2024-2026")
    print("═" * 105)

    all_results: dict[str, list[dict]] = {}

    for symbol in SYMBOLS:
        print(f"\n  ▸ {symbol} 参数扫描 (9 组)...")
        symbol_results = []
        for fast, slow in PARAM_GRID:
            r = await scan_one(symbol, fast, slow)
            symbol_results.append(r)
            print(f"    EMA({fast},{slow})  收益={r['return']:>+6.1f}%  夏普={r['sharpe']:>6.2f}  回撤={r['dd']:>6.1f}%  交易={r['trades']:>3}  胜率={r['wr']*100:>5.1f}%")
        all_results[symbol] = symbol_results

    # ── 每个币种最佳参数 ──
    print("\n" + "═" * 105)
    print("  ■ 各币种最优参数:")
    print(f"  {'币种':<10} {'最优参数':<16} {'收益%':>7} {'夏普':>6} {'回撤%':>7} {'交易':>5} {'胜率%':>6}  vs 基线")
    print("─" * 105)

    best_params = {}
    for symbol in SYMBOLS:
        # 按夏普排序
        sorted_r = sorted(all_results[symbol], key=lambda x: x["sharpe"], reverse=True)
        best = sorted_r[0]
        best_params[symbol] = (best["fast"], best["slow"])
        base = BASELINE[symbol]
        delta = best["return"] - base[2]
        print(f"  {symbol:<10} EMA({best['fast']},{best['slow']}){'':>8} {best['return']:>6.1f}% {best['sharpe']:>6.2f} {best['dd']:>6.1f}% {best['trades']:>5} {best['wr']*100:>5.1f}%  Δ={delta:+.1f}%")

    # ── 汇总对比 ──
    print("\n" + "═" * 105)
    print("  ■ 三层对比：基线(v1) → 止损(v2) → 成交量+时间止损+最优参数(v3)")
    print(f"  {'币种':<10} {'版本':<20} {'收益%':>7} {'夏普':>6} {'回撤%':>7} {'交易':>5} {'胜率%':>6}")
    print("─" * 105)

    # v2 数据（从上次运行）
    V2 = {
        "BTCUSDT":  (20, 50, 7.0, 0.27, -27.8),
        "ETHUSDT":  (20, 50, 41.3, 0.76, -29.6),
        "BNBUSDT":  (20, 50, 43.6, 0.81, -26.1),
        "SOLUSDT":  (20, 50, 48.1, 0.70, -26.6),
    }

    for symbol in SYMBOLS:
        # 基线
        b = BASELINE[symbol]
        print(f"  {symbol:<10} {'v1 原始 EMA双均线':<20} {b[2]:>6.1f}% {b[3]:>6.2f} {b[4]:>6.1f}%")
        # v2
        v2 = V2[symbol]
        print(f"  {symbol:<10} {'v2 +ATR止损':<20} {v2[2]:>6.1f}% {v2[3]:>6.2f} {v2[4]:>6.1f}%")
        # v3 最佳
        best = [r for r in all_results[symbol] if r["fast"] == best_params[symbol][0] and r["slow"] == best_params[symbol][1]][0]
        print(f"  {symbol:<10} {'v3 全优化+最优参数':<20} {best['return']:>6.1f}% {best['sharpe']:>6.2f} {best['dd']:>6.1f}%")
        print()

    # ── 组合收益 ──
    print("─" * 105)
    print("  ■ 等权组合（4币种各投入2500 USDT）:")
    total_baseline = sum(BASELINE[s][2] for s in SYMBOLS) / 4 * 100
    total_v2 = sum(V2[s][2] for s in SYMBOLS) / 4 * 100
    total_v3 = sum(
        sorted(all_results[s], key=lambda x: x["sharpe"], reverse=True)[0]["return"]
        for s in SYMBOLS
    ) / 4 * 100
    print(f"    v1 基线组合:  {total_baseline:+.0f} USDT")
    print(f"    v2 止损组合:  {total_v2:+.0f} USDT")
    print(f"    v3 全优化组合: {total_v3:+.0f} USDT")

    print("\n═" * 105)
    print("  扫描完成。")
    print("═" * 105)


if __name__ == "__main__":
    asyncio.run(main())
