# source: https://raw.githubusercontent.com/rmallarapu-bc/brahma/9287745fc036c2f4c00c586e598290885c2883b9/archive/Nibbles7.py
from datetime import datetime
from functools import reduce

import numpy as np
from freqtrade.strategy import IStrategy, DecimalParameter, IntParameter
from pandas import DataFrame
from scipy.signal import argrelextrema


class Github_rmallarapu_bc_brahma__Nibbles7__20240229_213751(IStrategy):
    timeframe = "5m"
    can_short = True
    process_only_new_candles = False

    buy_peak_order = IntParameter(10, 120, default=85, space="buy")
    sell_peak_order = IntParameter(10, 120, default=56, space="sell")

    # ROI table:
    minimal_roi = {
        "0": 0.01
    }

    # Stoploss:
    stoploss = -0.03

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.002
    trailing_stop_positive_offset = 0.005
    trailing_only_offset_is_reached = True

    protect_optimize = True
    cooldown_lookback = IntParameter(1, 240, default=5, space="protection", optimize=protect_optimize)
    max_drawdown_lookback = IntParameter(1, 288, default=12, space="protection", optimize=protect_optimize)
    max_drawdown_trade_limit = IntParameter(1, 20, default=5, space="protection", optimize=protect_optimize)
    max_drawdown_stop_duration = IntParameter(1, 288, default=12, space="protection", optimize=protect_optimize)
    max_allowed_drawdown = DecimalParameter(0.10, 0.50, default=0.20, decimals=2, space="protection",
                                            optimize=protect_optimize)
    stoploss_guard_lookback = IntParameter(1, 288, default=12, space="protection", optimize=protect_optimize)
    stoploss_guard_trade_limit = IntParameter(1, 20, default=3, space="protection", optimize=protect_optimize)
    stoploss_guard_stop_duration = IntParameter(1, 288, default=12, space="protection", optimize=protect_optimize)

    leverage_optimize = True
    leverage_num = IntParameter(low=1, high=1, default=1, space='buy', optimize=leverage_optimize)

    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 1
            },
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": 48,
                "trade_limit": 10,
                "stop_duration_candles": 4,
                "max_allowed_drawdown": 0.05
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": 2,
                "only_per_pair": False
            },
            # {
            #     "method": "LowProfitPairs",
            #     "lookback_period_candles": 6,
            #     "trade_limit": 2,
            #     "stop_duration_candles": 60,
            #     "required_profit": 0.01
            # },
            # {
            #     "method": "LowProfitPairs",
            #     "lookback_period_candles": 24,
            #     "trade_limit": 4,
            #     "stop_duration_candles": 2,
            #     "required_profit": 0.005
            # }
        ]

    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:

        return self.leverage_num.value

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        for val in self.buy_peak_order.range:
            ilocs_max = argrelextrema(dataframe['high'].values, np.greater_equal, order=val)[0]
            dataframe.loc[
                dataframe.iloc[ilocs_max].index,
                f'upper_peak_{val}'
            ] = dataframe['high']
            dataframe[f'upper_peak_{val}'].fillna(method='ffill', inplace=True)

        for val in self.sell_peak_order.range:
            ilocs_min = argrelextrema(dataframe['low'].values, np.less_equal, order=val)[0]
            dataframe.loc[
                dataframe.iloc[ilocs_min].index,
                f'lower_peak_{val}'
            ] = dataframe['low']
            dataframe[f'lower_peak_{val}'].fillna(method='ffill', inplace=True)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

        conditions_long = []
        conditions_short = []
        # #print("1 =>", dataframe)
        conditions_long.append(
            dataframe['close'] > dataframe[f'upper_peak_{self.buy_peak_order.value}'].shift(1)
        )

        conditions_short.append(
            dataframe['close'] < dataframe[f'lower_peak_{self.sell_peak_order.value}'].shift(1)
        )
        # #print("2 =>", dataframe)
        dataframe.loc[
            (
                    # (dataframe['date'].dt.hour.isin([0, 13, 14, 15, 22, 21, 23])) &
                    (dataframe['date'].dt.minute.isin([0])) &
                    reduce(lambda x, y: x & y, conditions_long)
                    # (dataframe['date'].dt.hour == 0)
            ),
            'enter_long'] = 1
        # #print("3 =>", dataframe)
        dataframe.loc[
            (
                    # (dataframe['date'].dt.hour.isin([0, 13, 14, 15, 22, 21, 23])) &
                    (dataframe['date'].dt.minute.isin([0])) &
                    reduce(lambda x, y: x & y, conditions_short)
                    # (dataframe['date'].dt.hour == 0)
            ),
            'enter_short'] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return super().populate_exit_trend(dataframe, metadata)
