# source: https://raw.githubusercontent.com/Chris6622/class-AdvancedFuturesSwingStrategy-IStrategy-/786cfa2c323feab11c072706b06cb9e4243af820/user_data/strategies/VolatilityGaussianBandsStrategy.py
from freqtrade.strategy import IStrategy, merge_informative_pair, IntParameter, DecimalParameter
from pandas import DataFrame
import numpy as np
import talib.abstract as ta

class Github_Chris6622_class_AdvancedFuturesSwingStrategy_IStrategy___VolatilityGaussianBandsStrategy__20260208_084829(IStrategy):
    INTERFACE_VERSION = 3
    can_short = False

    gaussian_length = IntParameter(5, 60, default=20, space="buy", optimize=True)
    band_distance   = DecimalParameter(0.5, 3.0, decimals=2, default=1.0, space="buy", optimize=True)

    minimal_roi = { "0": 0.03 }
    stoploss = -0.10

    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.02
    trailing_only_offset_is_reached = True

    timeframe = '5m'

    @property
    def leverage(self) -> float:
        return 3.0

    def gaussian_filter(self, src: np.ndarray, length: int, sigma: float = 10) -> np.ndarray:
        x = np.arange(length)
        center = (length - 1) / 2
        weights = np.exp(-0.5 * ((x - center) / sigma) ** 2)
        weights /= np.sum(weights)
        return np.convolve(src, weights, mode='same')

    def multi_trend(self, df: DataFrame, price_col: str = 'close', period: int = 20, mode: str = 'AVG', band_distance: float = 1.0):
        src = df[price_col].values
        g_values = []
        for step in range(21):
            length = period + step
            if length > len(src):
                break
            filtered = self.gaussian_filter(src, length)
            g_values.append(filtered)
        g_values = np.vstack(g_values)
        if mode == 'AVG':
            value = np.mean(g_values, axis=0)
        elif mode == 'MEADIAN':
            value = np.median(g_values, axis=0)
        elif mode == 'MODE':
            value = np.median(g_values, axis=0)
        else:
            value = np.mean(g_values, axis=0)
        volatility = ta.SMA(df['high'] - df['low'], timeperiod=100)
        lower_band = value - volatility * band_distance
        upper_band = value + volatility * band_distance
        close = df[price_col]
        trend = (close > upper_band).astype(int) - (close < lower_band).astype(int)
        score = (close - value) / (volatility + 1e-8)
        trend_line = np.where(trend > 0, lower_band, upper_band)
        return value, lower_band, upper_band, trend, score, trend_line

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        avg, lower, upper, trend, score, trend_line = self.multi_trend(
            dataframe,
            price_col='close',
            period=self.gaussian_length.value,
            mode='AVG',
            band_distance=self.band_distance.value
        )
        dataframe['vgb_avg'] = avg
        dataframe['vgb_lower'] = lower
        dataframe['vgb_upper'] = upper
        dataframe['vgb_trend'] = trend
        dataframe['vgb_score'] = score
        dataframe['vgb_trend_line'] = trend_line
        dataframe['vgb_crossup'] = (dataframe['close'] > trend_line) & (dataframe['close'].shift(1) <= trend_line)
        dataframe['vgb_crossdn'] = (dataframe['close'] < trend_line) & (dataframe['close'].shift(1) >= trend_line)
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # LONG ENTRY
        dataframe.loc[
            (
                (dataframe['vgb_crossup']) &
                (dataframe['vgb_trend'] > 0) &
                (dataframe['volume'] > 0)
            ),
            ['enter_long', 'enter_tag']
        ] = (1, 'vgb_long')

        # SHORT ENTRY
        dataframe.loc[
            (
                (dataframe['vgb_crossdn']) &
                (dataframe['vgb_trend'] < 0) &
                (dataframe['volume'] > 0)
            ),
            ['enter_short', 'enter_tag']
        ] = (1, 'vgb_short')

        print("Long signals:", dataframe['enter_long'].sum())
        print("Short signals:", dataframe['enter_short'].sum())

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # LONG EXIT
        dataframe.loc[
            (
                (dataframe['vgb_crossdn']) &
                (dataframe['vgb_trend'] < 0) &
                (dataframe['volume'] > 0)
            ),
            ['exit_long', 'exit_tag']
        ] = (1, 'vgb_exit_long')

        # SHORT EXIT
        dataframe.loc[
            (
                (dataframe['vgb_crossup']) &
                (dataframe['vgb_trend'] > 0) &
                (dataframe['volume'] > 0)
            ),
            ['exit_short', 'exit_tag']
        ] = (1, 'vgb_exit_short')

        # --- Debug print statements ---
        print("Long exits:", dataframe['exit_long'].sum())
        print("Short exits:", dataframe['exit_short'].sum())

        return dataframe