# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/narutoori.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# isort: skip_file
# --- Do not remove these libs ---
import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame
from freqtrade.strategy.interface import IStrategy
from freqtrade.strategy import DecimalParameter
from technical.indicators import ichimoku
from freqtrade.persistence import Trade
import talib.abstract as ta
import logging
from datetime import datetime, timedelta

logger = logging.getLogger(__name__)

LOG_FILENAME = datetime.now().strftime('logfile_%d_%m_%Y.log')
logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG, format='%(asctime)s :: %(message)s')


class Github_remiotore_freqtrade__narutoori__20260111_210550(IStrategy):
    # Configuração do tipo de ordem
    order_types = {
        'buy': 'limit',
        'sell': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': True
    }

    # Retorno mínimo sobre o investimento (ROI)
    minimal_roi = {
        "120": 0.001,
        "90": 0.0025,
        "60": 0.005,
        "30": 0.015,
        "15": 0.025,
        "0": 0.035,
    }

    # Configuração do timeframe
    timeframe = '5m'

    # Stoploss padrão
    stoploss = -0.05

    # Número máximo de trades abertos
    max_open_trades = 5

    # Interface do Freqtrade (necessário usar versão 2)
    INTERFACE_VERSION = 2

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Popula os indicadores técnicos usados pela estratégia.
        """
        # Indicadores Ichimoku
        ichi = ichimoku(dataframe)
        dataframe['tenkan'] = ichi['tenkan_sen']
        dataframe['kijun'] = ichi['kijun_sen']
        dataframe['senkou_a'] = ichi['senkou_span_a']
        dataframe['senkou_b'] = ichi['senkou_span_b']
        dataframe['cloud_green'] = ichi['cloud_green']
        dataframe['cloud_red'] = ichi['cloud_red']
        dataframe['chikou'] = ichi['chikou_span']

        # Indicadores adicionais
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)  # Índice de Força Relativa
        dataframe['ema8'] = ta.EMA(dataframe, timeperiod=8)  # Média móvel exponencial curta
        dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)  # Média móvel exponencial longa
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)  # Índice de força direcional
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)  # Volatilidade
        dataframe['macd'], dataframe['macdsignal'], dataframe['macdhist'] = ta.MACD(dataframe)  # MACD

        return dataframe

    def is_bullish_engulfing(self, dataframe: DataFrame) -> pd.Series:
        """
        Identifica padrão de engolfo de alta no dataframe.
        """
        return (
            (dataframe['close'] > dataframe['open']) &  # Candle atual é de alta
            (dataframe['close'].shift(1) < dataframe['open'].shift(1)) &  # Candle anterior foi de baixa
            (dataframe['close'] > dataframe['open'].shift(1)) &  # Candle atual "engolfa" o anterior
            (dataframe['open'] < dataframe['close'].shift(1))
        )

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define as condições de compra aprimoradas.
        """
        dataframe.loc[
            (
                # Condição 1: Rompimento da Senkou B com confirmações
                (dataframe['open'].shift(1) < dataframe['senkou_b'].shift(1)) &  # Rompeu nuvem no candle anterior
                (dataframe['close'].shift(1) > dataframe['senkou_b'].shift(1)) &
                (dataframe['open'] > dataframe['senkou_b']) &                   # Confirmado no candle atual
                (dataframe['close'] > dataframe['senkou_b']) &
                (dataframe['volume'] > dataframe['volume'].rolling(10).mean()) &  # Volume forte
                (dataframe['adx'] > 25) &                                       # ADX indicando força da tendência
                (dataframe['macd'] > dataframe['macdsignal'])                   # MACD indicando tendência de alta
                |
                # Condição 2: Cruzamento de EMA8 acima de EMA21 com RSI
                (dataframe['ema8'] > dataframe['ema21']) &                       # EMA8 cruzou acima da EMA21
                (dataframe['close'] > dataframe['ema8']) &                       # Preço acima da EMA8
                (dataframe['rsi'] > 50) &                                        # RSI indicando força
                (dataframe['volume'] > dataframe['volume'].rolling(10).mean()) & # Volume forte
                (dataframe['adx'] > 25)                                          # ADX indicando tendência forte
                |
                # Condição 3: RSI em sobrevendido com reversão (filtro adicional)
                (dataframe['rsi'] < 30) &                                        # RSI sobrevendido
                (dataframe['close'] > dataframe['ema8']) &                       # Preço recupera acima da EMA8
                (dataframe['volume'] > dataframe['volume'].rolling(10).mean()) & # Volume forte
                (dataframe['macd'] > dataframe['macdsignal']) &                  # MACD indicando reversão
                (dataframe['adx'] > 20)                                          # ADX indicando início de força
                |
                # Condição 4: Padrões de velas de reversão
                (self.is_bullish_engulfing(dataframe)) &                         # Padrão de engolfo de alta
                (dataframe['rsi'] > 40) &                                        # RSI confirma reversão
                (dataframe['adx'] > 20)                                          # ADX indicando início de força
            ),
            'buy'] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Define as condições de venda.
        """
        dataframe.loc[
            (
                # Condição 1: Cruzamento para baixo da Senkou B com volume
                ((dataframe['open'] > dataframe['senkou_b']) & 
                 (dataframe['close'] < dataframe['senkou_b']) &
                 (dataframe['volume'] > dataframe['volume'].rolling(10).mean()))  # Volume alto
                |
                # Condição 2: RSI > 70 com fraqueza no preço
                ((dataframe['rsi'] > 70) & 
                 (dataframe['close'] < dataframe['ema8']))  # Preço abaixo da EMA8
                |
                # Condição 3: Cruzamento de EMA8 para baixo da EMA21 (com tolerância)
                ((dataframe['ema8'] < dataframe['ema21'] * 0.999) &
                 (dataframe['close'] < dataframe['ema21']))
            ),
            'sell'] = 1
        return dataframe

    def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float,
                        current_profit: float, **kwargs) -> float:
        """
        Ajusta o stoploss com base no número de trades abertos e na duração do trade.
        """
        max_stoploss = -0.05
        min_stoploss = -0.01
        reduction_per_day = 0.01

        open_trades = Trade.get_open_trades()
        if len(open_trades) >= self.max_open_trades:
            trade_duration = current_time - trade.open_date_utc
            trade_age_days = trade_duration.total_seconds() / (24 * 60 * 60)
            adjusted_stoploss = max_stoploss + (trade_age_days * reduction_per_day)
            adjusted_stoploss = max(adjusted_stoploss, min_stoploss)
            logger.info(f"[{pair}] Stoploss ajustado para {adjusted_stoploss:.4f} após {trade_age_days:.2f} dias.")
            return adjusted_stoploss

        return max_stoploss
