# source: https://raw.githubusercontent.com/DOUGLASGUEDESATRIA/OSIRIS_TRADE/fe3c09567f3798d1cad6d7a306fa4f6131d91e17/user_data/strategies/OsirisShort.py
"""
Github_DOUGLASGUEDESATRIA_OSIRIS_TRADE__OsirisShort__20260329_060843 — Short-Only Mean-Reversion on Overbought
======================================================
Only enters the FIRST short of each overbought episode.
SL/TP both intra-candle via native stoploss + minimal_roi.
"""

import logging
from pandas import DataFrame

from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy, IntParameter
import talib.abstract as ta

logger = logging.getLogger(__name__)


class Github_DOUGLASGUEDESATRIA_OSIRIS_TRADE__OsirisShort__20260329_060843(IStrategy):
    INTERFACE_VERSION = 3
    can_short = True
    timeframe = "5m"

    stoploss = -0.003   # 0.3% SL (intra-candle)
    minimal_roi = {"0": 0.005}  # 0.5% TP (intra-candle)

    trailing_stop = False
    use_custom_stoploss = False
    startup_candle_count = 50
    process_only_new_candles = True

    rsi_ob = IntParameter(60, 78, default=65, space="buy", optimize=True)
    max_hold = IntParameter(6, 24, default=10, space="sell", optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        bb = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
        dataframe["bb_upper"] = bb["upperband"]
        dataframe["bb_mid"] = bb["middleband"]
        dataframe["bb_lower"] = bb["lowerband"]
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        ob = int(self.rsi_ob.value)
        has_data = dataframe["rsi"].notna() & (dataframe["volume"] > 0)

        # Core signal: RSI overbought + at BB upper
        raw_signal = (
            has_data
            & (dataframe["rsi"] > ob)
            & (dataframe["close"] >= dataframe["bb_upper"])
        )

        # FRESH ENTRY FILTER: require RSI was BELOW threshold recently
        # This ensures we only catch the FIRST entry of each overbought episode
        # not repeated entries while RSI stays high (trend continuation)
        was_below = (dataframe["rsi"].shift(1) <= ob) | (dataframe["rsi"].shift(2) <= ob) | (dataframe["rsi"].shift(3) <= ob)

        fresh_signal = raw_signal & was_below

        dataframe.loc[fresh_signal, "enter_short"] = 1
        return dataframe

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

    def custom_exit(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
        if trade.open_date_utc:
            minutes = (current_time - trade.open_date_utc).total_seconds() / 60
            candles = minutes / 5
            if candles >= self.max_hold.value:
                return "timeout"
        return None

    def leverage(self, pair, current_time, current_rate, proposed_leverage,
                 max_leverage, entry_tag, side, **kwargs) -> float:
        return 1.0
