# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/NOTankAi15_20250105.py
"""
Freqtrade Strategy Template.
Adapted to test the strategy in futures markets with leverage and enhanced risk management.
"""
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import numpy as np
from freqtrade.strategy import IntParameter, DecimalParameter
from typing import Dict, List

class Github_remiotore_freqtrade__NOTankAi15_20250105__20260111_210550(IStrategy):
    """
    Strategy intended for 15m timeframe.
    Adapted for futures markets with leverage and enhanced risk management.
    """

    INTERFACE_VERSION = 3

    # Strategy Parameters
    can_short = True
    timeframe = '15m'

    # ROI table
    minimal_roi = {
        "0": 0.1,
        "30": 0.05,
        "60": 0.025,
        "120": 0
    }

    # Stoploss
    stoploss = -0.10  # Adjusted for futures to be more conservative

    # Trailing stop
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.02
    trailing_only_offset_is_reached = True

    # Hyperparameters for optimization
    buy_rsi = IntParameter(20, 80, default=30, space='buy', optimize=True)
    sell_rsi = IntParameter(60, 100, default=70, space='sell', optimize=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: Dict) -> DataFrame:
        """
        Add indicators used by the strategy.
        """
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
        dataframe['ema200'] = ta.EMA(dataframe, timeperiod=200)
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)  # Average True Range for volatility-based position sizing
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: Dict) -> DataFrame:
        """
        Define conditions for entering trades.
        """
        # Long condition
        dataframe.loc[
            (
                (dataframe['rsi'] < self.buy_rsi.value) &
                (dataframe['ema50'] > dataframe['ema200'])
            ),
            'enter_long'
        ] = 1

        # Short condition
        dataframe.loc[
            (
                (dataframe['rsi'] > self.sell_rsi.value) &
                (dataframe['ema50'] < dataframe['ema200'])
            ),
            'enter_short'
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: Dict) -> DataFrame:
        """
        Define conditions for exiting trades.
        """
        # Exit long condition
        dataframe.loc[
            (
                (dataframe['rsi'] > self.sell_rsi.value)
            ),
            'exit_long'
        ] = 1

        # Exit short condition
        dataframe.loc[
            (
                (dataframe['rsi'] < self.buy_rsi.value)
            ),
            '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:
        """
        Adjust leverage dynamically based on ATR (volatility).
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        atr = dataframe['atr'].iloc[-1]

        # Higher ATR (volatility) = lower leverage
        # Adjust the multiplier as needed
        dynamic_leverage = max(1.0, min(max_leverage, 2.0 / atr))

        return dynamic_leverage

    def custom_stake_amount(self, pair: str, current_time, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, **kwargs) -> float:
        """
        Dynamically adjust stake size based on ATR (volatility).
        """
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        atr = dataframe['atr'].iloc[-1]

        # Lower ATR (volatility) = higher stake size
        dynamic_stake = max(min_stake, min(max_stake, proposed_stake * (2.0 / atr)))

        return dynamic_stake
