# Zeus Strategy: First Generation of GodStra Strategy with maximum
# AVG/MID profit in USDT
# Author: @Mablue (Masoud Azizi)
# github: https://github.com/mablue/
# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta)
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus
# --- Do not remove these libs ---
from datetime import timedelta, datetime
from typing import Optional

from freqtrade import data
from freqtrade.persistence import Trade
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter

from numpy.lib import math
from freqtrade.strategy.interface import IStrategy
import pandas
from pandas import DataFrame
import time
import logging
import calendar
from freqtrade.loggers import setup_logging
from freqtrade.strategy.strategy_helper import merge_informative_pair

# --------------------------------

# Add your lib to import here
import ta
from functools import reduce
import numpy as np
import talib.abstract as talib
from freqtrade.strategy.strategy_helper import merge_informative_pair
import freqtrade.vendor.qtpylib.indicators as qtpylib

from random import shuffle

logger = logging.getLogger(__name__)

class Zeus_8_3_3_3(IStrategy):

    # ROI table:
    minimal_roi = {
        "0": 0.564,
        "567": 0.273,
        "2814": 0.12,
        "7675": 0
    }

    # Stoploss:
    stoploss = -1 #0.256

    # Buy hypers
    timeframe = '5m'

    market_overview = {'up': 0, 'down': 0}
    market_overview_pct5 = 0
    market_overview_pct1 = 0
    max_open_trades = 5
    max_amount = 40
    stop_buy_for_all = False
    stop_buying = {}

    # DCA config
    position_adjustment_enable = True
    #max_dca_orders = 2  # n - 1
    max_dca_multiplier = 7  # (2^n - 1)
    dca_trigger = 0

    plot_config = {
        "main_plot": {
            "min200": {
                "color": "#86c932"
            },
            "min50": {
                "color": "white"
            },
            # "max200": {
            #     "color": "yellow"
            # },
            "sma3_1d": {
                "color": "pink"
            },
            "sma5_1d": {
                "color": "blue"
            },
            "sma10_1d": {
                "color": "orange"
            },
            "close_1d": {
                "color": "#73e233",
            },
            "low": {
                "color": "cyan",
            },
            "bb_lowerband": {
                "color": "#da59a6"},
            "bb_upperband": {
                "color": "#da59a6",
            }
        },
        "subplots": {
            # "Ind": {
            #     "trend_ichimoku_base": {
            #         "color": "#dd1384"
            #     },
            #     "trend_kst_diff": {
            #         "color": "#850678"
            #     }
            # },
            # "BB": {
            #     "bb_width": {
            #         "color": "white"
            #     },
            #     "bb_lower_5": {
            #         "color": "yellow"
            #     }
            # },
            "Rsi": {
                "rsi_1d": {
                    "color": "pink"
                },
                # "rsi_1h": {
                #     "color": "green"
                # },
                "rsi5": {
                    "color": "yellow"
                },
                "rsi3_1d": {
                    "color": "red"
                }
            },
            # "Percent": {
            #     "pct_change_1_1d": {
            #         "color": "green"
            #     },
            #     "pct_change_3_1d": {
            #         "color": "orange"
            #     },
            #     "pct_change_5_1d": {
            #         "color": "red"
            #     }
            # }
        }
    }
    trades = list()

    buy_min_horizon = IntParameter(50, 200, default=72, space='buy')

    buy_rsi = IntParameter(20, 90, default=72, space='buy')
    buy_bb_width_n = DecimalParameter(1, 10, decimals=1, default=5, space='buy')

    buy_min_max_nh = IntParameter(1, 48, default=24, space='buy')
    buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy')
    buy_min_max_rsi = IntParameter(50, 90, default=72, space='buy')
    buy_min_max_coef = DecimalParameter(1, 1.01, decimals=3, default=1.002, space='buy')
    buy_min_max_decalage = IntParameter(2, 10, default=2, space='buy')

    profit_b_no_change = BooleanParameter(default=True, space="sell")
    profit_b_quick_lost = BooleanParameter(default=True, space="sell")
    profit_b_sma5 = BooleanParameter(default=True, space="sell")
    profit_b_sma10 = BooleanParameter(default=True, space="sell")
    profit_b_sma20 = BooleanParameter(default=True, space="sell")
    profit_b_quick_gain = BooleanParameter(default=True, space="sell")
    profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell")
    profit_b_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_b_over_rsi = BooleanParameter(default=True, space="sell")
    profit_b_short_loss = BooleanParameter(default=True, space="sell")

    sell_b_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')
    sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')
    sell_b_candels = IntParameter(0, 48, default=12, space='sell')

    sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell')
    sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')

    sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3,  default=0.005, space='sell')
    sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4,  default=0.001, space='sell')

    sell_b_RSI = IntParameter(70, 98, default=88, space='sell')
    sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell')
    sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell')

    sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')
    # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3,  default=0.01, space='sell')

    profit_h_no_change = BooleanParameter(default=True, space="sell")
    profit_h_quick_lost = BooleanParameter(default=True, space="sell")
    profit_h_sma5 = BooleanParameter(default=True, space="sell")
    profit_h_sma10 = BooleanParameter(default=True, space="sell")
    profit_h_sma20 = BooleanParameter(default=True, space="sell")
    profit_h_quick_gain = BooleanParameter(default=True, space="sell")
    profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell")
    profit_h_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_h_over_rsi = BooleanParameter(default=True, space="sell")
    profit_h_short_loss = BooleanParameter(default=True, space="sell")

    sell_h_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')
    sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')
    sell_h_candels = IntParameter(0, 48, default=12, space='sell')

    sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell')
    sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')

    sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3,  default=0.005, space='sell')
    sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4,  default=0.001, space='sell')

    sell_h_RSI = IntParameter(70, 98, default=88, space='sell')
    sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell')
    sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell')

    sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3,  default=0.01, space='sell')

    protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection')
    protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection')

    def calc_profit(self, price: float, current: float) -> float:
        fee = 1.0007
        profit = ((current*fee) -
            (price*fee))

        return float(f"{profit:.8f}")

    def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str,
                            current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool:
        allow_to_buy = True
        # info_previous_last_candle = informative.iloc[-2].squeeze()

        if self.stop_buying.get(pair, None) is None:
            print("enable buying tag", pair)
            self.stop_buying[pair] = False

        informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
        info_last_candle = informative.iloc[-1].squeeze()

        if ((info_last_candle['rsi_1h'] >= 76) & (info_last_candle['close_1h'] >= info_last_candle['bb_upperband_1h'])) \
                & (self.stop_buying[pair] is False):
            logger.info("1 - Disable buying %s date %s", pair, info_last_candle['date'])
            self.stop_buying[pair] = True

        if self.stop_buying[pair] is True:
            if ((info_last_candle['rsi_1h'] <= 35) | (info_last_candle['close_1h'] < info_last_candle['bb_lowerband_1h'])):
                logger.info("2 - Enable buying %s date %s", pair, info_last_candle['date'])
                self.stop_buying[pair] = False

        if self.stop_buying[pair]:
            allow_to_buy = False
            logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date'])
        else:
            logger.info("3 - accept buying %s date %s", pair, info_last_candle['date'])
        return allow_to_buy

    def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
                    current_profit: float, **kwargs):
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()
        previous_last_candle = dataframe.iloc[-2].squeeze()
        previous_previous_last_candle = dataframe.iloc[-2].squeeze()

        previous_5_candle = dataframe.iloc[-5].squeeze()

        return (previous_last_candle['rsi5'] > 60) \
            & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \
            & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']) \
            & (last_candle['close'] > last_candle['close_1d']) & (last_candle['percent'] < 0)

    #     expected_profit = 0.01
    #     #print(last_candle['buy_tag'])
    #
    #     days = (current_time - trade.open_date_utc).days
    #     ######
    #
    #     if (last_candle['mrsi3_1h'] < previous_last_candle['mrsi3_1h']): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0):
    #         max_percent = 0.004  # last_candle['bb_width'] / 3.5  # 0.005
    #         max_profit = 0.004  # last_candle['bb_width'] * 3 / 4 # 0.015
    #
    #         if (current_profit > 0.01) & \
    #                 (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600):
    #             return 'b_percent10'
    #         if (current_profit > max_profit) & \
    #                 ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | (
    #                         last_candle['percent5'] < -max_percent)):
    #             return 'b_percent_quick'
    #
    #         if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\
    #                 & (days < self.sell_b_too_old_day.value * 2)\
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "b_too_old_0.01"
    #         if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\
    #             & (days < self.sell_b_too_old_day.value * 3) \
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "b_too_old_0.02"
    #         if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "b_too_old_0.03"
    #
    #         if self.profit_b_quick_lost.value and (current_profit >= max_profit) & (
    #                 last_candle['percent3'] < -max_percent):
    #             return "b_quick_lost"
    #
    #         if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \
    #                 & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \
    #                 & ((current_time - trade.open_date_utc).seconds >= 3600):
    #             return "b_no_change"
    #
    #         if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \
    #                 & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value):
    #             return "b_quick_gain_param"
    #
    #         if self.profit_b_sma5.value:
    #             if (current_profit > expected_profit) \
    #                     & ((previous_5_candle['sma5'] > last_candle['sma5']) \
    #                        | (last_candle['percent3'] < -expected_profit) | (
    #                                last_candle['percent5'] < -expected_profit)) \
    #                     & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_sma5'
    #
    #         if self.profit_b_sma10.value:
    #             if (current_profit > expected_profit) \
    #                     & ((previous_5_candle['sma10'] > last_candle['sma10']) \
    #                        | (last_candle['percent3'] < -expected_profit) | (
    #                                last_candle['percent5'] < -expected_profit)) \
    #                     & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_sma10'
    #
    #         if self.profit_b_sma20.value:
    #             if (current_profit > max_percent) \
    #                     & (previous_last_candle['sma10'] > last_candle['sma10']) \
    #                     & ((current_time - trade.open_date_utc).seconds >= 3600) \
    #                     & ((previous_last_candle['sma20'] > last_candle['sma20']) &
    #                        ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (
    #                                last_candle['percent20'] < 0))):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_sma20'
    #
    #         if self.profit_b_over_rsi.value:
    #             if (current_profit > 0) & (previous_last_candle[
    #                                            'rsi'] > self.sell_b_RSI.value):  # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_over_rsi'
    #
    #             if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \
    #                     (last_candle[
    #                          'percent'] < - self.sell_b_RSI2_percent.value):  # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_over_rsi_2'
    #
    #             if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \
    #                     (last_candle['close'] >= last_candle['max200']) & (last_candle[
    #                                                                            'percent'] < - self.sell_b_RSI2_percent.value):  # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_over_rsi_max'
    #
    #         if self.profit_b_short_loss.value:
    #             if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (
    #                     last_candle['percent'] < 0) \
    #                     & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'b_short_lost'
    #     else:
    #         max_percent = 0.005  # last_candle['bb_width'] / 3.5  # 0.005
    #         max_profit = 0.01  # last_candle['bb_width'] * 3 / 4 # 0.015
    #
    #         if (current_profit > max_profit) & (
    #                 (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (
    #                 last_candle['percent5'] < -max_percent)):
    #             return 'h_percent_quick'
    #
    #         # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \
    #         #     ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)):
    #         #     return 'h_bb_width_max'
    #
    #         if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\
    #                 & (days < self.sell_h_too_old_day.value * 2)\
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "h_too_old_0.01"
    #         if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\
    #             & (days < self.sell_h_too_old_day.value * 3) \
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "h_too_old_0.02"
    #         if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \
    #                 & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
    #             return "h_too_old_0.03"
    #
    #         if self.profit_h_quick_lost.value and (current_profit >= max_profit) & (
    #                 last_candle['percent3'] < -max_percent):
    #             return "h_quick_lost"
    #
    #         if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \
    #                 & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \
    #                 & ((current_time - trade.open_date_utc).seconds >= 3600):
    #             return "h_no_change"
    #
    #         if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \
    #                 & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value):
    #             return "h_quick_gain_param"
    #
    #         if self.profit_h_sma5.value:
    #             if (current_profit > expected_profit) \
    #                     & ((previous_5_candle['sma5'] > last_candle['sma5']) \
    #                        | (last_candle['percent3'] < -expected_profit) | (
    #                                last_candle['percent5'] < -expected_profit)) \
    #                     & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_sma5'
    #
    #         if self.profit_h_sma10.value:
    #             if (current_profit > expected_profit) \
    #                     & ((previous_5_candle['sma10'] > last_candle['sma10']) \
    #                        | (last_candle['percent3'] < -expected_profit) | (
    #                                last_candle['percent5'] < -expected_profit)) \
    #                     & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_sma10'
    #
    #         if self.profit_h_sma20.value:
    #             if (current_profit > max_percent) \
    #                     & (previous_last_candle['sma10'] > last_candle['sma10']) \
    #                     & ((current_time - trade.open_date_utc).seconds >= 3600) \
    #                     & ((previous_last_candle['sma20'] > last_candle['sma20']) &
    #                        ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (
    #                                last_candle['percent20'] < 0))):
    #                 # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_sma20'
    #
    #         if self.profit_h_over_rsi.value:
    #             if (current_profit > 0) & (previous_last_candle[
    #                                            'rsi'] > self.sell_h_RSI.value):  # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_over_rsi'
    #
    #             if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \
    #                     (last_candle[
    #                          'percent'] < - self.sell_h_RSI2_percent.value):  # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_over_rsi_2'
    #
    #             if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \
    #                     (last_candle['close'] >= last_candle[
    #                         'max200']):  # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_over_rsi_max'
    #
    #         if self.profit_h_short_loss.value:
    #             if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (
    #                     last_candle['percent'] < 0) \
    #                     & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
    #                 # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
    #                 return 'h_short_lost'

    def informative_pairs(self):
        # get access to all pairs available in whitelist.
        pairs = self.dp.current_whitelist()
        informative_pairs = [(pair, '1d') for pair in pairs]
        # informative_pairs += [(pair, '4h') for pair in pairs]
        informative_pairs += [(pair, '1h') for pair in pairs]

        return informative_pairs

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # Add all ta features
        dataframe['pct_change'] = dataframe['close'].pct_change(5)
        dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value)
        dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10)
        dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20)
        dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50)
        dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200)
        dataframe['min200_1'] = dataframe['min200'] * 1.005
        dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() 

        dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50)
        dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200)
        dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200']  
        dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value)
        dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value)
        dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n']
        dataframe['rsi'] = talib.RSI(dataframe)
        dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5)
        dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5)
        dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10)
        dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20)
        dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50)
        dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100)
        dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
        dataframe["percent5"] = dataframe["percent"].rolling(5).sum()
        dataframe["percent3"] = dataframe["percent"].rolling(3).sum()
        dataframe["percent10"] = dataframe["percent"].rolling(10).sum()
        dataframe["percent20"] = dataframe["percent"].rolling(20).sum()
        dataframe["percent50"] = dataframe["percent"].rolling(50).sum()
        # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum()
        dataframe["volume10"] = dataframe["volume"].rolling(10).mean()
        # Bollinger Bands
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe['bb_lowerband'] = bollinger['lower']
        dataframe['bb_middleband'] = bollinger['mid']
        dataframe['bb_upperband'] = bollinger['upper']
        dataframe["bb_percent"] = (
            (dataframe["close"] - dataframe["bb_lowerband"]) /
            (dataframe["bb_upperband"] - dataframe["bb_lowerband"])
        )
        dataframe["bb_width"] = (
            (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
        )
        dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var()
        dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1)
        dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value))

        dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
        dataframe['min1.1'] = 1.01 * dataframe['min']
        dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean())
        dataframe['min_max_close'] = (
                    (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200']))

        # profit = False
        # profit_percent = False
        # percent_lower = False
        # current_price = dataframe['close'].iloc[-1]
        #
        # dataframe['should_sell'] = False
        # dataframe['should_buy'] = False
        #
        # # Get the previous trade
        # trade = Trade.get_trades_proxy(is_open=False, pair=metadata['pair'])
        # if trade:
        #     trade = trade[-1]
        #     lsp = trade.close_rate
        #     if lsp:
        #         percent_lower = self.calc_percentage_lower(price=lsp, current=current_price)
        #     # Found a bug? When force selling it doesnt close it
        #     else:
        #         lsp = trade.open_rate
        #         if lsp:
        #             percent_lower = self.calc_percentage_lower(price=lsp, current=current_price)
        # else:
        #     lsp = 0.00
        #
        # # Get the current Trade
        # trade = Trade.get_trades_proxy(is_open=True, pair=metadata['pair'])
        # if trade:
        #     trade = trade[-1]
        #     lbp = trade.open_rate
        #     open_trade = True
        #     profit = self.calc_profit(price=lbp, current=current_price)
        #     profit_percent = (profit/lbp)*100
        # else:
        #     lbp = 0.00
        #     open_trade = False
        #     profit = False
        #     profit_percent = False
        #
        # print("------------")
        #
        # print("Last Sold For:", lsp)
        #
        # if open_trade:
        #     print("Bought for: ", lbp)
        # print("Current Price: ", current_price)
        # if profit:
        #     print("Current Profit: ", profit, " ", float(f"{profit_percent:.8f}"), "%")
        # if percent_lower and not open_trade:
        #     print("Percent Lower: ", float(f"{percent_lower:.8f}"), "%")
        #
        # # Should we Sell?
        # if profit_percent:
        #     if profit_percent > 1:
        #         dataframe['should_sell'] = True
        #
        # # Should we buy?
        # if not open_trade:
        #     if (lsp == 0.00 ) & (lbp == 0.00):
        #         dataframe['should_buy'] = True
        #     # Is the percentage of what we sold for and the current price 2% lower
        #     if percent_lower > 2:
        #         dataframe['should_buy'] = True
        #
        # dataframe['last_sell_price'] = lsp
        # dataframe['last_buy_price'] = lbp

        ################### INFORMATIVE 1D
        informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
        informative["rsi"] = talib.RSI(informative)
        informative["rsi3"] = talib.RSI(informative, 3)
        informative["mrsi3"] = informative["rsi"].rolling(3).mean()
        informative["max3"] = talib.MAX(informative['close'], timeperiod=3)
        informative["min3"] = talib.MIN(informative['close'], timeperiod=3)
        informative['pct_change_1'] = informative['close'].pct_change(1)
        informative['pct_change_3'] = informative['close'].pct_change(3)
        informative['pct_change_5'] = informative['close'].pct_change(5)
        informative['sma3'] = talib.SMA(informative, timeperiod=3)
        informative['sma5'] = talib.SMA(informative, timeperiod=5)
        informative['sma10'] = talib.SMA(informative, timeperiod=10)
        informative['sar'] = talib.SAR(informative)

        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2)
        informative['bb_lowerband'] = bollinger['lower']
        informative['bb_middleband'] = bollinger['mid']
        informative['bb_upperband'] = bollinger['upper']
        informative["bb_percent"] = (
            (informative["close"] - informative["bb_lowerband"]) /
            (informative["bb_upperband"] - informative["bb_lowerband"])
        )
        informative["bb_width"] = (
            (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"]
        )

        dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)

        # ######################## INFORMATIVE 4h
        # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h")
        # informative["rsi"] = talib.RSI(informative)
        # informative['pct_change_1'] = informative['close'].pct_change(1)
        # informative['pct_change_3'] = informative['close'].pct_change(3)
        # informative['pct_change_5'] = informative['close'].pct_change(5)
        # informative['sma3'] = talib.SMA(informative, timeperiod=3)
        # informative['sma5'] = talib.SMA(informative, timeperiod=5)
        # informative['sma10'] = talib.SMA(informative, timeperiod=10)
        # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True)

        ######################## INFORMATIVE 1h
        informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h")
        informative["rsi"] = talib.RSI(informative)
        informative["rsi3"] = talib.RSI(informative, 3)
        informative["mrsi3"] = informative["rsi"].rolling(3).mean()
        informative['pct_change_1'] = informative['close'].pct_change(1)
        informative['pct_change_3'] = informative['close'].pct_change(3)
        informative['pct_change_5'] = informative['close'].pct_change(5)
        informative['sma3'] = talib.SMA(informative, timeperiod=3)
        informative['sma5'] = talib.SMA(informative, timeperiod=5)
        informative['sma10'] = talib.SMA(informative, timeperiod=10)
        bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2)
        informative['bb_lowerband'] = bollinger['lower']
        informative['bb_middleband'] = bollinger['mid']
        informative['bb_upperband'] = bollinger['upper']

        dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True)

        return dataframe

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

        dataframe.loc[
            (
                # (dataframe['min_max_n'] >= self.buy_min_max_n.value)
                    (dataframe['rsi5'].shift(1) < 12)
                & (dataframe['rsi5'].shift(1) < dataframe['rsi5'])
                & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2))
                # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value)
                #& (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n'])
                # & (dataframe['pct_change_1_1d'] > 0)
                & (dataframe['close'] <= dataframe['close_1d'])
                & (dataframe['close_1d'] <= dataframe['sma3_1d'])
                & (dataframe['close_1d'] <= dataframe['sma5_1d'])
                & (dataframe['close_1d'] <= dataframe['sma10_1d'])
                & (dataframe['low'] <= dataframe['min200'])
                & (dataframe['min'].shift(2) == dataframe['min50'])
                # & (dataframe['rsi3_1d'].shift(288) <= dataframe['rsi3_1d'])
            ), ['buy', 'buy_tag']] = (1, 'buy_rsi5')

        return dataframe

    # def bot_loop_start(self, **kwargs) -> None:
    #     pairs = self.dp.current_whitelist()
    #     print("Calcul des pairs informatives")
    #     for pairname in pairs:
    #         self.stop_buying[pairname] = True
    #     print("Fin Calcul des pairs informatives")

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # dataframe.loc[
        #     (
        #         (dataframe['rsi5'].shift(1) > 60)
        #         & (dataframe['rsi5'].shift(1) >= dataframe['rsi5'])
        #         & (dataframe['rsi5'].shift(1) >= dataframe['rsi5'].shift(2))
        #         & (dataframe['close'] > dataframe['close_1d'])
        #         # & (dataframe['close_1d'] > dataframe['sma3_1d'])
        #         # & (dataframe['close_1d'] > dataframe['sma5_1d'])
        #         # & (dataframe['close_1d'] > dataframe['sma10_1d'])
        #         # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value)
        #
        #         # & (dataframe['rsi3_1d'].shift(288) > dataframe['rsi3_1d'])
        #         # (dataframe['close_1d'] > dataframe['sma3_1d'])
        #         # & (dataframe['rsi3_1d'] > 72)
        #         #& (dataframe['last_buy_price'] < (dataframe['close']))
        #         #& (dataframe['should_sell'] == True)
        #     ), ['sell', 'sell_tag']] = (1, 'sell_close_1d')
        # print("dans sell" + metadata['pair'])
        return dataframe

    def adjust_trade_position(self, trade: Trade, current_time: datetime,
                              current_rate: float, current_profit: float, min_stake: float,
                              max_stake: float, **kwargs):
        dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
        if (len(dataframe) < 1):
            return None

        # dataframe = self.populate_buy_trend(dataframe, {'pair': trade.pair})
        # if not (self.populate_buy_trend(dataframe, {'pair': trade.pair})):
        #     return None
        if (self.stop_buying.get(trade.pair, None) == None):
            print("-----------" + trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------")
            self.stop_buying[trade.pair] = True

        if (self.stop_buying[trade.pair] == True):
            print("-----------" + trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------")
            return None
        last_candle = dataframe.iloc[-1].squeeze()
        previous_last_candle = dataframe.iloc[-2].squeeze()
        previous_previous_last_candle = dataframe.iloc[-3].squeeze()

        # last_candle_5 = dataframe.iloc[-3].squeeze()
        # last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze()
        # print(last_candle['buy'])

        condition = (
                # (last_candle['min_max_n'] >= self.buy_min_max_n.value)
                (previous_last_candle['rsi5'] < 12)
                & (previous_last_candle['rsi5'] < last_candle['rsi5'])
                & (previous_last_candle['rsi5'] < previous_previous_last_candle['rsi5'])
                # & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value)
                & (last_candle['close'] <= last_candle['close_1d'])
                & (last_candle['close_1d'] <= last_candle['sma3_1d'])
                & (last_candle['close_1d'] <= last_candle['sma5_1d'])
                & (last_candle['close_1d'] <= last_candle['sma10_1d'])
                # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value)
        )
        if not (condition):
            return None

        # min_d = min(last_candle['sma3_4h'], last_candle['close_1d'])

        filled_buys = trade.select_filled_orders('buy')
        count_of_buys = len(filled_buys)
        # days = (current_time - trade.open_date_utc).days
        # minutes = (current_time - trade.open_date_utc).seconds / 60
        # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']))
        p = self.protection_percent_buy_lost.value
        percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9]

        if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \
                & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition):
            try:
                p = self.config['stake_amount']
                factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p]

                stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost
                # This then calculates current safety order size
                print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) +
                      " " + str(current_time) + "---------------------")
                return stake_amount
            except Exception as exception:
                print(exception)
                return None
        return None
