# source: https://raw.githubusercontent.com/1amcord/freqtrade_settings/b078a9d66f5e88f6ad18d35066241aaf91c31032/strategies/RsiQuickStrat.py
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from functools import reduce
from pandas import DataFrame
# --------------------------------
from datetime import datetime
from datetime import timedelta

import pandas as pd
import talib.abstract as ta
import numpy as np
import freqtrade.vendor.qtpylib.indicators as qtpylib
import datetime
from technical.util import resample_to_interval, resampled_merge
from technical.indicators import atr
from freqtrade.strategy import DecimalParameter, IntParameter, BooleanParameter, merge_informative_pair, stoploss_from_open
from technical.util import resample_to_interval, resampled_merge
from freqtrade.persistence import Trade

import logging
logger = logging.getLogger(__name__)


rangeUpper = 60
rangeLower = 5

use_sell_signal = True
sell_profit_only = False
ignore_roi_if_buy_signal = False

# Elliot Wave Oscillator


def EWO(dataframe, sma1_length=5, sma2_length=35):
    df = dataframe.copy()
    sma1 = ta.SMA(df, timeperiod=sma1_length)
    sma2 = ta.SMA(df, timeperiod=sma2_length)
    smadif = (sma1 - sma2) / df['close'] * 100
    return smadif


def valuewhen(dataframe, condition, source, occurrence):
    copy = dataframe.copy()
    copy['colFromIndex'] = copy.index
    copy = copy.sort_values(
        by=[condition, 'colFromIndex'], ascending=False).reset_index(drop=True)
    copy['valuewhen'] = np.where(
        copy[condition] > 0, copy[source].shift(-occurrence), copy[source])
    copy['barrsince'] = copy['colFromIndex'] - \
        copy['colFromIndex'].shift(-occurrence)
    copy.loc[
        (
            (rangeLower <= copy['barrsince']) &
            (copy['barrsince'] <= rangeUpper)
        ), "in_range"] = 1
    copy['in_range'] = copy['in_range'].fillna(0)
    copy = copy.sort_values(by=['colFromIndex'],
                            ascending=True).reset_index(drop=True)
    return copy['valuewhen'], copy['in_range']


class github_1amcord_freqtrade_settings__RsiQuickStrat__20220814_101522(IStrategy):
    INTERFACE_VERSION = 2

    # Optimal timeframe for the strategy
    timeframe = '5m'
    inf_tf = '1h'


    # Buy hyperspace params:
    buy_params = {
        'use_bull': False,
        'use_hidden_bull': False,
        'use_rsi_smma_buy': True,
        "high_rsi_buy": 49,
        "high_smma_rsi_buy": 42,
        "ewo_rol_bull_buy": 1,
        "ewo_rol_smma_buy": 2,
    }
    # Sell hyperspace params:
    sell_params = {
        'low_ewo_sell': 1.9,
        'ewo_rol_sell': 4,
    }

    # ROI table:
    minimal_roi = {
        "0": 10,
    }

    # Stoploss:
    stoploss = -0.272

    # Trailing stop:
    trailing_stop = False
    trailing_stop_positive = 0.33
    trailing_stop_positive_offset = 0.42200000000000004
    trailing_only_offset_is_reached = True
    use_custom_stoploss = True

    # Enable/Disable crit
    use_bull = BooleanParameter(
        default=buy_params['use_bull'], space='buy', optimize=False)
    use_hidden_bull = BooleanParameter(
        default=buy_params['use_hidden_bull'], space='buy', optimize=False)
    use_rsi_smma_buy = BooleanParameter(
        default=buy_params['use_rsi_smma_buy'], space='buy', optimize=False)

    # EWO sell crit
    low_ewo_sell = DecimalParameter(
        0, 2, decimals=1, default=sell_params['low_ewo_sell'], space='sell', optimize=False)
    ewo_rol_sell = IntParameter(
        1, 4, default=sell_params['ewo_rol_sell'], space='sell', optimize=False)

    # EWO buy crit
    high_smma_rsi_buy = IntParameter(
        15, 50, default=buy_params['high_smma_rsi_buy'], space='buy', optimize=True)
    ewo_rol_smma_buy = IntParameter(
        1, 4, default=buy_params['ewo_rol_smma_buy'], space='buy', optimize=True)

    # Bull Buy crit
    ewo_rol_bull_buy = IntParameter(
        1, 4, default=buy_params['ewo_rol_bull_buy'], space='buy', optimize=False)
    high_rsi_buy = IntParameter(
        20, 50, default=buy_params['high_rsi_buy'], space='buy', optimize=False)

    # Protection
    fast_ewo = 5
    slow_ewo = 35

    # Number of candles the strategy requires before producing valid signals
    startup_candle_count: int = 50

    osc = 'RSI'
    src = 'close'
    lbL = 40
    lbR = 5

    @property
    def plot_config(self):
        return {
            # Main plot indicators (Moving averages, ...)
            'main_plot': {
                # 'resample_360_sar': {'color': 'lightblue'},
                # 'fastd': {'color': 'lightblue'},
                # f'sl_10_{self.atr_len.value}_{self.atr_multiplier_profit_10.value}': {'color': '#ffd700'},
                # f'sl_5_{self.atr_len.value}_{self.atr_multiplier_profit_5.value}': {'color': '#fcf75e'},
                # f'sl_0_{self.atr_len.value}_{self.atr_multiplier_profit.value}': {'color': '#fdfd96'},
                # f'sl_below_0_{self.atr_len.value}_{self.atr_multiplier_no_profit.value}': {'color': '#c3b091'},
                # 'sar_4h': {'color': 'blue'},
            },
            'subplots': {
                # Subplots - each dict defines one additional plot
                "RSI": {
                    'RSI': {'color': 'red'},
                    'SMMA': {'color': 'yellow'}
                }
            }
        }

    def informative_pairs(self):
        pairs = self.dp.current_whitelist()
        informative_pairs = [(pair, self.informative_timeframe) for pair in pairs]
        informative_pairs.extend([(pair, self.inf_tf) for pair in pairs])
        return informative_pairs

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

        # RSI
        dataframe['RSI'] = ta.RSI(dataframe, timeperiod=14)

        # SMMA
        dataframe['SMMA'] = ta.SMA(
            ta.RSI(dataframe, timeperiod=5).rolling(3).mean(), period=14
        )

        # Elliot
        dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)

        # dataframe['osc'] = dataframe[self.osc]

        # # plFound = na(pivotlow(osc, lbL, lbR)) ? false: true
        # dataframe['min'] = dataframe['osc'].rolling(self.lbL).min()
        # dataframe['prevMin'] = np.where(dataframe['min'] > dataframe['min'].shift(
        # ), dataframe['min'].shift(), dataframe['min'])
        # dataframe.loc[
        #     (
        #         (dataframe['osc'].shift(1) == dataframe['prevMin'].shift(1)) &
        #         (dataframe['osc'] != dataframe['prevMin'])
        #     ), 'plFound'] = 1

        # # phFound = na(pivothigh(osc, lbL, lbR)) ? false : true
        # dataframe['max'] = dataframe['osc'].rolling(self.lbL).max()
        # dataframe['prevMax'] = np.where(dataframe['max'] < dataframe['max'].shift(
        # ), dataframe['max'].shift(), dataframe['max'])
        # dataframe.loc[
        #     (
        #         (dataframe['osc'].shift(1) == dataframe['prevMax'].shift(1)) &
        #         (dataframe['osc'] != dataframe['prevMax'])
        #     ), 'phFound'] = 1

        # # ------------------------------------------------------------------------------
        # # Regular Bullish
        # # Osc: Higher Low
        # # oscHL = osc[lbR] > valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
        # dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(
        #     dataframe, 'plFound', 'osc', 1)
        # dataframe.loc[
        #     (
        #         (dataframe['osc'] > dataframe['valuewhen_plFound_osc']) &
        #         (dataframe['inrange_plFound_osc'] == 1)
        #     ), 'oscHL'] = 1

        # # Price: Lower Low
        # # priceLL = low[lbR] < valuewhen(plFound, low[lbR], 1)
        # dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(
        #     dataframe, 'plFound', 'low', 1)
        # dataframe.loc[
        #     (dataframe['low'] < dataframe['valuewhen_plFound_low']), 'priceLL'] = 1
        # # bullCond = plotBull and priceLL and oscHL and plFound
        # dataframe.loc[
        #     (
        #         (dataframe['priceLL'] == 1) &
        #         (dataframe['oscHL'] == 1) &
        #         (dataframe['plFound'] == 1)
        #     ), 'bullCond'] = 1

        # # plot(
        # #      plFound ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Regular Bullish",
        # #      linewidth=2,
        # #      color=(bullCond ? bullColor : noneColor)
        # #      )

        # # plotshape(
        # #      bullCond ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Regular Bullish Label",
        # #      text=" Bull ",
        # #      style=shape.labelup,
        # #      location=location.absolute,
        # #      color=bullColor,
        # #      textcolor=textColor
        # #      )

        # # //------------------------------------------------------------------------------
        # # // Hidden Bullish
        # # // Osc: Lower Low
        # #
        # # oscLL = osc[lbR] < valuewhen(plFound, osc[lbR], 1) and _inRange(plFound[1])
        # dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(
        #     dataframe, 'plFound', 'osc', 1)
        # dataframe.loc[
        #     (
        #         (dataframe['osc'] < dataframe['valuewhen_plFound_osc']) &
        #         (dataframe['inrange_plFound_osc'] == 1)
        #     ), 'oscLL'] = 1
        # #
        # # // Price: Higher Low
        # #
        # # priceHL = low[lbR] > valuewhen(plFound, low[lbR], 1)
        # dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(
        #     dataframe, 'plFound', 'low', 1)
        # dataframe.loc[
        #     (dataframe['low'] > dataframe['valuewhen_plFound_low']), 'priceHL'] = 1
        # # hiddenBullCond = plotHiddenBull and priceHL and oscLL and plFound
        # dataframe.loc[
        #     (
        #         (dataframe['priceHL'] == 1) &
        #         (dataframe['oscLL'] == 1) &
        #         (dataframe['plFound'] == 1)
        #     ), 'hiddenBullCond'] = 1
        # #
        # # plot(
        # #      plFound ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Hidden Bullish",
        # #      linewidth=2,
        # #      color=(hiddenBullCond ? hiddenBullColor : noneColor)
        # #      )
        # #
        # # plotshape(
        # #      hiddenBullCond ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Hidden Bullish Label",
        # #      text=" H Bull ",
        # #      style=shape.labelup,
        # #      location=location.absolute,
        # #      color=bullColor,
        # #      textcolor=textColor
        # #      )
        # #
        # # //------------------------------------------------------------------------------
        # # // Regular Bearish
        # # // Osc: Lower High
        # #
        # # oscLH = osc[lbR] < valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
        # dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(
        #     dataframe, 'phFound', 'osc', 1)
        # dataframe.loc[
        #     (
        #         (dataframe['osc'] < dataframe['valuewhen_phFound_osc']) &
        #         (dataframe['inrange_phFound_osc'] == 1)
        #     ), 'oscLH'] = 1
        # #
        # # // Price: Higher High
        # #
        # # priceHH = high[lbR] > valuewhen(phFound, high[lbR], 1)
        # dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(
        #     dataframe, 'phFound', 'high', 1)
        # dataframe.loc[
        #     (dataframe['high'] > dataframe['valuewhen_phFound_high']), 'priceHH'] = 1
        # #
        # # bearCond = plotBear and priceHH and oscLH and phFound
        # dataframe.loc[
        #     (
        #         (dataframe['priceHH'] == 1) &
        #         (dataframe['oscLH'] == 1) &
        #         (dataframe['phFound'] == 1)
        #     ), 'bearCond'] = 1
        # #
        # # plot(
        # #      phFound ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Regular Bearish",
        # #      linewidth=2,
        # #      color=(bearCond ? bearColor : noneColor)
        # #      )
        # #
        # # plotshape(
        # #      bearCond ? osc[lbR] : na,
        # #      offset=-lbR,
        # #      title="Regular Bearish Label",
        # #      text=" Bear ",
        # #      style=shape.labeldown,
        # #      location=location.absolute,
        # #      color=bearColor,
        # #      textcolor=textColor
        # #      )
        # #
        # # //------------------------------------------------------------------------------
        # # // Hidden Bearish
        # # // Osc: Higher High
        # #
        # # oscHH = osc[lbR] > valuewhen(phFound, osc[lbR], 1) and _inRange(phFound[1])
        # dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(
        #     dataframe, 'phFound', 'osc', 1)
        # dataframe.loc[
        #     (
        #         (dataframe['osc'] > dataframe['valuewhen_phFound_osc']) &
        #         (dataframe['inrange_phFound_osc'] == 1)
        #     ), 'oscHH'] = 1
        # #
        # # // Price: Lower High
        # #
        # # priceLH = high[lbR] < valuewhen(phFound, high[lbR], 1)
        # dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(
        #     dataframe, 'phFound', 'high', 1)
        # dataframe.loc[
        #     (dataframe['high'] < dataframe['valuewhen_phFound_high']), 'priceLH'] = 1
        # #
        # # hiddenBearCond = plotHiddenBear and priceLH and oscHH and phFound
        # dataframe.loc[
        #     (
        #         (dataframe['priceLH'] == 1) &
        #         (dataframe['oscHH'] == 1) &
        #         (dataframe['phFound'] == 1)
        #     ), 'hiddenBearCond'] = 1

        return dataframe

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

        conditions = []

        # if self.use_bull.value:
        # conditions.append(
        #     (
        #         (dataframe['bullCond'] > 0) &
        #         (dataframe['EWO'] > dataframe['EWO'].shift(1).rolling(self.ewo_rol_bull_buy.value).max()) &
        #         (dataframe['RSI'] < self.high_rsi_buy.value)
        #     )
        # )

        # if self.use_hidden_bull.value:
        #     conditions.append(
        #         (
        #             (dataframe['hiddenBullCond'] > 0) &
        #             (dataframe['EWO'] > dataframe['EWO'].shift(1).rolling(self.ewo_rol_bull_buy.value).max()) &
        #             (dataframe['RSI'] < self.high_rsi_buy.value) &
        #             (dataframe['volume'] > 0)
        #         )
        #     )

        # if self.use_rsi_smma_buy.value:
        conditions.append(
            (dataframe['EWO'] > dataframe['EWO'].shift(1).rolling(self.ewo_rol_smma_buy.value).max()) &
            (dataframe['RSI'] < self.high_smma_rsi_buy.value) &
            (qtpylib.crossed_above(dataframe['RSI'], dataframe['SMMA']))
        )

        conditions.append(
            (dataframe['volume'] > 0)
        )

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

        return dataframe

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

        conditions = []

        conditions.append(
            (dataframe['EWO'] > self.low_ewo_sell.value) &
            (dataframe['EWO'] < dataframe['EWO'].shift(1).rolling(self.ewo_rol_sell.value).min()) &
            (dataframe['RSI'] < dataframe['SMMA']) &
            (dataframe['volume'] > 0)
        )

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

        # dataframe.to_csv('user_data/csvs/%s_%s.csv' %
        #                  (self.__class__.__name__, metadata["pair"].replace("/", "_")))

        return dataframe

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:
        sl_new = 1

        if (current_profit > 0.2):
            sl_new = 0.05
        elif (current_profit > 0.1):
            sl_new = 0.03
        elif (current_profit > 0.05):
            sl_new = 0.02
        elif (current_profit > 0.02):
            sl_new = 0.01

        return sl_new
