import logging
# --- Do not remove these libs ---
from functools import reduce
from freqtrade.strategy import IStrategy, stoploss_from_open, DecimalParameter
import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.persistence import Trade
from datetime import datetime, timedelta
from pandas import DataFrame
import numpy as np
# --------------------------------

import talib.abstract as ta

log = logging.getLogger(__name__)

def to_minutes(**timdelta_kwargs):
    return int(timedelta(**timdelta_kwargs).total_seconds() / 60)


class ShaneHolds_TSL_CSL_s0undt3ch_20211008(IStrategy):
    timeframe = '15m'

    # Stoploss
    stoploss = -0.20

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

    trailing_stop = False
    use_custom_stoploss = True
    use_sell_signal = False

    # Indicator values:
    ema_xs = 3
    ema_sm = 5
    ema_md = 10
    ema_xl = 50
    ema_xxl = 200

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

    @property
    def protections(self):
        return [
            # Locks each pair after selling for 5 minutes (CooldownPeriod),
            # giving other pairs a chance to get filled.
            {
                "method": "CooldownPeriod",
                "stop_duration": to_minutes(minutes=5)
            },
            # Stops trading for 4 hours if the last 2 days had 20 trades, which caused a
            # max-drawdown of more than 20%. (MaxDrawdown).
            {
                "method": "MaxDrawdown",
                "lookback_period": to_minutes(days=2),
                "trade_limit": 20,
                "stop_duration": to_minutes(hours=4),
                "max_allowed_drawdown": 0.2
            },
            # Stops trading if more than 4 stoploss occur for all pairs within a 1 day limit (StoplossGuard).
            {
                "method": "StoplossGuard",
                "lookback_period": to_minutes(days=1),
                "trade_limit": 4,
                "stop_duration": to_minutes(hours=2),
                "only_per_pair": False
            },
            # Locks all pairs that had 4 Trades within the last 6 hours with a combined profit ratio of
            # below 0.02 (<2%) (LowProfitPairs).
            {
                "method": "LowProfitPairs",
                "lookback_period": to_minutes(hours=6),
                "trade_limit": 2,
                "stop_duration": to_minutes(days=2),
                "required_profit": 0.02
            },
            # Locks all pairs for 2 hours that had a profit of below 0.01 (<1%) within the last 24h, a minimum of 4 trades.
            {
                "method": "LowProfitPairs",
                "lookback_period": to_minutes(days=1),
                "trade_limit": 4,
                "stop_duration": to_minutes(hours=2),
                "required_profit": 0.01
            }
        ]

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

        # Adding EMA's into the dataframe
        dataframe['ema_xs'] = ta.EMA(dataframe, timeperiod=self.ema_xs)
        dataframe['ema_sm'] = ta.EMA(dataframe, timeperiod=self.ema_sm)
        dataframe['ema_md'] = ta.EMA(dataframe, timeperiod=self.ema_md)
        dataframe['ema_xl'] = ta.EMA(dataframe, timeperiod=self.ema_xl)
        dataframe['ema_xxl'] = ta.EMA(dataframe, timeperiod=self.ema_xxl)

        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # basic buy methods to keep the strategy complex
        conditions = [
            (dataframe['close'] < dataframe['ema_xxl']),
            (qtpylib.crossed_above(dataframe['ema_sm'], dataframe['ema_md'])),
            (dataframe['ema_xs'] < dataframe['ema_xl']),
            (dataframe['volume'] > 0),
        ]
        dataframe.loc[reduce(lambda x, y: x & y, conditions), "buy"] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # This is essentailly ignored as we're using strict ROI / Stoploss / TTP sale scenarios
        dataframe.loc[(), "sell"] = 0
        return dataframe

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:
        if current_profit > 0.20:
            return stoploss_from_open(current_profit - 0.05, current_profit)
        if current_profit > 0.10:
            return stoploss_from_open(current_profit - 0.03, current_profit)
        if current_profit > 0.06:
            return stoploss_from_open(current_profit - 0.02, current_profit)
        if current_profit > 0.03:
            return stoploss_from_open(current_profit - 0.01, current_profit)
        return stoploss_from_open(-0.20, current_profit)
