# source: https://raw.githubusercontent.com/rmallarapu-bc/brahma/9287745fc036c2f4c00c586e598290885c2883b9/archive/Ahalya.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



# {
#   "strategy_name": "Nibbles7",
#   "params": {
#     "buy": {
#       "buy_peak_order": 77,
#       "leverage_num": 1
#     },
#     "sell": {
#       "sell_peak_order": 104
#     },
#     "protection": {
#       "cooldown_lookback": 91,
#       "max_allowed_drawdown": 0.01,
#       "max_drawdown_lookback": 71,
#       "max_drawdown_stop_duration": 36,
#       "max_drawdown_trade_limit": 2,
#       "stoploss_guard_lookback": 104,
#       "stoploss_guard_stop_duration": 97,
#       "stoploss_guard_trade_limit": 14
#     },
#     "roi": {
#       "0": 0.01
#     },
#     "stoploss": {
#       "stoploss": -0.1
#     },
#     "trailing": {
#       "trailing_stop": true,
#       "trailing_stop_positive": 0.002,
#       "trailing_stop_positive_offset": 0.003,
#       "trailing_only_offset_is_reached": true
#     }
#   },
#   "ft_stratparam_v": 1,
#   "export_time": "2022-08-25 19:16:47.632377+00:00"
# }

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

    buy_peak_order = IntParameter(10, 120, default=77, space="buy")
    sell_peak_order = IntParameter(10, 120, default=104, space="sell")

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

    # Stoploss:
    stoploss = -0.05

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.1
    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
            }
        ]

    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(range(15))) &
                    # (dataframe['date'].dt.minute  ==  0) &
                    reduce(lambda x, y: x & y, conditions_short)

                    # (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(range(15))) &
                    # (dataframe['date'].dt.minute == 0) &
                    reduce(lambda x, y: x & y, conditions_long)
                    # (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)

