# source: https://raw.githubusercontent.com/Vinylether/okx/71f225cd973d057f7b1f3c1a95c3ac5a6674df76/user_data/strategies/OkxFutures15mRegimeCombo.py
from datetime import datetime

from pandas import DataFrame

import talib.abstract as ta

from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy


class Github_Vinylether_okx__OkxFutures15mRegimeCombo__20260601_075127(IStrategy):
    INTERFACE_VERSION = 3

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

    minimal_roi = {"0": 0.50}
    stoploss = -0.070

    trailing_stop = False
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    order_types = {
        "entry": "limit",
        "exit": "limit",
        "stoploss": "market",
        "stoploss_on_exchange": False,
    }

    order_time_in_force = {
        "entry": "GTC",
        "exit": "GTC",
    }

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

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["ema96"] = ta.EMA(dataframe, timeperiod=96)
        dataframe["ema384"] = ta.EMA(dataframe, timeperiod=384)
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["roc16"] = ta.ROC(dataframe, timeperiod=16)
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
        dataframe["atr_pct"] = dataframe["atr"] / dataframe["close"]
        dataframe["volume_mean_48"] = dataframe["volume"].rolling(48).mean()
        dataframe["donchian_high_48"] = dataframe["high"].rolling(48).max().shift(1)
        mean_48 = dataframe["close"].rolling(48).mean()
        std_48 = dataframe["close"].rolling(48).std()
        dataframe["z48"] = (dataframe["close"] - mean_48) / std_48
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        liquid = (
            (dataframe["volume"] > 0)
            & (dataframe["volume"] > dataframe["volume_mean_48"] * 0.35)
        )
        tradable_vol = (dataframe["atr_pct"] > 0.001) & (dataframe["atr_pct"] < 0.04)

        long_breakout = (
            liquid
            & tradable_vol
            & (dataframe["close"] > dataframe["ema384"])
            & (dataframe["ema96"] > dataframe["ema384"])
            & (dataframe["close"] > dataframe["donchian_high_48"])
        )
        short_reversion = (
            liquid
            & tradable_vol
            & (dataframe["close"] < dataframe["ema384"])
            & (dataframe["close"] < dataframe["ema96"])
            & (dataframe["z48"] > 1.0)
            & (dataframe["roc16"] < 1.0)
            & (dataframe["rsi"] < dataframe["rsi"].shift(1))
        )

        dataframe.loc[long_breakout, ["enter_long", "enter_tag"]] = (1, "long_bo")
        dataframe.loc[short_reversion, ["enter_short", "enter_tag"]] = (1, "short_mr")
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe

    def custom_exit(
        self,
        pair: str,
        trade: Trade,
        current_time: datetime,
        current_rate: float,
        current_profit: float,
        **kwargs,
    ) -> str | bool | None:
        tag = trade.enter_tag or ""
        if "short_mr" in tag:
            if current_profit >= 0.025:
                return "short_mr_take_profit"
            if (current_time - trade.open_date_utc).total_seconds() >= 24 * 15 * 60:
                return "short_mr_time_exit"
            return None

        if current_profit >= 0.20:
            return "long_bo_take_profit"
        if (current_time - trade.open_date_utc).total_seconds() >= 960 * 60:
            return "long_bo_time_exit"
        return None
