# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/ConsecutiveDipFuturesStrategyFutures_20250115_2.py
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
from pandas import DataFrame
import talib.abstract as ta
import numpy as np

class Github_remiotore_freqtrade__ConsecutiveDipFuturesStrategyFutures_20250115_2__20260111_210550(IStrategy):
    """
    Estratégia para operar no mercado de futures, comprando e vendendo pares
    com base em velas consecutivas negativas e outros indicadores técnicos.
    """

    # Configurações gerais
    timeframe = "1h"  # Timeframe de 1 hora
    startup_candle_count = 50  # Número de candles necessários antes de começar
    can_short = True  # Suporte para operações de venda (short)

    # ROI (Return on Investment)
    minimal_roi = {
        "0": 0.05,  # 5% de retorno mínimo
        "60": 0.03,  # 3% após 1 hora
        "120": 0.02,  # 2% após 2 horas
        "180": 0.01,  # 1% após 3 horas
        "240": 0  # Sem limite após 4 horas
    }

    # Stoploss fixo
    stoploss = -0.10  # 10% de stop-loss (mais conservador para futures)

    # Trailing stop para proteger lucros
    trailing_stop = True
    trailing_stop_positive = 0.01  # Reduzido para 1% para entradas mais rápidas
    trailing_stop_positive_offset = 0.03

    # Parâmetros otimizáveis
    rsi_threshold = IntParameter(10, 50, default=25, space="buy", optimize=True)  # RSI de entrada ajustado
    consecutive_candles = IntParameter(2, 4, default=3, space="buy", optimize=True)  # Número de velas negativas consecutivas ajustado
    atr_multiplier = DecimalParameter(1.0, 2.0, default=1.2, space="buy", optimize=True)  # Multiplicador do ATR ajustado

    # Filtro ADX ajustado
    adx_threshold = IntParameter(15, 25, default=20, space="buy", optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Adiciona indicadores ao DataFrame.
        """
        # RSI para detectar sobrevenda
        dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)

        # ATR para medir volatilidade
        dataframe["atr"] = ta.ATR(dataframe, timeperiod=14)

        # ADX para confirmar força da tendência
        dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)

        # Média do volume para identificar picos
        dataframe["volume_mean"] = dataframe["volume"].rolling(window=20).mean()

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define as condições de entrada para compra e venda.
        """
        consecutive = self.consecutive_candles.value

        # Condições de compra (long)
        dataframe["consecutive_dip"] = True
        for i in range(1, consecutive + 1):
            dataframe["consecutive_dip"] &= dataframe["close"].shift(i) < dataframe["close"].shift(i - 1)

        dataframe.loc[(
            dataframe["consecutive_dip"] &
            (dataframe["rsi"] < self.rsi_threshold.value) &
            (dataframe["volume"] > dataframe["volume_mean"]) &
            (dataframe["adx"] > self.adx_threshold.value)  # Tendência moderada ou forte
        ), "enter_long"] = 1

        # Condições de venda (short)
        dataframe["consecutive_rise"] = True
        for i in range(1, consecutive + 1):
            dataframe["consecutive_rise"] &= dataframe["close"].shift(i) > dataframe["close"].shift(i - 1)

        dataframe.loc[(
            dataframe["consecutive_rise"] &
            (dataframe["rsi"] > 100 - self.rsi_threshold.value) &
            (dataframe["volume"] > dataframe["volume_mean"]) &
            (dataframe["adx"] > self.adx_threshold.value)  # Tendência moderada ou forte
        ), "enter_short"] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define as condições de saída.
        """
        # Saída de posições long
        dataframe.loc[(
            (dataframe["rsi"] > 70) |  # RSI indicando sobrecompra
            (dataframe["close"] > (dataframe["close"] + dataframe["atr"] * self.atr_multiplier.value))  # Preço acima do ATR ajustado
        ), "exit_long"] = 1

        # Saída de posições short
        dataframe.loc[(
            (dataframe["rsi"] < 30) |  # RSI indicando sobrevenda
            (dataframe["close"] < (dataframe["close"] - dataframe["atr"] * self.atr_multiplier.value))  # Preço abaixo do ATR ajustado
        ), "exit_short"] = 1

        return dataframe

    def leverage(self, pair: str, current_time, current_rate: float, proposed_leverage: float, max_leverage: float, side: str, **kwargs) -> float:
        """
        Ajusta a alavancagem dinamicamente com base no ATR (volatilidade).
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        atr = dataframe["atr"].iloc[-1]

        # Maior volatilidade = menor alavancagem
        dynamic_leverage = max(1.0, min(max_leverage, 2.0 / atr))
        return dynamic_leverage
