# source: https://raw.githubusercontent.com/LoLoSenPai/freqtrade-hl-bot/11a5d3238922a0376470e2096cb27b52c83df4e6/user_data/strategies/TrendRegimeV1.py
from datetime import datetime

from pandas import DataFrame
import talib.abstract as ta

from freqtrade.strategy import DecimalParameter, IStrategy, IntParameter, informative


class Github_LoLoSenPai_freqtrade_hl_bot__TrendRegimeV1__20260510_172513(IStrategy):
    """Simple 15m trend-regime strategy for Hyperliquid futures dry-run testing."""

    INTERFACE_VERSION = 3

    can_short = True
    timeframe = "15m"
    startup_candle_count = 250
    process_only_new_candles = True

    position_adjustment_enable = False
    max_entry_position_adjustment = 0

    minimal_roi = {
        "0": 0.04,
        "120": 0.02,
        "240": 0.0,
    }

    stoploss = -0.06
    trailing_stop = True
    trailing_stop_positive = 0.015
    trailing_stop_positive_offset = 0.03
    trailing_only_offset_is_reached = True

    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    rsi_long_min = IntParameter(35, 55, default=45, space="buy", optimize=False)
    rsi_long_max = IntParameter(60, 78, default=68, space="buy", optimize=False)
    rsi_short_min = IntParameter(22, 40, default=32, space="buy", optimize=False)
    rsi_short_max = IntParameter(45, 65, default=55, space="buy", optimize=False)
    adx_min = IntParameter(18, 35, default=22, space="buy", optimize=False)
    volume_min_factor = DecimalParameter(0.2, 1.2, default=0.5, decimals=2, space="buy", optimize=False)
    rsi_long_exit = IntParameter(72, 88, default=78, space="sell", optimize=False)
    rsi_short_exit = IntParameter(12, 28, default=22, space="sell", optimize=False)

    @property
    def protections(self) -> list[dict]:
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 2,
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 48,
                "trade_limit": 3,
                "stop_duration_candles": 12,
                "required_profit": 0.0,
                "only_per_pair": False,
                "only_per_side": False,
            },
            {
                "method": "MaxDrawdown",
                "calculation_mode": "equity",
                "lookback_period_candles": 96,
                "trade_limit": 10,
                "stop_duration_candles": 24,
                "max_allowed_drawdown": 0.12,
            },
        ]

    @informative("1h")
    def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)
        dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
        return dataframe

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema_50"] = ta.EMA(dataframe, timeperiod=50)
        dataframe["ema_200"] = ta.EMA(dataframe, timeperiod=200)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
        dataframe["volume_mean_20"] = dataframe["volume"].rolling(20, min_periods=20).mean()
        dataframe["ema_50_slope"] = dataframe["ema_50"] - dataframe["ema_50"].shift(3)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        volume_ok = (
            (dataframe["volume"] > 0)
            & (dataframe["volume_mean_20"] > 0)
            & (dataframe["volume"] >= dataframe["volume_mean_20"] * self.volume_min_factor.value)
        )

        long_reclaim_ema50 = (
            (dataframe["close"] > dataframe["ema_50"])
            & (
                (dataframe["close"].shift(1) <= dataframe["ema_50"].shift(1))
                | ((dataframe["low"] <= dataframe["ema_50"]) & (dataframe["close"] > dataframe["open"]))
            )
        )

        short_reject_ema50 = (
            (dataframe["close"] < dataframe["ema_50"])
            & (
                (dataframe["close"].shift(1) >= dataframe["ema_50"].shift(1))
                | ((dataframe["high"] >= dataframe["ema_50"]) & (dataframe["close"] < dataframe["open"]))
            )
        )

        long_conditions = (
            volume_ok
            & (dataframe["close"] > dataframe["ema_200"])
            & (dataframe["ema_50"] > dataframe["ema_200"])
            & (dataframe["ema_50_slope"] > 0)
            & (dataframe["close_1h"] > dataframe["ema_200_1h"])
            & (dataframe["ema_50_1h"] > dataframe["ema_200_1h"])
            & (dataframe["adx"] > self.adx_min.value)
            & (dataframe["adx_1h"] > self.adx_min.value)
            & (dataframe["rsi"] > self.rsi_long_min.value)
            & (dataframe["rsi"] < self.rsi_long_max.value)
            & long_reclaim_ema50
        )

        short_conditions = (
            volume_ok
            & (dataframe["close"] < dataframe["ema_200"])
            & (dataframe["ema_50"] < dataframe["ema_200"])
            & (dataframe["ema_50_slope"] < 0)
            & (dataframe["close_1h"] < dataframe["ema_200_1h"])
            & (dataframe["ema_50_1h"] < dataframe["ema_200_1h"])
            & (dataframe["adx"] > self.adx_min.value)
            & (dataframe["adx_1h"] > self.adx_min.value)
            & (dataframe["rsi"] > self.rsi_short_min.value)
            & (dataframe["rsi"] < self.rsi_short_max.value)
            & short_reject_ema50
        )

        dataframe.loc[long_conditions, ["enter_long", "enter_tag"]] = (1, "long_trend_pullback")
        dataframe.loc[short_conditions, ["enter_short", "enter_tag"]] = (1, "short_trend_pullback")
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        exit_long_ema50 = (dataframe["volume"] > 0) & (dataframe["close"] < dataframe["ema_50"])
        exit_long_regime = (dataframe["volume"] > 0) & (dataframe["ema_50"] < dataframe["ema_200"])
        exit_long_rsi = (dataframe["volume"] > 0) & (dataframe["rsi"] > self.rsi_long_exit.value)

        exit_short_ema50 = (dataframe["volume"] > 0) & (dataframe["close"] > dataframe["ema_50"])
        exit_short_regime = (dataframe["volume"] > 0) & (dataframe["ema_50"] > dataframe["ema_200"])
        exit_short_rsi = (dataframe["volume"] > 0) & (dataframe["rsi"] < self.rsi_short_exit.value)

        dataframe.loc[exit_long_ema50, ["exit_long", "exit_tag"]] = (1, "ema50_break")
        dataframe.loc[exit_long_regime, ["exit_long", "exit_tag"]] = (1, "regime_lost")
        dataframe.loc[exit_long_rsi, ["exit_long", "exit_tag"]] = (1, "rsi_extreme")

        dataframe.loc[exit_short_ema50, ["exit_short", "exit_tag"]] = (1, "ema50_break")
        dataframe.loc[exit_short_regime, ["exit_short", "exit_tag"]] = (1, "regime_lost")
        dataframe.loc[exit_short_rsi, ["exit_short", "exit_tag"]] = (1, "rsi_extreme")
        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 1.0
