# source: https://raw.githubusercontent.com/surendra2304/Stratex/edabb3c0f76ae012298616b8b6977e9f4c6f954b/stratex_freqtrade_adapter/strategy/builtin/bband_rsi.py
# directory_url: https://github.com/surendra2304/Stratex/blob/main/stratex_freqtrade_adapter/strategy/builtin/
# User: surendra2304
# Repository: Stratex
# --------------------"""stratex_freqtrade_adapter/strategy/builtin/bband_rsi.py

Classic Bollinger Bands + RSI Mean Reversion Strategy.
"""

from __future__ import annotations
from typing import Any, Dict, Optional
import pandas as pd

from ..interface import IStrategy
from ..registry import registry


@registry.register("bband_rsi")
class Github_surendra2304_Stratex__bband_rsi__20261006_193745(IStrategy):
    """Mean Reversion Strategy exploiting Bollinger Band extremes confirmed by RSI."""

    timeframe = "15m"
    minimal_roi = {
        "0": 0.03,
        "20": 0.015,
        "40": 0.005,
        "60": 0.0,
    }
    stoploss = -0.035
    trailing_stop = False
    can_short = True

    def populate_indicators(self, dataframe: pd.DataFrame, metadata: Optional[Dict[str, Any]] = None) -> pd.DataFrame:
        df = dataframe
        # Bollinger Bands (20, 2.0)
        mid = df["close"].rolling(20).mean()
        std = df["close"].rolling(20).std()
        df["bb_lower"] = mid - (2.0 * std)
        df["bb_middle"] = mid
        df["bb_upper"] = mid + (2.0 * std)

        # RSI (14)
        delta = df["close"].diff()
        gain = (delta.where(delta > 0, 0)).ewm(alpha=1/14, adjust=False).mean()
        loss = (-delta.where(delta < 0, 0)).ewm(alpha=1/14, adjust=False).mean()
        rs = gain / (loss + 1e-9)
        df["rsi"] = 100 - (100 / (1 + rs))

        # Volume rolling mean
        df["volume_mean"] = df["volume"].rolling(24).mean() if "volume" in df.columns else 1.0

        return df

    def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: Optional[Dict[str, Any]] = None) -> pd.DataFrame:
        df = dataframe
        df["enter_long"] = 0
        df["enter_short"] = 0
        df["enter_tag"] = ""

        # Long: Price pierces below lower band and RSI < 32 (oversold)
        long_cond = (
            (df["close"] <= df["bb_lower"]) &
            (df["rsi"] < 32)
        )
        df.loc[long_cond, "enter_long"] = 1
        df.loc[long_cond, "enter_tag"] = "bb_oversold_long"

        # Short: Price pierces above upper band and RSI > 68 (overbought)
        short_cond = (
            (df["close"] >= df["bb_upper"]) &
            (df["rsi"] > 68)
        )
        df.loc[short_cond, "enter_short"] = 1
        df.loc[short_cond, "enter_tag"] = "bb_overbought_short"

        return df

    def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: Optional[Dict[str, Any]] = None) -> pd.DataFrame:
        df = dataframe
        df["exit_long"] = 0
        df["exit_short"] = 0
        df["exit_tag"] = ""

        # Exit long when price reaches middle band or RSI > 60
        exit_long_cond = (df["close"] >= df["bb_middle"]) | (df["rsi"] > 60)
        df.loc[exit_long_cond, "exit_long"] = 1
        df.loc[exit_long_cond, "exit_tag"] = "bb_mid_or_rsi_normalized"

        # Exit short when price reaches middle band or RSI < 40
        exit_short_cond = (df["close"] <= df["bb_middle"]) | (df["rsi"] < 40)
        df.loc[exit_short_cond, "exit_short"] = 1
        df.loc[exit_short_cond, "exit_tag"] = "bb_mid_or_rsi_normalized"

        return df
