# source: https://raw.githubusercontent.com/GoLukeEnviro/trading-hub/a20e8f66de687fa112152e48369055dd9fc806d6/freqtrade/bots/regime-hybrid/user_data/strategies/SafeEntryDaily.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np


class Github_GoLukeEnviro_trading_hub__SafeEntryDaily__20260603_010621(IStrategy):
    """
    Strategy 4: Github_GoLukeEnviro_trading_hub__SafeEntryDaily__20260603_010621
    Pullback entries in confirmed uptrend.
    EMA50 > EMA200 (uptrend confirmed) + RSI pullback (40-55) + BTC regime.
    Waits for dips, never chases. Most conservative.
    """
    INTERFACE_VERSION = 3

    minimal_roi = {
        "0": 0.10,
        "1440": 0.05,
        "2880": 0.03,
        "4320": 0.01,
        "0": 0
    }

    stoploss = -0.05
    can_short = False
    timeframe = '1d'
    startup_candle_count = 250
    trailing_stop = False
    use_custom_stoploss = False

    rsi_floor = IntParameter(30, 45, default=40, space="buy")
    rsi_ceiling = IntParameter(50, 65, default=55, space="buy")
    pullback_pct = DecimalParameter(0.02, 0.08, default=0.04, space="buy")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['ema50'] = ta.EMA(dataframe['close'], timeperiod=50)
        dataframe['ema200'] = ta.EMA(dataframe['close'], timeperiod=200)
        dataframe['ema50_slope'] = dataframe['ema50'].diff(5)
        
        # Uptrend confirmation
        dataframe['uptrend_confirmed'] = (
            (dataframe['ema50'] > dataframe['ema200']) &
            (dataframe['ema50_slope'] > 0) &
            (dataframe['close'] > dataframe['ema50'])
        )
        
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        
        # Pullback detection: price dipped from recent high
        dataframe['high_5'] = dataframe['high'].rolling(5).max()
        dataframe['pullback_trigger'] = (
            (dataframe['high_5'] - dataframe['close']) / dataframe['high_5'] > self.pullback_pct.value
        )
        
        # Volume: increased on pullback = accumulation
        dataframe['volume_sma20'] = ta.SMA(dataframe['volume'], timeperiod=20)
        dataframe['volume_spike'] = dataframe['volume'] > dataframe['volume_sma20'] * 0.8

        # BTC regime filter
        try:
            btc_df = self.dp.get_pair_dataframe("BTC/USDT:USDT", "1d")
            btc_df['btc_ema200'] = ta.EMA(btc_df['close'], timeperiod=200)
            dataframe['btc_ema200'] = btc_df['btc_ema200'].reindex(dataframe.index, method='ffill')
            dataframe['btc_close'] = btc_df['close'].reindex(dataframe.index, method='ffill')
        except Exception:
            dataframe['btc_ema200'] = 0
            dataframe['btc_close'] = 999999
        
        dataframe['macro_uptrend'] = dataframe['btc_close'] > dataframe['btc_ema200']
        
        # Safe entry: uptrend + pullback + RSI pullback zone + BTC regime
        dataframe['safe_entry'] = (
            (dataframe['uptrend_confirmed']) &
            (dataframe['pullback_trigger']) &
            (dataframe['rsi'] > self.rsi_floor.value) &
            (dataframe['rsi'] < self.rsi_ceiling.value)
        )

        # Exit: trend breaking down
        dataframe['trend_broken'] = (
            (dataframe['close'] < dataframe['ema200']) |
            ((dataframe['ema50'] < dataframe['ema200']) & (dataframe['rsi'] < 50))
        )

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['safe_entry']) &
                (dataframe['macro_uptrend']) &
                (dataframe['volume_spike']) &
                (dataframe['volume'] > 0)
            ),
            ['enter_long', 'enter_tag']
        ] = (1, 'safe_entry_daily_long')

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['trend_broken']) |
                (~dataframe['macro_uptrend'])
            ),
            ['exit_long', 'exit_tag']
        ] = (1, 'safe_entry_daily_exit')

        return dataframe
