# source: https://raw.githubusercontent.com/KOPYk4T/freqtrade-strategies/03a8d9e99e8a315229c8b2e85e4cad5a979b51e3/strategies/Grid/GridStrategy.py
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List, Optional
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
from pandas import DataFrame

class Github_KOPYk4T_freqtrade_strategies__GridStrategy__20251105_183916(IStrategy):
    """
    Estrategia de Grid Trading optimizada para $100
    - Compra en niveles bajos
    - Vende en niveles altos  
    - Mantiene rejilla dinámica
    """
    
    INTERFACE_VERSION = 3
    timeframe = '5m'
    
    # ROI y Stoploss
    minimal_roi = {
        "0": 0.02  # 2% ganancia por trade
    }
    
    stoploss = -0.05  # 5% stop loss máximo
    
    # Grid Settings - AJUSTABLES
    grid_spacing_percent = 2.0    # 2% entre niveles
    grid_levels = 4               # 4 niveles arriba/abajo
    
    # Configuración adicional
    can_short = False
    startup_candle_count: int = 30
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False
    
    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Añadir indicadores técnicos para Grid Trading
        """
        
        # SMA para determinar tendencia general
        dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
        dataframe['sma_50'] = ta.SMA(dataframe, timeperiod=50)
        
        # RSI para evitar comprar en sobrecompra
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        
        # ATR para medir volatilidad
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
        
        # Bollinger Bands para límites de grid
        bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2)
        dataframe['bb_lowerband'] = bollinger['lower']
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe['bb_middleband'] = bollinger['mid']
        
        # Calcular niveles de grid dinámicos
        dataframe['grid_buy_level'] = dataframe['close'] * (1 - self.grid_spacing_percent / 100)
        dataframe['grid_sell_level'] = dataframe['close'] * (1 + self.grid_spacing_percent / 100)
        
        # Volumen promedio
        dataframe['volume_sma'] = ta.SMA(dataframe['volume'], timeperiod=20)
        
        return dataframe
    
    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Condiciones de compra para Grid Trading
        """
        
        dataframe.loc[
            (
                # Grid Buy Conditions
                (dataframe['close'] <= dataframe['bb_lowerband']) |  # Precio en banda inferior
                (dataframe['rsi'] < 40) |                            # RSI indica sobreventa
                (
                    (dataframe['close'] < dataframe['sma_20']) &     # Precio bajo SMA
                    (dataframe['volume'] > dataframe['volume_sma'])   # Volumen alto
                )
            ) &
            (dataframe['volume'] > 0) &                              # Volumen mínimo
            (dataframe['close'] > 0),                                # Precio válido
            'enter_long'
        ] = 1
        
        return dataframe
    
    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Condiciones de venta para Grid Trading
        """
        
        dataframe.loc[
            (
                # Grid Sell Conditions
                (dataframe['close'] >= dataframe['bb_upperband']) |  # Precio en banda superior
                (dataframe['rsi'] > 60) |                            # RSI indica sobrecompra
                (
                    (dataframe['close'] > dataframe['sma_20']) &     # Precio sobre SMA
                    (dataframe['volume'] > dataframe['volume_sma'])   # Volumen alto
                )
            ) &
            (dataframe['volume'] > 0),                               # Volumen mínimo
            'exit_long'
        ] = 1
        
        return dataframe
    
    def custom_stoploss(self, pair: str, trade: 'Trade', current_time, current_rate,
                       current_profit: float, **kwargs) -> float:
        """
        Stop loss dinámico para Grid Trading
        """
        
        # Si estamos ganando más del 1%, ajustar stop loss
        if current_profit > 0.01:
            return -0.02  # Stop loss a -2% si ya ganamos 1%
        
        # Stop loss normal
        return self.stoploss
    
    def confirm_trade_entry(self, pair: str, order_type: str, amount: float,
                           rate: float, time_in_force: str, current_time,
                           entry_tag, side: str, **kwargs) -> bool:
        """
        Confirmar entrada de trade - útil para validaciones extra
        """
        
        # Lógica adicional si es necesaria
        # Por ejemplo, no entrar si ya tenemos muchas posiciones del mismo par
        
        return True