from freqtrade.strategy import IStrategy, IntParameter
from pandas import DataFrame
import talib.abstract as ta

class Hermes(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = '1m'

    # ROI y trailing_stop como método de salida
    minimal_roi = {
        "0": 0.02,
        "10": 0.01,
        "30": 0
    }

    stoploss = -0.04
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.015
    trailing_only_offset_is_reached = True
    
    buy_above_ma9 = False
    buy_ma_9_above_25 = False
    use_rsi_filter = True
    rsi_requires_ma9_above_ma25 = False
    use_ichimoku_filter = False

    # Hiperparámetro optimizable: periodo del RSI
    ma9_timeperiod = IntParameter(9, 9, default=9, space='buy', optimize=buy_above_ma9)
    rsi_period = IntParameter(5, 30, default=14, space='buy', optimize=use_rsi_filter)
    tenkan_period = IntParameter(3, 6, default=4, space='buy', optimize=use_ichimoku_filter)
    kijun_period = IntParameter(7, 15, default=9, space='buy', optimize=use_ichimoku_filter)
    senkou_period = IntParameter(15, 30, default=26, space='buy', optimize=use_ichimoku_filter)

    def populate_indicators(self, df: DataFrame, metadata: dict) -> DataFrame:
        if self.use_rsi_filter:
            df['rsi'] = ta.RSI(df, timeperiod=self.rsi_period.value)

        if self.buy_above_ma9 or self.buy_ma_9_above_25 or self.rsi_requires_ma9_above_ma25:
            df['ma_9'] = ta.MA(df, timeperiod=self.ma9_timeperiod.value)

        if self.buy_ma_9_above_25 or self.rsi_requires_ma9_above_ma25:
            df['ma_25'] = ta.MA(df, timeperiod=25)

        if self.use_ichimoku_filter:
            high = df['high']
            low = df['low']
            tenkan = self.tenkan_period.value
            kijun = self.kijun_period.value
            senkou = self.senkou_period.value

            df['tenkan_sen'] = (high.rolling(window=tenkan).max() + low.rolling(window=tenkan).min()) / 2
            df['kijun_sen'] = (high.rolling(window=kijun).max() + low.rolling(window=kijun).min()) / 2
            df['senkou_span_a'] = ((df['tenkan_sen'] + df['kijun_sen']) / 2).shift(kijun)
            df['senkou_span_b'] = ((high.rolling(window=senkou).max() + low.rolling(window=senkou).min()) / 2).shift(kijun)

        return df

    def populate_buy_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
        df['buy'] = 0

        condition = True

        if self.use_rsi_filter:
            condition &= (df['rsi'] < 30)
            if self.rsi_requires_ma9_above_ma25:
                condition &= (df['ma_9'] > df['ma_25'])

        if self.buy_above_ma9:
            condition &= (df['close'] > df['ma_9'])

        if self.buy_ma_9_above_25:
            condition &= (df['ma_9'] > df['ma_25']) & (df['ma_9'].shift(1) <= df['ma_25'].shift(1))

        if self.use_ichimoku_filter:
            condition &= (df['close'] > df['senkou_span_a']) & (df['close'] > df['senkou_span_b'])

        df.loc[condition, 'buy'] = 1

        return df

    def populate_sell_trend(self, df: DataFrame, metadata: dict) -> DataFrame:
        df['sell'] = 0
        return df
