# source: https://raw.githubusercontent.com/jerome-benoit/freqai-strategies/29af7509cfbc2277200e94b69e215ddd5bf9e333/ReforceXY/user_data/strategies/RLAgentStrategy.py
import logging
from functools import cached_property, reduce
from typing import Any

# import talib.abstract as ta
from freqtrade.freqai.RL.Base5ActionRLEnv import Actions
from freqtrade.strategy import IStrategy
from pandas import DataFrame

logger = logging.getLogger(__name__)

ACTION_COLUMN = "&-action"


class Github_jerome_benoit_freqai_strategies__RLAgentStrategy__20250810_150706(IStrategy):
    """
    Github_jerome_benoit_freqai_strategies__RLAgentStrategy__20250810_150706
    """

    INTERFACE_VERSION = 3

    minimal_roi = {"0": 0.03}

    process_only_new_candles = True

    stoploss = -0.02
    # # Trailing stop:
    # trailing_stop = False
    # trailing_stop_positive = 0.01
    # trailing_stop_positive_offset = 0.011
    # trailing_only_offset_is_reached = True

    startup_candle_count: int = 300

    # @cached_property
    # def protections(self) -> list[dict[str, Any]]:
    #     fit_live_predictions_candles = int(
    #         self.freqai_info.get("fit_live_predictions_candles", 100)
    #     )
    #     estimated_trade_duration_candles = int(
    #         self.config.get("estimated_trade_duration_candles", 36)
    #     )
    #     stoploss_guard_lookback_period_candles = int(fit_live_predictions_candles / 2)
    #     stoploss_guard_trade_limit = max(
    #         1,
    #         int(
    #             round(
    #                 (
    #                     stoploss_guard_lookback_period_candles
    #                     / estimated_trade_duration_candles
    #                 )
    #                 * 0.75
    #             )
    #         ),
    #     )
    #     return [
    #         {"method": "CooldownPeriod", "stop_duration_candles": 4},
    #         {
    #             "method": "MaxDrawdown",
    #             "lookback_period_candles": fit_live_predictions_candles,
    #             "trade_limit": 2 * self.config.get("max_open_trades"),
    #             "stop_duration_candles": fit_live_predictions_candles,
    #             "max_allowed_drawdown": 0.2,
    #         },
    #         {
    #             "method": "StoplossGuard",
    #             "lookback_period_candles": stoploss_guard_lookback_period_candles,
    #             "trade_limit": stoploss_guard_trade_limit,
    #             "stop_duration_candles": stoploss_guard_lookback_period_candles,
    #             "only_per_pair": True,
    #         },
    #     ]

    @cached_property
    def can_short(self) -> bool:
        return self.is_short_allowed()

    # def feature_engineering_expand_all(
    #     self, dataframe: DataFrame, period: int, metadata: dict[str, Any], **kwargs
    # ) -> DataFrame:
    #     dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)

    #     return dataframe

    def feature_engineering_expand_basic(
        self, dataframe: DataFrame, metadata: dict[str, Any], **kwargs
    ) -> DataFrame:
        dataframe["%-close_pct_change"] = dataframe.get("close").pct_change()
        dataframe["%-raw_volume"] = dataframe.get("volume")

        return dataframe

    def feature_engineering_standard(
        self, dataframe: DataFrame, metadata: dict[str, Any], **kwargs
    ) -> DataFrame:
        dates = dataframe.get("date")
        dataframe["%-day_of_week"] = (dates.dt.dayofweek + 1) / 7
        dataframe["%-hour_of_day"] = (dates.dt.hour + 1) / 25

        dataframe["%-raw_close"] = dataframe.get("close")
        dataframe["%-raw_open"] = dataframe.get("open")
        dataframe["%-raw_high"] = dataframe.get("high")
        dataframe["%-raw_low"] = dataframe.get("low")

        return dataframe

    def set_freqai_targets(
        self, dataframe: DataFrame, metadata: dict[str, Any], **kwargs
    ) -> DataFrame:
        dataframe[ACTION_COLUMN] = Actions.Neutral

        return dataframe

    def populate_indicators(
        self, dataframe: DataFrame, metadata: dict[str, Any]
    ) -> DataFrame:
        dataframe = self.freqai.start(dataframe, metadata, self)

        return dataframe

    def populate_entry_trend(
        self, dataframe: DataFrame, metadata: dict[str, Any]
    ) -> DataFrame:
        enter_long_conditions = [
            dataframe.get("do_predict") == 1,
            dataframe.get(ACTION_COLUMN) == Actions.Long_enter,
        ]
        dataframe.loc[
            reduce(lambda x, y: x & y, enter_long_conditions),
            ["enter_long", "enter_tag"],
        ] = (1, "long")

        enter_short_conditions = [
            dataframe.get("do_predict") == 1,
            dataframe.get(ACTION_COLUMN) == Actions.Short_enter,
        ]
        dataframe.loc[
            reduce(lambda x, y: x & y, enter_short_conditions),
            ["enter_short", "enter_tag"],
        ] = (1, "short")

        return dataframe

    def populate_exit_trend(
        self, dataframe: DataFrame, metadata: dict[str, Any]
    ) -> DataFrame:
        exit_long_conditions = [
            dataframe.get("do_predict") == 1,
            dataframe.get(ACTION_COLUMN) == Actions.Long_exit,
        ]
        dataframe.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1

        exit_short_conditions = [
            dataframe.get("do_predict") == 1,
            dataframe.get(ACTION_COLUMN) == Actions.Short_exit,
        ]
        dataframe.loc[
            reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"
        ] = 1

        return dataframe

    def is_short_allowed(self) -> bool:
        trading_mode = self.config.get("trading_mode")
        if trading_mode == "margin" or trading_mode == "futures":
            return True
        elif trading_mode == "spot":
            return False
        else:
            raise ValueError(f"Invalid trading_mode: {trading_mode}")
