# source: https://raw.githubusercontent.com/genieys/vwap1/f59869c32c272d1961c8e420d8837c8f913d4e58/engulfing.py
from freqtrade.strategy import IStrategy
from freqtrade.strategy import BooleanParameter, DecimalParameter
from pandas import DataFrame
import numpy as np
import talib.abstract as ta # Import for RSI

# --------------------------------
#   Strategy: Github_genieys_vwap1__engulfing__20251208_091756
#   Author:   Gemini
#   Version:  3.2 (Fixed Hyperopt Toggles)
# --------------------------------

class Github_genieys_vwap1__engulfing__20251208_091756(IStrategy):

    INTERFACE_VERSION = 3
    
    # -----------------------------------
    # HYPEROPT PARAMETERS 
    # NOTE: Only parameters with optimize=True are tuned by Hyperopt.
    # -----------------------------------
    
    # Buy Filters (FIXED TO OPTIMIZED VALUES)
    use_volume_filter = BooleanParameter(default=True, space='buy', optimize=False)
    use_trend_filter = BooleanParameter(default=False, space='buy', optimize=False)
    use_body_size_filter = BooleanParameter(default=True, space='buy', optimize=False)
    use_risk_filter = BooleanParameter(default=False, space='buy', optimize=False)
    
    # 🛑 ENABLE OPTIMIZATION FOR THE NEW RSI FILTER 🛑
    use_rsi_filter = BooleanParameter(default=True, space='buy', optimize=True) 

    # Filter Values (FIXED TO OPTIMIZED VALUES)
    volume_multiplier = DecimalParameter(1.0, 3.0, decimals=2, default=2.83, space='buy', optimize=False)
    risk_threshold = DecimalParameter(0.1, 0.8, decimals=2, default=0.33, space='buy', optimize=False)
    
    # 🛑 ENABLE OPTIMIZATION FOR THE NEW RSI THRESHOLD 🛑
    rsi_buy_threshold = DecimalParameter(30.0, 70.0, decimals=1, default=60.0, space='buy', optimize=True)

    # Stoploss Parameter (FIXED TO OPTIMIZED VALUE)
    stoploss_param = DecimalParameter(
        -0.20, -0.05, decimals=3, default=-0.088, space='stoploss', optimize=False
    )
    
    # Trailing Stop Parameters (FIXED TO OPTIMIZED VALUES)
    tsp_param = DecimalParameter(0.005, 0.03, decimals=3, default=0.335, space='trailing_stop', optimize=False)
    tsp_offset_param = DecimalParameter(0.01, 0.05, decimals=3, default=0.373, space='trailing_stop', optimize=False)
    
    # -----------------------------------
    
    # STOPLOSS PROPERTY
    @property
    def stoploss(self):
        return self.stoploss_param.value

    @stoploss.setter
    def stoploss(self, value: float):
        self.stoploss_param.value = value

    # TRAILING_STOP_POSITIVE PROPERTY
    @property
    def trailing_stop_positive(self):
        return self.tsp_param.value

    @trailing_stop_positive.setter
    def trailing_stop_positive(self, value: float):
        self.tsp_param.value = value

    # TRAILING_STOP_POSITIVE_OFFSET PROPERTY
    @property
    def trailing_stop_positive_offset(self):
        return self.tsp_offset_param.value

    @trailing_stop_positive_offset.setter
    def trailing_stop_positive_offset(self, value: float):
        self.tsp_offset_param.value = value


    # Strategy Parameters (Fixed)
    minimal_roi = { "0": 0.05, "30": 0.03, "60": 0.01 }
 
    trailing_stop = True
    trailing_only_offset_is_reached = False 
    
    timeframe = '5m'
    startup_candle_count: int = 20 
    process_only_new_candles = False

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Adds required indicators for signals and filters.
        """
        
        # --- 1. Base Signal: Bullish Engulfing ---
        dataframe['bullish_Github_genieys_vwap1__engulfing__20251208_091756'] = (
            (dataframe['close'] > dataframe['open']) &
            (dataframe['close'].shift(1) < dataframe['open'].shift(1)) &
            (dataframe['open'] <= dataframe['close'].shift(1)) &
            (dataframe['close'] >= dataframe['open'].shift(1))
        )

        # --- 2. Volume Filter Calculation ---
        dataframe['volume_mean_20'] = dataframe['volume'].rolling(window=20).mean()
        dataframe['volume_above_average'] = (
            dataframe['volume'] > (dataframe['volume_mean_20'] * self.volume_multiplier.value)
        )

        # --- 3. Body Size Filter Calculation ---
        dataframe['body_size'] = (dataframe['close'] - dataframe['open']).abs()
        dataframe['body_size_mean_10'] = dataframe['body_size'].rolling(window=10).mean()
        dataframe['strong_body'] = (
            dataframe['body_size'] > dataframe['body_size_mean_10']
        )
        
        # --- 4. Trend Filter Calculation ---
        dataframe['short_term_downtrend'] = (
            (dataframe['low'] < dataframe['low'].shift(1)) & 
            (dataframe['low'].shift(1) < dataframe['low'].shift(2))
        )
        
        # --- 5. Risk Filter Calculation ---
        dataframe['low_risk_entry'] = (
            dataframe['close'] < dataframe['low'] + (dataframe['high'] - dataframe['low']) * self.risk_threshold.value
        )

        # --- 6. RSI Confirmation Filter ---
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_confirm'] = (dataframe['rsi'] < self.rsi_buy_threshold.value)
        
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Combines base signal with all filters.
        """
        conditions = [
            # 1. Base Signal (ALWAYS REQUIRED)
            dataframe['bullish_Github_genieys_vwap1__engulfing__20251208_091756'],
            (dataframe['volume'] > 0), # Freqtrade safety
        ]
        
        # 2. Filter: Volume Confirmation 
        if self.use_volume_filter.value:
            conditions.append(dataframe['volume_above_average'])
            
        # 3. Filter: Trend Confirmation 
        if self.use_trend_filter.value:
            conditions.append(dataframe['short_term_downtrend'])

        # 4. Filter: Signal Strength 
        if self.use_body_size_filter.value:
            conditions.append(dataframe['strong_body'])
        
        # 5. Filter: Risk Check
        if self.use_risk_filter.value:
            conditions.append(dataframe['low_risk_entry'])
            
        # 6. Filter: RSI Check 
        if self.use_rsi_filter.value:
            conditions.append(dataframe['rsi_confirm'])

        # Combine all active conditions
        if conditions:
            dataframe.loc[
                np.all(conditions, axis=0),
                'buy'] = 1

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Uses Bearish Engulfing for exit.
        """
        dataframe['bearish_Github_genieys_vwap1__engulfing__20251208_091756'] = (
            (dataframe['close'] < dataframe['open']) &
            (dataframe['close'].shift(1) > dataframe['open'].shift(1)) &
            (dataframe['open'] >= dataframe['close'].shift(1)) &
            (dataframe['close'] <= dataframe['open'].shift(1))
        )

        dataframe.loc[(dataframe['bearish_Github_genieys_vwap1__engulfing__20251208_091756']), 'sell'] = 1
        
        return dataframe
