"""
高波动率均值回归策略（Grok 方案 #2）。

核心逻辑：整体波动率处于高位（ATR 显著高于历史均值）时，
价格触及布林带极端区域做反向均值回归，目标回到布林带中轨。

适合：高波动震荡市。避免单边强趋势。
参数未经 hyperopt 优化，dry-run 验证用。
"""

from datetime import datetime

import talib.abstract as ta
from pandas import DataFrame

from freqtrade.strategy import IStrategy


class HighVolMeanRev(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "5m"
    can_short = True

    # 高波动环境：止损给宽（约 2*ATR 量级），目标别太激进
    minimal_roi = {"0": 0.03, "30": 0.015, "120": 0.005}
    stoploss = -0.025

    # 均值回归不用强 trailing
    trailing_stop = False

    startup_candle_count = 60

    atr_period = 14
    atr_regime_period = 50
    bb_period = 20
    bb_std = 2.0
    rsi_period = 14

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=self.atr_period)
        dataframe["atr_mean"] = dataframe["atr"].rolling(self.atr_regime_period).mean()
        dataframe["atr_std"] = dataframe["atr"].rolling(self.atr_regime_period).std()
        dataframe["high_vol"] = (
            dataframe["atr"] > dataframe["atr_mean"] + 0.8 * dataframe["atr_std"]
        )

        upper, mid, lower = ta.BBANDS(
            dataframe["close"],
            timeperiod=self.bb_period,
            nbdevup=self.bb_std,
            nbdevdn=self.bb_std,
        )
        dataframe["bb_upper"] = upper
        dataframe["bb_mid"] = mid
        dataframe["bb_lower"] = lower

        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=self.rsi_period)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            dataframe["high_vol"]
            & (dataframe["close"] < dataframe["bb_lower"])
            & (dataframe["rsi"] < 35)
            & (dataframe["volume"] > 0),
            "enter_long",
        ] = 1

        dataframe.loc[
            dataframe["high_vol"]
            & (dataframe["close"] > dataframe["bb_upper"])
            & (dataframe["rsi"] > 65)
            & (dataframe["volume"] > 0),
            "enter_short",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # 回归到中轨即离场
        dataframe.loc[
            (dataframe["close"] >= dataframe["bb_mid"]) & (dataframe["volume"] > 0),
            "exit_long",
        ] = 1
        dataframe.loc[
            (dataframe["close"] <= dataframe["bb_mid"]) & (dataframe["volume"] > 0),
            "exit_short",
        ] = 1
        return dataframe

    def leverage(
        self,
        pair: str,
        current_time: datetime,
        current_rate: float,
        proposed_leverage: float,
        max_leverage: float,
        entry_tag: str | None,
        side: str,
        **kwargs,
    ) -> float:
        return 2.0
