# source: https://raw.githubusercontent.com/Aymane-lahlou/Trading_Binance/66bee44d3f65c5ac7e5be69f42f3733288f0e3d2/user_data/strategies/HalalSpotStrategy.py
from pandas import DataFrame
import talib.abstract as ta

from freqtrade.strategy import IStrategy, merge_informative_pair


class Github_Aymane_lahlou_Trading_Binance__HalalSpotStrategy__20260615_230514(IStrategy):
    INTERFACE_VERSION = 3

    timeframe = "15m"
    # Higher timeframe used to confirm the broader trend before entering.
    informative_timeframe = "4h"
    can_short = False

    minimal_roi = {
        "0": 0.05,    # exit at +5% immediately
        "120": 0.025, # after 2h, exit at +2.5%
        "480": 0.012, # after 8h, exit at +1.2%
        "1440": 0.005, # after 24h, exit at +0.5%
    }

    stoploss = -0.05

    # Trailing stop activates after a meaningful move and then protects profit.
    trailing_stop = True
    trailing_stop_positive = 0.015
    trailing_stop_positive_offset = 0.03
    trailing_only_offset_is_reached = True

    process_only_new_candles = True
    startup_candle_count = 200

    # Protections guard against whipsaw re-entries and drawdown clusters.
    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 4,
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 2,
                "stop_duration_candles": 12,
                "only_per_pair": True,
            },
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": 48,
                "trade_limit": 4,
                "stop_duration_candles": 12,
                "max_allowed_drawdown": 0.1,
            },
        ]

    def informative_pairs(self):
        pairs = self.dp.current_whitelist()
        return [(pair, self.informative_timeframe) for pair in pairs]

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
        dataframe["sma_fast"] = ta.SMA(dataframe, timeperiod=20)
        dataframe["sma_slow"] = ta.SMA(dataframe, timeperiod=50)
        dataframe["ema_trend"] = ta.EMA(dataframe, timeperiod=200)
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)
        dataframe["atr_ratio"] = dataframe["atr"] / dataframe["close"]
        dataframe["volume_mean"] = dataframe["volume"].rolling(20).mean()
        dataframe["volume_ratio"] = dataframe["volume"] / dataframe["volume_mean"]

        # Higher-timeframe trend filter keeps entries aligned with the broader move.
        informative = self.dp.get_pair_dataframe(
            pair=metadata["pair"], timeframe=self.informative_timeframe
        )
        informative["sma_trend"] = ta.SMA(informative, timeperiod=50)
        informative["sma_trend_slope"] = informative["sma_trend"] - informative[
            "sma_trend"
        ].shift(3)
        dataframe = merge_informative_pair(
            dataframe, informative, self.timeframe, self.informative_timeframe, ffill=True
        )

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        htf_close = f"close_{self.informative_timeframe}"
        htf_trend = f"sma_trend_{self.informative_timeframe}"
        htf_trend_slope = f"sma_trend_slope_{self.informative_timeframe}"
        dataframe.loc[
            (
                (dataframe["rsi"] > 32)
                & (dataframe["rsi"].shift(1) <= 32)
                & (dataframe["sma_fast"] > dataframe["sma_slow"])
                & (dataframe["close"] > dataframe["ema_trend"])
                # Only buy recovering dips while the 4h trend is up.
                & (dataframe[htf_close] > dataframe[htf_trend])
                & (dataframe[htf_trend_slope] > 0)
                & (dataframe["close"] > dataframe["open"])
                & (dataframe["volume_ratio"] > 1.0)
                & (dataframe["atr_ratio"] > 0.002)
                & (dataframe["atr_ratio"] < 0.06)
                & (dataframe["volume"] > 0)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe["rsi"] > 70)
                | (dataframe["sma_fast"] < dataframe["sma_slow"])
                | (dataframe["close"] < dataframe["ema_trend"])
            ),
            "exit_long",
        ] = 1
        return dataframe
