# source: https://raw.githubusercontent.com/mlsys-io/PortfolioBench/305264dcb72ebb0c24ccdea477c5781ac749f7f5/strategy/MacdAdxStrategy.py
from datetime import datetime
from pandas import DataFrame

from freqtrade.strategy import (
    IStrategy,
    IntParameter,
)

import talib.abstract as ta


class Github_mlsys_io_PortfolioBench__MacdAdxStrategy__20260311_141008(IStrategy):
    """
    Strategy adapted from paper: http://arxiv.org/abs/2511.00665
    """

    # Strategy interface version - allow new iterations of the strategy interface.
    # Check the documentation or the Sample strategy to get the latest version.
    INTERFACE_VERSION = 3

    # Optimal timeframe for the strategy.
    timeframe = "5m"

    # Can this strategy go short?
    can_short: bool = False

    # Minimal ROI designed for the strategy.
    # This attribute will be overridden if the config file contains "minimal_roi".
    minimal_roi = {}

    # Optimal stoploss designed for the strategy.
    # This attribute will be overridden if the config file contains "stoploss".
    stoploss = -99

    # Trailing stoploss
    trailing_stop = False
    # trailing_only_offset_is_reached = False
    # trailing_stop_positive = 0.01
    # trailing_stop_positive_offset = 0.0  # Disabled / not configured

    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = True

    # These values can be overridden in the config.
    use_exit_signal = True
    exit_profit_only = False
    ignore_roi_if_entry_signal = False

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count: int = 30

    # Strategy parameters
    macdFast = IntParameter(8, 15, default=15, space="buy")
    macdSlow = IntParameter(20, 30, default=26, space="buy")
    macdSignal = IntParameter(7, 15, default=9, space="buy")
    adxPeriod = IntParameter(10, 20, default=15, space="buy")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        macd = ta.MACD(
            dataframe,
            fastperiod=self.macdFast.value,
            slowperiod=self.macdSlow.value,
            signalperiod=self.macdSignal.value
        )
        dataframe["macd"] = macd["macd"]
        dataframe["macdsignal"] = macd["macdsignal"]
        dataframe["adx"] = ta.ADX(dataframe, timeperiod=self.adxPeriod.value)
        dataframe["mean-volume"] = dataframe["volume"].rolling(20).mean()
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['macd'] > dataframe['macdsignal']) &
                (dataframe['adx'] > 25) & 
                (dataframe["mean-volume"] > 0.75)
            ),
            "enter_long",
        ] = 1
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (dataframe['macd'] < dataframe['macdsignal']) &
                (dataframe['adx'] > 25) & 
                (dataframe["mean-volume"] > 0.75)
            ),
            "exit_long",
        ] = 1
        return dataframe

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
                            time_in_force: str, current_time: datetime, entry_tag: str | None,
                            side: str, **kwargs) -> bool:
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_close = dataframe.iloc[-1]["close"]
        max_deviation = 0.01  # 1% deviation allowed
        deviation = abs(rate - last_close) / last_close

        if deviation > max_deviation:
            return False

        return True