# source: https://raw.githubusercontent.com/YJSN180/nico-ranking-custom/8602da2a78f2a679f4ebfa105fbe1fa1a4ef6e20/user_data/strategies/AdvancedHighPerformanceStrategy.py
# --- Do not remove these libs ---
from freqtrade.strategy import IStrategy, merge_informative_pair
from pandas import DataFrame
import talib.abstract as ta
import numpy as np
import freqtrade.vendor.qtpylib.indicators as qtpylib

class Github_YJSN180_nico_ranking_custom__AdvancedHighPerformanceStrategy__20250615_125057(IStrategy):
    """
    Advanced High-Performance Strategy
    
    This strategy aims for high returns with controlled drawdown by combining
    trend-following indicators with oscillators and a dynamic stoploss mechanism.

    Strategy Concept:
    - Trend Identification: Uses a combination of EMAs and ADX to identify the main trend direction and strength.
    - Entry Signals: Enters trades on pullbacks/throwbacks within an established trend, timed with RSI and MACD.
    - Exit Logic (Risk Management): Utilizes the Chandelier Exit (based on ATR) as a dynamic trailing stoploss to protect profits and limit losses.
    - Profit Taking: Primarily relies on the trailing stoploss, but also includes a basic ROI and an option for an exit signal based on trend reversal.
    """
    
    # Strategy interface version - attribute needed so Freqtrade doesn't break.
    INTERFACE_VERSION = 3

    # Timeframe: 1-hour candles are a good balance for this type of strategy.
    timeframe = '1h'
    
    # Can this strategy go short?
    can_short: bool = True

    # Minimal ROI table: A safety net for taking profits.
    minimal_roi = {
        "60": 0.01,
        "30": 0.02,
        "0": 0.04
    }

    # Stoploss: A large static stoploss is used, as the primary stoploss mechanism is the custom Chandelier Exit.
    stoploss = -0.99

    # Trailing stop: Disabled in favor of the custom Chandelier Exit.
    trailing_stop = False

    # --- Hyperoptable Parameters ---
    
    # Entry parameters
    buy_adx_threshold = 30
    buy_rsi_threshold = 40
    
    sell_adx_threshold = 30
    sell_rsi_threshold = 60

    # Chandelier Exit parameters
    ce_atr_period = 22
    ce_atr_multiplier = 3.0
    
    # --- Indicator-based logic ---

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Adds several different TA indicators to the given DataFrame
        """
        # Exponential Moving Averages for trend direction
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=20)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=50)

        # ADX for trend strength
        dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)

        # RSI for entry timing (pullbacks)
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)

        # MACD for momentum confirmation
        macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        dataframe['macdhist'] = macd['macdhist']

        # Average True Range (ATR) for Chandelier Exit
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=self.ce_atr_period)

        # --- Chandelier Exit Calculation ---
        # Long exit line
        chandelier_long_max_high = dataframe['high'].rolling(self.ce_atr_period).max()
        dataframe['chandelier_exit_long'] = chandelier_long_max_high - (dataframe['atr'] * self.ce_atr_multiplier)
        
        # Short exit line
        chandelier_short_min_low = dataframe['low'].rolling(self.ce_atr_period).min()
        dataframe['chandelier_exit_short'] = chandelier_short_min_low + (dataframe['atr'] * self.ce_atr_multiplier)
        
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the entry signal for the given dataframe
        """
        # --- Long Entry Conditions ---
        dataframe.loc[
            (
                # Trend is up
                (dataframe['ema_fast'] > dataframe['ema_slow']) &
                (dataframe['adx'] > self.buy_adx_threshold) &
                
                # Pullback confirmed by RSI
                (dataframe['rsi'] < self.buy_rsi_threshold) &
                
                # MACD confirms upward momentum
                (dataframe['macd'] > dataframe['macdsignal']) &
                
                # Volume is not zero
                (dataframe['volume'] > 0)
            ),
            'enter_long'] = 1

        # --- Short Entry Conditions ---
        dataframe.loc[
            (
                # Trend is down
                (dataframe['ema_fast'] < dataframe['ema_slow']) &
                (dataframe['adx'] > self.sell_adx_threshold) &
                
                # Throwback confirmed by RSI
                (dataframe['rsi'] > self.sell_rsi_threshold) &
                
                # MACD confirms downward momentum
                (dataframe['macd'] < dataframe['macdsignal']) &
                
                # Volume is not zero
                (dataframe['volume'] > 0)
            ),
            'enter_short'] = 1
            
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        """
        Based on TA indicators, populates the exit signal for the given dataframe
        """
        # This basic version relies on the custom stoploss.
        # An advanced version could include exits based on trend reversal signals.
        dataframe.loc[
            (dataframe['volume'] > 0), # Dummy condition to avoid empty dataframe
            ['exit_long', 'exit_short']] = 0

        return dataframe

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: 'datetime',
                        current_rate: float, current_profit: float, **kwargs) -> float:
        """
        Custom stoploss logic, implementing Chandelier Exit
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()

        if trade.is_short:
            # For short trades, we exit if the price goes ABOVE the Chandelier Exit line
            if current_rate > last_candle['chandelier_exit_short']:
                return 0.01 # A small positive value to trigger market sell
        else:
            # For long trades, we exit if the price goes BELOW the Chandelier Exit line
            if current_rate < last_candle['chandelier_exit_long']:
                return -0.01 # A small negative value to trigger market sell

        return self.stoploss 