# source: https://raw.githubusercontent.com/Chris6622/class-AdvancedFuturesSwingStrategy-IStrategy-/786cfa2c323feab11c072706b06cb9e4243af820/user_data/strategies/OBVEMAStrategy.py
import numpy as np
import pandas as pd
from pandas import DataFrame

from freqtrade.strategy import IStrategy, IntParameter
import talib.abstract as ta

class Github_Chris6622_class_AdvancedFuturesSwingStrategy_IStrategy___OBVEMAStrategy__20260208_084829(IStrategy):
    """
    Freqtrade strategy using only OBV and OBV_EMA (hyperoptable period).
    Long: OBV crosses above its EMA.
    Short: OBV crosses below its EMA (can_short = True).
    """

    INTERFACE_VERSION = 3
    can_short: bool = True
    timeframe = "5m"
    minimal_roi = {"0": 0.02}
    stoploss = -0.10
    trailing_stop = False
    process_only_new_candles = True
    startup_candle_count: int = 50

    # Hyperoptable parameter for OBV_EMA period
    obv_ema_period = IntParameter(5, 50, default=20, space="buy", optimize=True, load=True)

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # On-Balance Volume (OBV)
        dataframe["obv"] = ta.OBV(dataframe)
        # OBV EMA (hyperoptable period)
        dataframe["obv_ema"] = dataframe["obv"].ewm(span=self.obv_ema_period.value, adjust=False).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Long: OBV crosses above its EMA
        dataframe.loc[
            (dataframe["obv"] > dataframe["obv_ema"]) &
            (dataframe["obv"].shift(1) <= dataframe["obv_ema"].shift(1)) &
            (dataframe["volume"] > 0),
            "enter_long"
        ] = 1

        # Short: OBV crosses below its EMA (if shorts enabled)
        dataframe.loc[
            (dataframe["obv"] < dataframe["obv_ema"]) &
            (dataframe["obv"].shift(1) >= dataframe["obv_ema"].shift(1)) &
            (dataframe["volume"] > 0),
            "enter_short"
        ] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Exit long: OBV crosses below its EMA
        dataframe.loc[
            (dataframe["obv"] < dataframe["obv_ema"]) &
            (dataframe["obv"].shift(1) >= dataframe["obv_ema"].shift(1)) &
            (dataframe["volume"] > 0),
            "exit_long"
        ] = 1

        # Exit short: OBV crosses above its EMA
        dataframe.loc[
            (dataframe["obv"] > dataframe["obv_ema"]) &
            (dataframe["obv"].shift(1) <= dataframe["obv_ema"].shift(1)) &
            (dataframe["volume"] > 0),
            "exit_short"
        ] = 1

        return dataframe