"""
夏普比率专项优化 — 波动率自适应 + ADX过滤 + 分批止盈

优化手段（核心目标：提高收益/波动比）：
  1. 波动率自适应仓位 — ATR大→confidence小（少买），ATR小→confidence大（多买）
  2. ADX 趋势过滤 — ADX>20 才交易，避开震荡市的反复假突破
  3. 分批止盈 — RSI过热先出一半锁利，剩下一半ATR跟踪

对比：v1基线 / v3优化 / v4夏普优化

用法：
    source .venv/bin/activate && python example/strategy_optimize3.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, rsi as calc_rsi, adx


# ════════════════════════════════════════════════════════
# EMA v4: 波动率自适应 + ADX过滤 + 分批止盈
# ════════════════════════════════════════════════════════


class EmaV4Config(StrategyConfig):
    fast: int = 20
    slow: int = 50
    atr_period: int = 14
    atr_stop_mult: float = 3.0
    adx_period: int = 14
    adx_threshold: float = 20.0       # ADX 趋势阈值
    vol_base: float = 20.0            # ATR% 基准（周期数用于标准化）
    rsi_period: int = 14
    rsi_take_profit: float = 72.0     # 止盈 RSI 线
    partial_exit_pct: float = 0.5     # 分批止盈比例（0=不分批）


class EmaV4Strategy(BaseStrategy):
    """EMA v4: 以夏普比率为目标的全方位优化"""

    strategy_type = "ema_v4"

    def __init__(self, c: EmaV4Config):
        super().__init__(c)
        self.cfg = c
        self._closes: list[float] = []
        self._highs: list[float] = []
        self._lows: list[float] = []
        self._highest_since_entry: float = 0.0
        self._in_position = False
        self._partial_done = 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)
        n = len(self._closes)
        need = max(self.cfg.slow, self.cfg.adx_period * 2)
        if n < need + 5:
            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)
        adx_vals = adx(self._highs, self._lows, self._closes, self.cfg.adx_period)
        rsi_vals = calc_rsi(self._closes, self.cfg.rsi_period)

        cur_f, cur_s = fast[-1], slow[-1]
        cur_atr, cur_adx, cur_rsi = atr_vals[-1], adx_vals[-1], rsi_vals[-1]
        if cur_f == 0 or cur_s == 0 or cur_atr == 0 or cur_adx == 0 or cur_rsi == 0:
            return None

        # ── 波动率自适应仓位系数 ──
        # ATR/价格 = 当前波动率，波动率越高→仓位越小
        atr_pct = cur_atr / k.close if k.close > 0 else 0.02
        # 基准波动率约 2%，波动率翻倍时仓位减半
        vol_conf = min(1.0, max(0.2, 0.02 / max(atr_pct, 0.005)))
        # ADX 趋势强度加成：强趋势更有信心
        trend_bonus = min(1.3, max(0.7, cur_adx / 25))
        position_conf = min(1.0, vol_conf * trend_bonus)

        # ADX 趋势过滤
        in_trend = cur_adx > self.cfg.adx_threshold

        # ── 出场 ──
        if self._in_position:
            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

            # ATR 止损
            if k.close < stop_price:
                self._in_position = False
                return Signal(symbol=self.cfg.symbol, side="SELL",
                              confidence=1.0,
                              reason=f"ATR止损 P={k.close:.0f}", timestamp=k.open_time)

            # EMA 死叉
            if death_cross:
                self._in_position = False
                return Signal(symbol=self.cfg.symbol, side="SELL",
                              confidence=1.0,
                              reason="EMA死叉", timestamp=k.open_time)

            # 分批止盈：RSI过热先出一半
            if not self._partial_done and cur_rsi > self.cfg.rsi_take_profit and self.cfg.partial_exit_pct > 0:
                self._partial_done = True
                return Signal(symbol=self.cfg.symbol, side="SELL",
                              quantity=None,  # None=全部，但我们用confidence控制比例
                              confidence=self.cfg.partial_exit_pct,
                              reason=f"半仓止盈 RSI={cur_rsi:.0f}", timestamp=k.open_time)

        # ── 入场 ──
        if not self._in_position:
            golden = fast[-2] <= slow[-2] and cur_f > cur_s
            if golden and in_trend:
                self._in_position = True
                self._highest_since_entry = k.close
                self._partial_done = False
                return Signal(
                    symbol=self.cfg.symbol, side="BUY",
                    confidence=position_conf,
                    reason=f"金叉 ADX={cur_adx:.0f} vol_conf={vol_conf:.2f}",
                    timestamp=k.open_time,
                )

        return None


# ════════════════════════════════════════════════════════
# 对比运行
# ════════════════════════════════════════════════════════

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

# 各币种最优参数（来自 v3 扫描）
BEST_PARAMS = {
    "BTCUSDT":  (10, 50),
    "ETHUSDT":  (10, 75),
    "BNBUSDT":  (10, 40),
    "SOLUSDT":  (30, 50),
}

# v1 基线
V1 = {
    "BTCUSDT":  (45.5, 0.74, -31.6, 42, 26.2),
    "ETHUSDT":  (24.4, 0.47, -54.8, 41, 24.4),
    "BNBUSDT":  (52.0, 0.71, -39.8, 41, 39.0),
    "SOLUSDT":  (27.8, 0.49, -39.5, 45, 40.0),
}

# v3 最优参数结果
V3 = {
    "BTCUSDT":  (39.9, 1.03, -11.5, 20, 55.0),
    "ETHUSDT":  (53.6, 1.04, -15.3, 18, 38.9),
    "BNBUSDT":  (26.0, 0.64, -23.4, 23, 34.8),
    "SOLUSDT":  (73.6, 1.18, -25.7, 13, 46.2),
}


async def run_v4(symbol: str, fast: int, slow: int) -> BacktestResult:
    bt = BacktestConfig(
        symbol=symbol, interval="4h",
        start_time=datetime(2024, 1, 1), end_time=datetime(2026, 1, 1),
        initial_capital=10_000.0,
    )
    sc = EmaV4Config(symbol=symbol, fast=fast, slow=slow)
    engine = BacktestEngine(bt, db_config=config.db)
    return await engine.run(EmaV4Strategy, sc)


async def main():
    print()
    print("═" * 120)
    print("  夏普比率专项优化 — 波动率自适应 + ADX过滤 + 分批止盈")
    print("═" * 120)

    # ── 扫描 partial_exit_pct 参数 ──
    print("\n  ▸ 分批止盈参数扫描 (SOLUSDT 为例)")
    print(f"  {'partial%':>10} {'收益%':>8} {'夏普':>6} {'回撤%':>8} {'交易':>5} {'胜率%':>6}")
    print("  " + "─" * 50)
    for pct in [0.0, 0.3, 0.5, 0.7]:
        bt = BacktestConfig(symbol="SOLUSDT", interval="4h",
                            start_time=datetime(2024, 1, 1), end_time=datetime(2026, 1, 1),
                            initial_capital=10_000.0)
        sc = EmaV4Config(symbol="SOLUSDT", fast=30, slow=50, partial_exit_pct=pct)
        engine = BacktestEngine(bt, db_config=config.db)
        r = await engine.run(EmaV4Strategy, sc)
        m = r.metrics
        print(f"  {pct:>10.0%} {m.total_return_pct:>7.1f}% {m.sharpe_ratio:>6.2f} {m.max_drawdown_pct:>7.1f}% {m.total_trades:>5} {m.win_rate*100:>5.1f}%")

    # ── 全部币种 v4 运行 ──
    print("\n" + "═" * 120)
    print("  ■ v1 → v3 → v4 夏普进化 | 使用各币种最优参数")
    print(f"  {'币种':<10} {'版本':<18} {'收益%':>7} {'夏普':>6} {'Δ夏普':>7} {'回撤%':>7} {'交易':>5} {'胜率%':>6}")
    print("─" * 120)

    v4_results = {}
    for symbol in SYMBOLS:
        fast, slow = BEST_PARAMS[symbol]
        r = await run_v4(symbol, fast, slow)
        v4_results[symbol] = r

        v1 = V1[symbol]
        v3 = V3[symbol]
        m = r.metrics

        # v1
        print(f"  {symbol:<10} {'v1 原始':<18} {v1[0]:>6.1f}% {v1[1]:>6.2f} {'—':>7} {v1[2]:>6.1f}% {v1[3]:>5} {v1[4]:>5.1f}%")
        # v3
        print(f"  {symbol:<10} {'v3 最优参数':<18} {v3[0]:>6.1f}% {v3[1]:>6.2f} {v3[1]-v1[1]:>+6.2f} {v3[2]:>6.1f}%")
        # v4
        delta_sh = m.sharpe_ratio - v1[1]
        print(f"  {symbol:<10} {'v4 夏普优化':<18} {m.total_return_pct:>6.1f}% {m.sharpe_ratio:>6.2f} {delta_sh:>+6.2f} {m.max_drawdown_pct:>6.1f}% {m.total_trades:>5} {m.win_rate*100:>5.1f}%")
        print()

    # ── 夏普改善汇总 ──
    print("─" * 120)
    print("  ■ 夏普比率改善汇总:")
    for symbol in SYMBOLS:
        v1_sh = V1[symbol][1]
        v3_sh = V3[symbol][1]
        v4_sh = v4_results[symbol].metrics.sharpe_ratio
        print(f"    {symbol}:  v1={v1_sh:.2f}  →  v3={v3_sh:.2f}  →  v4={v4_sh:.2f}  (总提升 {v4_sh-v1_sh:+.2f})")

    # 平均夏普
    avg_v1 = sum(V1[s][1] for s in SYMBOLS) / 4
    avg_v3 = sum(V3[s][1] for s in SYMBOLS) / 4
    avg_v4 = sum(v4_results[s].metrics.sharpe_ratio for s in SYMBOLS) / 4
    print(f"    平均:    v1={avg_v1:.2f}  →  v3={avg_v3:.2f}  →  v4={avg_v4:.2f}  (总提升 {avg_v4-avg_v1:+.2f})")

    print("\n═" * 120)


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