# source: https://raw.githubusercontent.com/geovedi/ngepet/b4b5abeba14029df3ae48b4b191b05a5c369f2a7/freqtrade/strategies/snippets/atr_trailing_stop.py
import numpy as np
from freqtrade.strategy import CategoricalParameter, IStrategy

# from freqtrade.exchange import timeframe_to_prev_date


class Github_geovedi_ngepet__atr_trailing_stop__20240226_083431(IStrategy):
    # ...
    trailing_start = CategoricalParameter(
        np.arange(0.25, 6.0, 0.25).round(2), default=1.5, space="sell"
    )

    trailing_offset = CategoricalParameter(
        np.arange(0.25, 3.0, 0.25).round(2), default=0.5, space="sell"
    )

    stop_loss_ratio = CategoricalParameter(
        np.arange(0.25, 6.0, 0.25).round(2), default=1.5, space="sell"
    )

    max_trade_day = CategoricalParameter(range(1, 30, 2), default=7, space="sell")

    def populate_indicators(self, dataframe: DataFrame, metadata: Dict) -> DataFrame:
        # ...
        dataframe["atr"] = ta.EMA(ta.ATR(dataframe, timeperiod=15), timeperiod=20)
        return dataframe

    # def populate_entry_trend(...):
    # def populate_exit_trend(...):

    def custom_exit(
        self,
        pair: str,
        trade: "Trade",
        current_time: "datetime",
        current_rate: float,
        current_profit: float,
        **kwargs,
    ):
        trade_dur = (current_time - trade.open_date_utc).days
        if trade_dur >= self.max_trade_day.value:
            return "expired"

        dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
        current_candle = dataframe.iloc[-1].squeeze()
        current_rate = current_candle["close"]

        # -- faster method; EMA-ATR should give a reasonable true range.
        atr = current_candle["atr"]

        # -- slower method; need to import timeframe_to_prev_date
        # trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
        # trade_candle = dataframe.loc[dataframe['date'] == trade_date]
        # if trade_candle.empty:
        #     return None
        # atr = trade_candle["atr"]

        stop_loss_value = self.stop_loss_ratio.value
        trailing_start_value = self.trailing_start.value
        trailing_offset_value = self.trailing_offset.value

        side = -1 if trade.is_short else 1

        stop_loss_rate = trade.open_rate - (atr * stop_loss_value * side)
        trailing_start_rate = trade.open_rate + (atr * trailing_start_value * side)
        trailing_stop_rate = (
            min(trade.open_rate, trade.min_rate + (atr * trailing_offset_value))
            if trade.is_short
            else max(trade.open_rate, trade.max_rate - (atr * trailing_offset_value))
        )

        stop_loss_trigger = (
            current_rate <= stop_loss_rate
            if not trade.is_short
            else current_rate >= stop_loss_rate
        )

        trailing_stop_trigger = (
            (current_rate <= trailing_start_rate and current_rate >= trailing_stop_rate)
            if trade.is_short
            else (
                current_rate >= trailing_start_rate
                and current_rate <= trailing_stop_rate
            )
        )

        if stop_loss_trigger:
            return "stop_loss"
        elif trailing_stop_trigger:
            return "trailing_stop"

    def custom_exit_price(
        self,
        pair: str,
        trade: Trade,
        current_time: datetime,
        proposed_rate: float,
        current_profit: float,
        exit_tag: Optional[str],
        **kwargs,
    ) -> float:
        dataframe, last_updated = self.dp.get_analyzed_dataframe(
            pair=pair, timeframe=self.timeframe
        )
        return dataframe["close"].iat[-1]
