# GodStraNew Strategy
# Author: @Mablue (Masoud Azizi)
# github: https://github.com/mablue/
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew
# --- 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 calendar
from freqtrade.loggers import setup_logging

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

# Add your lib to import here
# TODO: talib is fast but have not more indicators
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce
import numpy as np
from random import shuffle

operators = [
    "D",  # Disabled gene
    ">",  # Indicator, bigger than cross indicator
    "<",  # Indicator, smaller than cross indicator
    "=",  # Indicator, equal with cross indicator
    "C",  # Indicator, crossed the cross indicator
    "CA",  # Indicator, crossed above the cross indicator
    "CB",  # Indicator, crossed below the cross indicator
    ">R",  # Normalized indicator, bigger than real number
    "=R",  # Normalized indicator, equal with real number
    "<R",  # Normalized indicator, smaller than real number
    "/>R",  # Normalized indicator devided to cross indicator, bigger than real number
    "/=R",  # Normalized indicator devided to cross indicator, equal with real number
    "/<R",  # Normalized indicator devided to cross indicator, smaller than real number
    "UT",  # Indicator, is in UpTrend status
    "DT",  # Indicator, is in DownTrend status
    "OT",  # Indicator, is in Off trend status(RANGE)
    "CUT",  # Indicator, Entered to UpTrend status
    "CDT",  # Indicator, Entered to DownTrend status
    "COT"  # Indicator, Entered to Off trend status(RANGE)
]
# number of candles to check up,don,off trend.
TREND_CHECK_CANDLES = 8
DECIMALS = 2

buy_crossed_indicator0 = 'MINUS_DM-5'
buy_operator0 = "/<R"
buy_indicator0 = 'MA-20'

buy_crossed_indicator1 = 'DX-5'
buy_operator1 = ">"
buy_indicator1 = 'STOCH-1-10'

buy_crossed_indicator2 = 'LINEARREG-50'
buy_operator2 = "/<R"
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'

def normalize(df):
    df = (df-df.min())/(df.max()-df.min())
    return df

def gene_calculator(dataframe, indicator):

    # Cuz Timeperiods not effect calculating CDL patterns recognations
    if 'CDL' in indicator:
        splited_indicator = indicator.split('-')
        splited_indicator[1] = "0"
        new_indicator = "-".join(splited_indicator)
        # print(indicator, new_indicator)
        indicator = new_indicator

    gene = indicator.split("-")
    gene_name = gene[0]
    gene_len = len(gene)

    if indicator in dataframe.keys():
        # print(f"{indicator}, calculated befoure")
        # print(len(dataframe.keys()))
        return dataframe[indicator]
    else:
        result = None
        # For Pattern Recognations
        if gene_len == 1:
            # print('gene_len == 1\t', indicator)
            result = getattr(ta, gene_name)(
                dataframe
            )
            return normalize(result)
        elif gene_len == 2:
            # print('gene_len == 2\t', indicator)
            gene_timeperiod = int(gene[1])
            result = getattr(ta, gene_name)(
                dataframe,
                timeperiod=gene_timeperiod,
            )
            return normalize(result)
        # For
        elif gene_len == 3:
            # print('gene_len == 3\t', indicator)
            gene_timeperiod = int(gene[2])
            gene_index = int(gene[1])
            result = getattr(ta, gene_name)(
                dataframe,
                timeperiod=gene_timeperiod,
            ).iloc[:, gene_index]
            return normalize(result)
        # For trend operators(MA-5-SMA-4)
        elif gene_len == 4:
            # print('gene_len == 4\t', indicator)
            gene_timeperiod = int(gene[1])
            sharp_indicator = f'{gene_name}-{gene_timeperiod}'
            dataframe[sharp_indicator] = getattr(ta, gene_name)(
                dataframe,
                timeperiod=gene_timeperiod,
            )
            return normalize(ta.SMA(dataframe[sharp_indicator].fillna(0), TREND_CHECK_CANDLES))
        # For trend operators(STOCH-0-4-SMA-4)
        elif gene_len == 5:
            # print('gene_len == 5\t', indicator)
            gene_timeperiod = int(gene[2])
            gene_index = int(gene[1])
            sharp_indicator = f'{gene_name}-{gene_index}-{gene_timeperiod}'
            dataframe[sharp_indicator] = getattr(ta, gene_name)(
                dataframe,
                timeperiod=gene_timeperiod,
            ).iloc[:, gene_index]
            return normalize(ta.SMA(dataframe[sharp_indicator].fillna(0), TREND_CHECK_CANDLES))


def condition_generator(dataframe, operator, indicator, crossed_indicator, real_num, decalage):

    condition = (dataframe['volume'] > 10)

    # TODO : it ill callculated in populate indicators.

    dataframe[indicator] = gene_calculator(dataframe, indicator)
    dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator)

    indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}"
    if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]:
        dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma)

    if operator == ">":
        condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage))
    elif operator == "=":
        condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
    elif operator == "<":
        condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage))
    elif operator == "C":
        condition = (
            (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) |
            (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
        )
    elif operator == "CA":
        condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
    elif operator == "CB":
        condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
    elif operator == ">R":
        condition = (dataframe[indicator].shift(decalage) > real_num)
    elif operator == "=R":
        condition = (np.isclose(dataframe[indicator].shift(decalage), real_num))
    elif operator == "<R":
        condition = (dataframe[indicator].shift(decalage) < real_num)
    elif operator == "/>R":
        condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num)
    elif operator == "/=R":
        condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num))
    elif operator == "/<R":
        condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) < real_num)
    elif operator == "UT":
        condition = (dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage))
    elif operator == "DT":
        condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage))
    elif operator == "OT":
        condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)))
    elif operator == "CUT":
        condition = (
            (
                qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
            ) &
            (
                dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage)
            )
        )
    elif operator == "CDT":
        condition = (
            (
                qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
            ) &
            (
                dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)
            )
        )
    elif operator == "COT":
        condition = (
            (
                (
                    qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
                ) |
                (
                    qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
                )
            ) &
            (
                np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
            )
        )
    return condition, dataframe


class GodStraJD3_7_6_2(IStrategy):
    # #################### RESULTS PASTE PLACE ####################
    # ROI table:
    minimal_roi = {
        "0": 10,
        # "600": 0.12,
        # "1200": 0.08,
        # "2400": 0.06,
        # "3600": 0.04,
        # "7289": 0
    }

    # Stoploss:
    stoploss = -1
    # Buy hypers
    timeframe = '5m'

    # Trailing stoploss
    trailing_stop = False
    trailing_stop_positive = 0.15
    trailing_stop_positive_offset = 0.20
    trailing_only_offset_is_reached = True

    plot_config = {
        # Main plot indicators (Moving averages, ...)
        'main_plot': {
            'bb_lowerband': {'color': 'red'},
            'bb_upperband': {'color': 'green'},
            'sma100': {'color': 'blue'},
            'sma10': {'color': 'yellow'},
            'min20': {'color': '#87e470'},
            'min50': {'color': '#ac3e2a'},
            "min1.1": {'color': 'yellow'},
            'sma20': {'color': 'cyan'}
        },
        'subplots': {
            # Subplots - each dict defines one additional plot
            "BB": {
                'bb_width': {'color': 'white'}
            },
            # "Ind0": {
            #     buy_crossed_indicator0: {'color': 'green'},
            #     buy_indicator0: {'color': 'red'}
            # },
            "Cond": {
                'cond1': {'color': 'yellow'},
            },
            # "Ind1": {
            #     buy_indicator1: {'color': 'yellow'},
            #     buy_crossed_indicator1: {'color': 'pink'}
            # },
            # "Ind2": {
            #     buy_indicator2: {'color': 'cyan'},
            #     buy_crossed_indicator2: {'color': 'blue'},
            # },
            "Rsi": {
                'rsi': {'color': 'pink'},
            },
            "Ecart": {
                'ecart_20': {'color': 'red'},
                'ecart_50': {'color': 'yellow'},
            },
            # "rolling": {
            #     'bb_rolling': {'color': '#87e470'},
            #     "bb_rolling_min": {'color': '#ac3e2a'}
            # },
            "percent": {
                "percent": {'color': 'green'},
                "percent3": {'color': 'blue'},
                "percent5": {'color': 'red'},
                "distance_min": {'color': 'white'}
            }
        }
    }


    # #################### END OF RESULT PLACE ####################

    # profit_no_change = False
    # profit_old_sma10 = False
    # profit_over_rsi = True
    # profit_quick_gain = True
    # profit_quick_gain_3 = True
    # profit_quick_lost = False
    # profit_short_loss = False
    # profit_sma10 = False
    # profit_sma20 = True
    # profit_very_old_sma10 = False

    trades = list()
    profit_too_old = BooleanParameter(default=True, space="sell")
    profit_no_change = BooleanParameter(default=True, space="sell")
    profit_quick_lost = BooleanParameter(default=True, space="sell")
    profit_sma10 = BooleanParameter(default=True, space="sell")
    profit_sma20 = BooleanParameter(default=True, space="sell")
    profit_quick_gain = BooleanParameter(default=True, space="sell")
    profit_quick_gain_3 = BooleanParameter(default=True, space="sell")
    profit_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_very_old_sma10 = BooleanParameter(default=True, space="sell")
    profit_over_rsi = BooleanParameter(default=True, space="sell")
    profit_short_loss = BooleanParameter(default=True, space="sell")

    profit_too_old_max = DecimalParameter(0, 0.05, decimals=2,  default=0.01, space='sell')
    profit_too_old_days = IntParameter(1, 10, default=5, space='sell')
    profit_quick_lost_max = DecimalParameter(0, 0.03, decimals=3,  default=0.015, space='sell')
    profit_quick_lost_max_profit = DecimalParameter(0, 0.03, decimals=3,  default=0.015, space='sell')
    profit_sma10_current_profit  = DecimalParameter(0, 0.03, decimals=3,  default=0.015, space='sell')
    profit_sma10_facteur = DecimalParameter(1, 1.01, decimals=3,  default=1.005, space='sell')

    profit_sma20_current_profit  = DecimalParameter(0, 0.03, decimals=3,  default=0.015, space='sell')
    profit_sma20_facteur = DecimalParameter(1, 1.01, decimals=3,  default=1.005, space='sell')

    profit_over_rsi_max_rsi = IntParameter(70, 100, default=88, space='sell')
    profit_over_rsi_max_rsi2 = IntParameter(70, 100, default=82, space='sell')

    profit_over_rsi2_percent = DecimalParameter(0, 0.05, decimals=3,  default=0.02, space='sell')

    # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy')

    # buy_real_num0 = DecimalParameter(0, 1, decimals=2,  default=0.67, space='buy')
    buy_real_num1 = DecimalParameter(0, 1, decimals=2,  default=0.67, space='buy')
    buy_real_num3 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')

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

    # buy_0 = BooleanParameter(default=True, space="buy")
    # buy_2 = BooleanParameter(default=True, space="buy")
    # buy_3 = BooleanParameter(default=True, space="buy")

    # buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2,  default=-0.02, space='buy')
    buy_1_percent20 = DecimalParameter(-0.1, 0.1, decimals=2,  default=-0.02, space='buy')
    buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2,  default=-0.02, space='buy')

    # buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
    buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
    buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')

    # buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy')
    buy_decalage_deb_1 = IntParameter(1, 3, default=5, space='buy')
    buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy')

    # buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
    buy_decalage1 = IntParameter(buy_decalage_deb_1.value + 1, 8, default=5, space='buy')
    buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy')

    protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
    protection_stop = IntParameter(1, 100, default=48, space='protection')
    protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection')
    lookback = IntParameter(1, 200, default=48, space='protection')
    trade_limit = IntParameter(1, 10, default=2, space='protection')

    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:

        # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489,
        #  'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198,
        #  'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808,
        #  'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799,
        #  'info':
        #  {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667',
        #       'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000',
        #       'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000',
        #       'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000',
        #       'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000',
        #       'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570',
        #       'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484

        allow_to_buy = True
        max_gain = -100
        sum_gain = 0
        max_time = 0

        if self.dp:
            if self.dp.runmode.value in ('live', 'dry_run'):
                if len(self.trades) == 0:
                    print('search')
                    self.trades = Trade.get_open_trades()

                if len(self.trades) >= self.config['max_open_trades'] / 2:
                    for trade in self.trades:
                        ticker = self.dp.ticker(trade.pair)
                        last_price = ticker['last']
                        gain = (last_price - trade.open_rate) / trade.open_rate
                        max_gain = max(max_gain, gain)
                        sum_gain += gain
                        max_time = max(max_time, datetime.timestamp(trade.open_date))
                        print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date),
                              datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000))
                    now = datetime.now()
                    diff = (datetime.timestamp(now) - max_time / 3600)
                    if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6):
                        print("allow_to_buy=false")
                        allow_to_buy = False
                    print(pair, allow_to_buy, len(self.trades),
                          "max gain=", max_gain,
                          "sum_gain=", sum_gain,
                          "now=", now,
                          "max=", max_time,
                          "diff=", datetime.timestamp(now) - max_time)

                if allow_to_buy:
                    self.trades = list()

        return allow_to_buy

    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 10
            },
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": self.lookback.value,
                "trade_limit": self.trade_limit.value,
                "stop_duration_candles": self.protection_stop.value,
                "max_allowed_drawdown": self.protection_max_allowed_dd.value,
                "only_per_pair": False
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": self.protection_stoploss_stop.value,
                "only_per_pair": False
            }
        ]

    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_5_candle = dataframe.iloc[-5].squeeze()

        # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \
        #     & (last_candle['percent10'] < 0.001):
        #     return 'small_profit'
        #
        # if (current_profit > 0.01) \
        #         & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003):
        #     # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
        #     return 'sma10_quick'

        if self.profit_too_old.value:
            if (current_profit >= - self.profit_too_old_max.value) \
                    & ((current_time - trade.open_date_utc).days >= self.profit_too_old_days.value)\
                    & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 2))\
                    & (previous_last_candle['sma20'] > last_candle['sma20']):
                return "too_old_0.01"
            if (current_profit >= - (2 * self.profit_too_old_max.value)) \
                    & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 2))\
                    & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 3)) \
                    & (previous_last_candle['sma20'] > last_candle['sma20']):
                return "too_old_0.02"
            if (current_profit >= - (3 * self.profit_too_old_max.value)) \
                    & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 3)) \
                    & (previous_last_candle['sma20'] > last_candle['sma20']):
                return "too_old_0.03"

        if self.profit_quick_lost.value:
            if (current_profit >= self.profit_quick_lost_max_profit.value) \
                    & (last_candle['percent3'] < - self.profit_quick_lost_max.value):
                return "quick_lost"

        if self.profit_no_change.value:
            if (current_profit > 0.005) \
                    & (last_candle['percent10'] < 0.000) \
                    & (last_candle['percent5'] < 0) \
                    & ((current_time - trade.open_date_utc).seconds >= 3600):
                return "no_change"

        #if (current_profit > 0.01) & (last_candle['rsi'] < 30):
        #    return "small_rsi"
        if self.profit_quick_gain_3.value:
            if (current_profit >= 0.03) \
                    & (last_candle['percent3'] < 0) \
                    & ((current_time - trade.open_date_utc).seconds <= 3600):
                return "quick_gain_3"
        if self.profit_quick_gain.value:
            if (0.01 < current_profit < 0.03) \
                    & (last_candle['percent'] < 0) \
                    & ((current_time - trade.open_date_utc).seconds <= 3600):
                return "quick_gain"

        if self.profit_sma10.value:
            if (current_profit > self.profit_sma10_current_profit.value) \
                    & ((previous_5_candle['sma10'] > (last_candle['sma10'] * self.profit_sma10_facteur.value)) \
                        | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \
                    & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
                # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
                return 'sma10'

        if self.profit_sma20.value:
            if (current_profit > self.profit_sma20_current_profit.value) & (last_candle['percent5'] < 0) \
                    & (previous_5_candle['sma10'] > last_candle['sma10']) \
                    & ((current_time - trade.open_date_utc).seconds >= 3600) \
                    & ((previous_last_candle['sma20'] > (last_candle['sma20'] * self.profit_sma20_facteur.value)) &
                        ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))):
                # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
                return 'sma20'

        # if self.profit_old_sma10:
        #     if (current_profit > 0) \
        #             & ((current_time - trade.open_date_utc).days >= 3) \
        #             & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \
        #             & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
        #         # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
        #         return 'old_sma10'
        # if self.profit_very_old_sma10:
        #     if (current_profit > -0.01) \
        #             & ((current_time - trade.open_date_utc).days >= 6) \
        #             & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \
        #             & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
        #         # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
        #         return 'very_old_sma10'

        if self.profit_over_rsi.value:
            if (current_profit > 0) & (last_candle['rsi'] > self.profit_over_rsi_max_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 'over_rsi'

            if (current_profit > 0) & (previous_last_candle['rsi'] > self.profit_over_rsi_max_rsi2.value) \
                    & (last_candle['percent'] < - self.profit_over_rsi2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
                # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
                return 'over_rsi_2'

        if self.profit_short_loss.value:
            if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\
                    & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
                # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
                return 'short_lost'

        # if (current_profit > 0) \
        #         & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
        #     # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
        #     return 'over_rsi_2'

    def informative_pairs(self):
        return []

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

        # dataframe['profit'] = 0
        # RSI
        dataframe['rsi'] = ta.RSI(dataframe)
        dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10)
        dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20)
        dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50)
        dataframe['sma100'] = ta.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()

        # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)):
        #     dataframe["percent_ok"] = new dataframe()
        # else:
        #     dataframe["percent_ok"] = 0

        dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close']
        dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close']

        dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value)
        dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10)
        dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
        dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50)

        dataframe["volume10"] = dataframe["volume"].rolling(10).mean()

        dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200)
        dataframe['max_min'] = dataframe['max'] / dataframe['min']
        # 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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)

        dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
        dataframe['min1.1'] = 1.01 * dataframe['min']

        # Bollinger Bands - Weighted (EMA based instead of SMA)
        # weighted_bollinger = qtpylib.weighted_bollinger_bands(
        #     qtpylib.typical_price(dataframe), window=20, stds=2
        # )
        # dataframe["wbb_upperband"] = weighted_bollinger["upper"]
        # dataframe["wbb_lowerband"] = weighted_bollinger["lower"]
        # dataframe["wbb_middleband"] = weighted_bollinger["mid"]
        # dataframe["wbb_percent"] = (
        #     (dataframe["close"] - dataframe["wbb_lowerband"]) /
        #     (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"])
        # )
        # dataframe["wbb_width"] = (
        #     (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"]
        # )

        dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0)
        dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1)
        dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2)

        dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0)
        dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1)
        dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2)

        dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0])

        # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50']
        # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20']

        # # EMA - Exponential Moving Average
        # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
        return dataframe

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

        # pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
        # pandas.set_option('display.max_columns', 50)
        #
        # allow_to_buy = True
        # max_gain = -100
        # trades = Trade.get_open_trades()
        #
        # if self.dp:
        #     if self.dp.runmode.value in ('live', 'dry_run'):
        #         pairs = self.dp.current_whitelist()
        #         pairs_len = len(pairs)
        #         pair_index = pairs.index(metadata['pair'])
        #
        #         # print(pair_index, " ", metadata['pair'])
        #
        #         # ob = self.dp.orderbook(metadata['pair'], 1)
        #         # dataframe['best_bid'] = ob['bids'][0][0]
        #         # dataframe['best_ask'] = ob['asks'][0][0]
        #         # print(ob)
        #
        #         for trade in trades:
        #             # if (metadata['pair'] == trade.pair):
        #             ticker = self.dp.ticker(trade.pair) #metadata['pair'])
        #             last_price = ticker['last']
        #             # dataframe['volume24h'] = ticker['quoteVolume']
        #             # dataframe['vwap'] = ticker['vwap']
        #             # d = dataframe.tail(1)
        #             # print(dataframe)
        #             gain = (last_price - trade.open_rate) / trade.open_rate
        #
        #             # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain)
        #             max_gain = max(max_gain, gain)
        #
        # if max_gain > - 0.05:
        #     allow_to_buy = False
        #
        # # print(metadata['pair'], max_gain, allow_to_buy, len(trades))

        # for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value):
        #     if self.buy_0.value:
        #         conditions = list()
        #         condition1, dataframe = condition_generator(
        #             dataframe,
        #             buy_operator0,
        #             buy_indicator0,
        #             buy_crossed_indicator0,
        #             self.buy_real_num0.value,
        #             self.buy_decalage0.value
        #         )
        #         conditions.append(condition1)
        #         dataframe.loc[
        #             (
        #                reduce(lambda x, y: x & y, conditions)
        #                & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
        #                & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
        #                & (dataframe['close'] < dataframe['bb_middleband'])
        #                & (dataframe['open'] < dataframe['sma10'])
        #                & (dataframe['open'] < dataframe['sma100'])
        #                & (dataframe['min50'].shift(decalage) == dataframe['min50'])
        #                & (dataframe['min10'] <= dataframe['min50'] * 1.02)
        #                & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
        #                # & (dataframe['min20'] == dataframe['min50'])
        #                & (dataframe['distance_min'] <= self.buy_0_distance.value)
        #             ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
        for decalage in range(self.buy_decalage_deb_1.value, self.buy_decalage1.value):
            dataframe.loc[
                (
                   (dataframe['cond1'].shift(decalage) <= self.buy_real_num1.value)
                   & (dataframe['bb_width'].shift(decalage) >= 0.07)
                   # & (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage))
                   & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
                   & (dataframe['close'] < dataframe['sma10'])
                   & (dataframe['sma50'].shift(decalage) < dataframe['sma50'])
                   #& (dataframe['open'] < dataframe['min1.1'])
                   # & (dataframe['open'] < dataframe['sma10'])
                   & (dataframe['min50'].shift(decalage) == dataframe['min50'])
                   #& (dataframe['min10'] <= dataframe['min50'] * 1.02)
                   & (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value)
                   # & (dataframe['min20'] == dataframe['min50'])
                   & (dataframe['distance_min'] <= self.buy_1_distance.value)
                ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
        for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
            # if self.buy_3.value:
            dataframe.loc[
                (
                   (dataframe['cond1'].shift(decalage) <= self.buy_real_num3.value)
                   & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
                   & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
                   & (dataframe['close'] < dataframe['sma10'])
                   & (dataframe['open'] < dataframe['sma100'])
                   & (dataframe['open'] < dataframe['sma10'])
                   #& (dataframe['open'] < dataframe['min1.1'])
                   & (dataframe['min50'].shift(decalage) == dataframe['min50'])
                   #& (dataframe['min10'] <= dataframe['min50'] * 1.02)
                   & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
                   & (dataframe['distance_min'] <= self.buy_3_distance.value)
                ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))

        # pair = metadata['pair']
        # allow_to_buy = True
        # max_gain = -100
        # sum_gain = 0
        # max_time = 0
        # if len(self.trades) == 0:
        #     print('search')
        #     self.trades = Trade.get_open_trades()
        #
        # # if self.dp:
        # #     if self.dp.runmode.value in ('live', 'dry_run'):
        # if len(self.trades) >= self.config['max_open_trades'] / 2:
        #     for trade in self.trades:
        #         ticker = self.dp.ticker(trade.pair)
        #         last_price = ticker['last']
        #         gain = (last_price - trade.open_rate) / trade.open_rate
        #         max_gain = max(max_gain, gain)
        #         sum_gain += gain
        #         max_time = max(max_time, datetime.timestamp(trade.open_date))
        #         print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date),
        #               datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000))
        #     now = datetime.now()
        #     diff = (datetime.timestamp(now) - max_time / 3600)
        #     if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6):
        #         print("allow_to_buy=false")
        #         allow_to_buy = False
        #     print(pair, allow_to_buy, len(self.trades),
        #           "max gain=", max_gain,
        #           "sum_gain=", sum_gain,
        #           "now=", now,
        #           "max=", max_time,
        #           "diff=", datetime.timestamp(now) - max_time)
        #
        # if allow_to_buy:
        #     self.trades = list()

        # print(condition1)

        return dataframe

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

        return dataframe

