# --- Imports necesarios para la estrategia y la optimización ---
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter, CategoricalParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from datetime import datetime
from typing import Optional

class ScalpingDeepSeekStrategy(IStrategy):
    # --- Configuración General de la Estrategia ---
    timeframe = '1m' # Se recomienda empezar con 5m para no tener tanto ruido
    
    # Define un stoploss fijo
    stoploss = -0.10

    # Usa un ROI mínimo y permite que el Trailing Stop lo gestione
    minimal_roi = {"0": 100} # ROI desactivado, confiamos en el Trailing Stop o salidas personalizadas

    # Configuración del Trailing Stop
    trailing_stop = True
    trailing_stop_positive = 0.01  # Trailing stop a 1% por debajo del máximo beneficio
    trailing_stop_positive_offset = 0.025 # Se activa cuando el beneficio alcanza el 2.5%
    trailing_only_offset_is_reached = True

    # --- Definición de Parámetros Optimizables (Hyperparameters) ---

    # ⚙️ Parámetros de ENTRADA para COMPRA (LONG)
    buy_adx_enter = IntParameter(15, 40, default=25, space='buy')
    buy_rsi_enter = IntParameter(20, 50, default=45, space='buy')
    buy_volume_factor = DecimalParameter(1.1, 3.0, default=1.8, decimals=1, space='buy')
    
    #  Fibonacci para COMPRA
    buy_fib_lookback_period = IntParameter(24, 96, default=48, space='buy') # Periodo para buscar el swing High/Low
    buy_fib_level_enter = CategoricalParameter([0.382, 0.5, 0.618], default=0.5, space='buy')

    # ⚙️ Parámetros de ENTRADA para VENTA (SHORT)
    sell_adx_enter = IntParameter(15, 40, default=25, space='sell')
    sell_rsi_enter_bottom = IntParameter(50, 80, default=55, space='sell')
    sell_rsi_enter_top = IntParameter(70, 95, default=75, space='sell')
    sell_volume_factor = DecimalParameter(1.1, 3.0, default=1.8, decimals=1, space='sell')
    
    # Fibonacci para VENTA
    sell_fib_lookback_period = IntParameter(24, 96, default=48, space='sell')
    sell_fib_level_enter = CategoricalParameter([0.382, 0.5, 0.618], default=0.5, space='sell')


    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # --- Indicadores Clásicos ---
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=9)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=21)
        dataframe['ema_trend'] = ta.EMA(dataframe, timeperiod=50) # Filtro de tendencia mayor

        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) # RSI estándar
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
        dataframe['volume_ma'] = ta.SMA(dataframe['volume'], timeperiod=20)
        
        # --- Lógica de Retroceso de Fibonacci ---
        # Búsqueda de swing high/low para LONG
        swing_high_long = dataframe['high'].rolling(self.buy_fib_lookback_period.value).max().shift(1)
        swing_low_long = dataframe['low'].rolling(self.buy_fib_lookback_period.value).min().shift(1)
        dataframe['fib_level_long'] = swing_high_long - (swing_high_long - swing_low_long) * self.buy_fib_level_enter.value

        # Búsqueda de swing high/low para SHORT
        swing_high_short = dataframe['high'].rolling(self.sell_fib_lookback_period.value).max().shift(1)
        swing_low_short = dataframe['low'].rolling(self.sell_fib_lookback_period.value).min().shift(1)
        dataframe['fib_level_short'] = swing_low_short + (swing_high_short - swing_low_short) * self.sell_fib_level_enter.value

        # --- Cálculo de VWAP ---
        daily_key = dataframe['date'].dt.date
        tp_volume = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3 * dataframe['volume']
        cumulative_tp_volume = tp_volume.groupby(daily_key).cumsum()
        cumulative_volume = dataframe['volume'].groupby(daily_key).cumsum()
        dataframe['vwap'] = cumulative_tp_volume / cumulative_volume
        # Corregido para evitar FutureWarning
        dataframe['vwap'] = dataframe['vwap'].ffill()

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # --- Condiciones para ENTRADA EN LARGO (LONG) ---
        dataframe.loc[
            (
                # Condición de Fibonacci: el precio cruza hacia abajo el nivel de soporte de Fibonacci
                (qtpylib.crossed_below(dataframe['close'], dataframe['fib_level_long'])) &
                # Filtro de tendencia: el precio está por encima de la EMA de tendencia
                (dataframe['close'] > dataframe['ema_trend']) &
                # Filtro de RSI: el RSI no está sobrecomprado
                (dataframe['rsi'] < self.buy_rsi_enter.value) &
                # Filtro de ADX: hay algo de tendencia
                (dataframe['adx'] > self.buy_adx_enter.value) &
                # Filtro de volumen: hay un pico de volumen
                (dataframe['volume'] > dataframe['volume_ma'] * self.buy_volume_factor.value)
            ),
            'enter_long'
        ] = 1

        # --- Condiciones para ENTRADA EN CORTO (SHORT) ---
        dataframe.loc[
            (
                # Condición de Fibonacci: el precio cruza hacia arriba el nivel de resistencia de Fibonacci
                (qtpylib.crossed_above(dataframe['close'], dataframe['fib_level_short'])) &
                # Filtro de tendencia: el precio está por debajo de la EMA de tendencia
                (dataframe['close'] < dataframe['ema_trend']) &
                # Filtro de RSI: el RSI está en un rango óptimo para cortos
                (dataframe['rsi'] > self.sell_rsi_enter_bottom.value) & 
                (dataframe['rsi'] < self.sell_rsi_enter_top.value) &
                # Filtro de ADX: hay algo de tendencia
                (dataframe['adx'] > self.sell_adx_enter.value) &
                # Filtro de volumen: hay un pico de volumen
                (dataframe['volume'] > dataframe['volume_ma'] * self.sell_volume_factor.value)
            ),
            'enter_short'
        ] = 1
        
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # La salida se gestiona principalmente por el Trailing Stop y custom_exit
        return dataframe
    
    def custom_exit(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float,
                      current_profit: float, **kwargs):
        # Salida temprana si el RSI se sobrecalienta/enfría demasiado
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()
        
        if current_profit > 0.01: # Solo aplicar si ya hay una pequeña ganancia
            if trade.is_short:
                if last_candle['rsi'] < 30:
                    return 'rsi_exit_short'
            else:
                if last_candle['rsi'] > 70:
                    return 'rsi_exit_long'
        
        return None