# source: https://raw.githubusercontent.com/Chris6622/class-AdvancedFuturesSwingStrategy-IStrategy-/786cfa2c323feab11c072706b06cb9e4243af820/user_data/strategies/futures_strategy.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# --- Do not remove these libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, List

from freqtrade.strategy import (IStrategy, IntParameter, DecimalParameter, CategoricalParameter)
from freqtrade.persistence import Trade
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib


class Github_Chris6622_class_AdvancedFuturesSwingStrategy_IStrategy___futures_strategy__20260208_084829(IStrategy):
    """
    This is the final, robust hyperoptable version.
    It separates static defaults from hyperopt spaces and correctly assigns
    parameters to the 'buy' and 'sell' spaces for full compatibility.
    """
    INTERFACE_VERSION = 3
    timeframe = '4h'
    can_short: bool = True

    # --- Static Default Parameters for Backtesting & Initial Validation ---
    minimal_roi = {
        "0": 0.862,
        "1538": 0.312,
        "3044": 0.1,
        "7553": 0
    }
    
    stoploss = -0.282
    trailing_stop = True
    trailing_stop_positive = 0.015
    trailing_stop_positive_offset = 0.041
    trailing_only_offset_is_reached = True

    # --- Hyperoptable Entry Parameters (buy space) ---
    # These are defined directly in the class body.
    # The 'space' argument assigns them to the 'buy' hyperopt space.
    ema_fast_period = IntParameter(10, 60, default=19, space="buy", optimize=True)
    ema_slow_period = IntParameter(100, 250, default=175, space="buy", optimize=True)
    atr_period = IntParameter(5, 20, default=11, space="buy", optimize=True)
    atr_multiplier = DecimalParameter(1.0, 5.0, default=1.0, decimals=1, space="buy", optimize=True)


    # --- Strategy Settings ---
    startup_candle_count: int = 250
    
    order_types = {
        'entry': 'market',
        'exit': 'market',
        'stoploss': 'market',
        'stoploss_on_exchange': False,
    }
    order_time_in_force = {'entry': 'gtc', 'exit': 'gtc'}

    # --- Hyperopt Space for Exit Parameters ---

    def populate_exit_trend_space(self) -> List[any]:
        """
        Defines the hyperopt space for parameters used in exit logic.
        These are defined here because they are validated by Freqtrade at startup.
        """
        return [
            DecimalParameter(0.05, 0.25, default=0.15, name='stoploss'),
            IntParameter(10, 240, name='roi_t1'),
            DecimalParameter(0.01, 0.10, name='roi_p1'),
            CategoricalParameter([True, False], default=True, name='trailing_stop'),
            DecimalParameter(0.01, 0.10, default=0.03, name='trailing_stop_positive_offset'),
            DecimalParameter(0.005, 0.05, default=0.01, name='trailing_stop_positive'),
            CategoricalParameter([True, False], default=True, name='trailing_only_offset_is_reached'),
        ]

    # --- Indicator & Signal Logic ---

    def informative_pairs(self):
        return []

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # MACD
        macd = ta.MACD(dataframe)
        dataframe['macd'] = macd['macd']
        dataframe['macdsignal'] = macd['macdsignal']
        
        # EMAs - uses the value from the hyperoptable parameter
        dataframe['ema_fast'] = ta.EMA(dataframe, timeperiod=self.ema_fast_period.value)
        dataframe['ema_slow'] = ta.EMA(dataframe, timeperiod=self.ema_slow_period.value)

        # ATR - uses the value from the hyperoptable parameter
        dataframe['atr'] = ta.ATR(dataframe, timeperiod=self.atr_period.value)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['ema_fast'] > dataframe['ema_slow']) &
                (qtpylib.crossed_above(dataframe['macd'], dataframe['macdsignal']))
            ),
            'enter_long'] = 1

        dataframe.loc[
            (
                (dataframe['ema_fast'] < dataframe['ema_slow']) &
                (qtpylib.crossed_below(dataframe['macd'], dataframe['macdsignal']))
            ),
            'enter_short'] = 1
        
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exits are primarily handled by ROI, Stoploss, and Trailing Stop
        return dataframe

    def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:
        
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()
        
        if last_candle is not None and 'atr' in last_candle and last_candle['atr'] > 0:
            return (last_candle['atr'] * self.atr_multiplier.value) / current_rate
        
        # Fallback to the stoploss defined in the exit space or static default
        return self.stoploss

    def leverage(self, **kwargs) -> float:
        return 3.0