# source: https://raw.githubusercontent.com/ak4noir/freqtrade-strategies/2f02b6510af8dddbdfeabb09bdc8c5609de8ff53/user_data/strategies/stoch_rsi_tema.py
from functools import reduce

import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np  # noqa
import pandas as pd  # noqa
import talib.abstract as ta
from freqtrade.strategy import CategoricalParameter, IntParameter, IStrategy
from pandas import DataFrame


class Github_ak4noir_freqtrade_strategies__stoch_rsi_tema__20240407_180126(IStrategy):
    # 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

    """
    PASTE OUTPUT FROM HYPEROPT HERE
    """
    # Buy hyperspace params:
    buy_params = {
        "cci_lower_band": -175,
        "cci_period": 72,
        "rsi_lower_band": 36,
        "rsi_period": 15,
        "stoch_lower_band": 48,
    }

    # Sell hyperspace params:
    sell_params = {"tema_period": 5, "tema_trigger": "close"}

    # ROI table:
    minimal_roi = {"0": 0.19503, "13": 0.09149, "36": 0.02891, "64": 0}

    # Stoploss:
    stoploss = -0.02205

    # Trailing stop:
    trailing_stop = True
    trailing_stop_positive = 0.17251
    trailing_stop_positive_offset = 0.2516
    trailing_only_offset_is_reached = False
    """
    END HYPEROPT
    """

    # cci params
    cci_period = IntParameter(5, 30, default=15, space="buy")
    cci_lower_band = IntParameter(-100, 0, default=-50, space="buy")

    # rsi params
    rsi_period = IntParameter(5, 30, default=15, space="buy")
    rsi_lower_band = IntParameter(30, 50, default=40, space="buy")

    # tema params
    tema_period = IntParameter(5, 45, default=9, space="sell")
    tema_trigger = CategoricalParameter(
        ["close", "both", "average"], default="close", space="sell"
    )

    # stochastic rsi params
    stoch_fastk_period = IntParameter(7, 21, default=14, space="buy", optimize=False)
    stoch_slowk_period = IntParameter(1, 5, default=3, space="buy", optimize=False)
    stoch_slowd_period = IntParameter(1, 5, default=3, space="buy", optimize=False)
    stoch_lower_band = IntParameter(20, 50, default=30, space="buy", optimize=False)

    # make sure these match or are not overridden in config
    use_exit_signal = True
    exit_profit_only = True
    sell_profit_offset = 0.01
    ignore_roi_if_buy_signal = False

    timeframe = "5m"

    # run "populate_indicators()" only for new candle.
    process_only_new_candles: bool = False

    # number of candles the strategy requires before producing valid signals
    # set this to the highest period value in the indicator_params dict or highest of the ranges in the hyperopt settings (default: 72)
    startup_candle_count: int = 50

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        for val in self.cci_period.range:
            dataframe[f"cci({val})"] = ta.CCI(dataframe, timeframe=val)

        for val in self.rsi_period.range:
            dataframe[f"rsi({val})"] = ta.RSI(dataframe, timeperiod=val)

        for val in self.tema_period.range:
            dataframe[f"tema({val})"] = ta.TEMA(dataframe, timeperiod=val)

        # Stochastic Slow
        # fastk_period=5, slowk_period=3, slowk_matype=0, slowd_period=3, slowd_matype=0)
        stoch_slow = ta.STOCH(
            dataframe,
            fastk_period=self.stoch_fastk_period.value,
            slowk_period=self.stoch_slowk_period.value,
            slowd_period=self.stoch_slowd_period.value,
        )
        dataframe["stoch_slowk"] = stoch_slow["slowk"]
        dataframe["stoch_slowd"] = stoch_slow["slowd"]

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        conditions.append(
            dataframe[f"rsi({self.rsi_period.value})"] > self.rsi_lower_band.value
        )
        conditions.append(
            dataframe[f"cci({self.cci_period.value})"] > self.cci_lower_band.value
        )
        conditions.append(
            qtpylib.crossed_above(dataframe["stoch_slowd"], self.stoch_lower_band.value)
        )
        conditions.append(
            qtpylib.crossed_above(dataframe["stoch_slowk"], self.stoch_lower_band.value)
        )
        conditions.append(
            qtpylib.crossed_above(dataframe["stoch_slowk"], dataframe["stoch_slowd"])
        )

        # Check that the candle had volume
        conditions.append(dataframe["volume"] > 0)

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), "enter_long"] = 1

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        conditions = []

        if self.tema_trigger.value == "close":
            conditions.append(
                dataframe["close"] < dataframe[f"tema({self.tema_period.value})"]
            )
        if self.tema_trigger.value == "both":
            conditions.append(
                (dataframe["close"] < dataframe[f"tema({self.tema_period.value})"])
                & (dataframe["open"] < dataframe[f"tema({self.tema_period.value})"])
            )
        if self.tema_trigger.value == "average":
            conditions.append(
                ((dataframe["close"] + dataframe["open"]) / 2)
                < dataframe[f"tema({self.tema_period.value})"]
            )

        # Check that the candle had volume
        conditions.append(dataframe["volume"] > 0)

        if conditions:
            dataframe.loc[reduce(lambda x, y: x & y, conditions), "exit_long"] = 1

        return dataframe
