from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
from pandas import DataFrame
import numpy as np

class Hermes_SR(IStrategy):
    """
    Estrategia que detecta soportes y resistencias con múltiples toques
    y confirma la entrada con el cierre de la siguiente vela.
    """
    INTERFACE_VERSION = 3

    timeframe = '1m'
    minimal_roi = {"0": 0.005}
    stoploss = -0.01
    startup_candle_count = 150  # para tener margen

    # Parámetros optimizables
    lookback_period = IntParameter(80, 150, default=120, space='buy')
    touch_threshold = IntParameter(2, 8, default=3, space='buy')
    margin_percent = DecimalParameter(0.001, 0.01, default=0.002, space='buy')
    min_absolute_margin = DecimalParameter(0.00001, 0.001, default=0.0001, space='buy')  # margen mínimo en precio absoluto

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Detecta niveles con múltiples toques.
        """
        period = self.lookback_period.value
        margin_percent = self.margin_percent.value
        min_absolute_margin = self.min_absolute_margin.value

        levels = []
        confirmations = []

        for i in range(len(dataframe)):
            if i < period + 1:
                levels.append(np.nan)
                confirmations.append(False)
                continue

            # Ventana histórica de N velas
            window = dataframe['close'].iloc[i - period:i]

            # Dividimos rango en 30 niveles
            bin_counts, bin_edges = np.histogram(window, bins=30)

            # Encontramos el nivel más tocado
            idx_max = np.argmax(bin_counts)
            level_low = bin_edges[idx_max]
            level_high = bin_edges[idx_max + 1]
            level_mid = (level_low + level_high) / 2

            # Rango de tolerancia:
            # Máximo entre porcentaje relativo y margen absoluto mínimo
            margin_range = max(level_mid * margin_percent, min_absolute_margin)
            margin_low = level_mid - margin_range
            margin_high = level_mid + margin_range

            # Contar cuántos cierres tocaron ese rango
            touches = ((window >= margin_low) & (window <= margin_high)).sum()

            if touches >= self.touch_threshold.value:
                levels.append(level_mid)
                # Confirmación: si vela anterior cerró por debajo y esta por encima
                prev_close = dataframe['close'].iloc[i - 1]
                confirm = prev_close < level_mid and dataframe['close'].iloc[i] > level_mid
                confirmations.append(confirm)
            else:
                levels.append(np.nan)
                confirmations.append(False)

        dataframe['level'] = levels
        dataframe['confirmed'] = confirmations

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Entrada LONG si:
        - Tenemos nivel detectado
        - Confirmación por cierre en la vela actual
        """
        dataframe['enter_long'] = 0

        dataframe.loc[
            (
                dataframe['level'].notnull() &
                (dataframe['confirmed'] == True)
            ),
            'enter_long'
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Salida por stoploss/ROI o puedes definir lógica extra.
        """
        dataframe['exit_long'] = 0
        return dataframe
