import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
from freqtrade.persistence import Trade
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
from datetime import datetime, timedelta
from freqtrade.strategy import merge_informative_pair

from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter
import pandas as pd
pd.options.mode.chained_assignment = None

import math

def hma(dataframe, source, length):
    return ta.WMA(
                    2 * ta.WMA(dataframe[source], int(math.floor(length/2))) - ta.WMA(dataframe[source], length), int(round(np.sqrt(length)))
            )

def calc_streaks(series: pd.Series):
    # logic tables
    geq = series >= series.shift(1)  # True if rising
    eq = series == series.shift(1)  # True if equal
    logic_table = pd.concat([geq, eq], axis=1)

    streaks = [0]  # holds the streak duration, starts with 0

    for row in logic_table.iloc[1:].itertuples():  # iterate through logic table
        if row[2]:  # same value as before
            streaks.append(0)
            continue
        last_value = streaks[-1]
        if row[1]:  # higher value than before
            streaks.append(last_value + 1 if last_value >=
                                             0 else 1)  # increase or reset to +1
        else:  # lower value than before
            streaks.append(last_value - 1 if last_value <
                                             0 else -1)  # decrease or reset to -1

    return streaks

class Sylv(IStrategy):    #WinRatioAndProfitRatioLoss
    # ROI table:
    minimal_roi = {
        "0": 10,
    }

    INTERFACE_VERSION = 2


    # Buy hyperspace params:
    buy_params = {
        "dev_low_buy": 1.166,
        "deviation_2_buy": 0.707,
        "deviation_buy": 1.657,
        "period_1_buy": 4,
        "period_2_buy": 4,
    }

    # Sell hyperspace params:
    sell_params = {
        "dev_low_sell": 0.763,
        "deviation_2_sell": 1.137,
        "deviation_sell": 3.14,
        "period_1_sell": 17,
        "period_2_sell": 6,
    }





    
    deviation_buy = DecimalParameter(1, 4, default=3.55, space='buy')
    dev_low_buy = DecimalParameter(0.7, 1.3, default=0.9, space='buy')
    period_1_buy = IntParameter(2, 18, default=13, space='buy')
    period_2_buy = IntParameter(2, 13, default=8, space='buy')
    deviation_2_buy = DecimalParameter(0.5, 1.2, default=1, space='buy')



    deviation_sell = DecimalParameter(1, 4, default=3.55, space='sell')
    dev_low_sell = DecimalParameter(0.7, 1.3, default=0.9, space='sell')
    period_1_sell = IntParameter(2, 18, default=13, space='sell')
    period_2_sell = IntParameter(2, 13, default=8, space='sell')
    deviation_2_sell = DecimalParameter(0.5, 1.2, default=1, space='sell')



    stoploss = -0.99 # effectively disabled.

    timeframe = '5m'


    # Sell signal
    use_sell_signal = True
    sell_profit_only = False
    sell_profit_offset = 0.001 # it doesn't meant anything, just to guarantee there is a minimal profit.
    ignore_roi_if_buy_signal = False

    # Trailing stoploss
    trailing_stop = False
    trailing_only_offset_is_reached = False
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.025

    # Custom stoploss
    use_custom_stoploss = False

    # Run "populate_indicators()" only for new candle.
    process_only_new_candles = False

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

    # Optional order type mapping.
    order_types = {
        'buy': 'limit',
        'sell': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }
    
    plot_config = {
        # Main plot indicators (Moving averages, ...)
        'main_plot': {
            'sylvain_upper': {'color': 'blue'},
            'med_avg': {'color': 'red'},
            'sylvain_lower': {'color': 'blue'}, 
        },
        'subplots': {
            # Subplots - each dict defines one additional plot
            "Stochastic": {
                'srsi_k': {'color': 'blue'},
                'd': {'color': 'red'},
            },
            "RSI": {
                'rsi': {'color': 'red'},
            }
        }
    }

    def informative_pairs(self):
        """
        Define additional, informative pair/interval combinations to be cached from the exchange.
        These pair/interval combinations are non-tradeable, unless they are part
        of the whitelist as well.
        For more information, please consult the documentation
        :return: List of tuples in the format (pair, interval)
            Sample: return [("ETH/USDT", "5m"),
                            ("BTC/USDT", "15m"),
                            ]
        """
        return []



    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        
        dataframe['typical'] = dataframe['close']
        
        if dataframe['close'].iloc[-1] >= dataframe['close'].iloc[-2]:
            dataframe['typical'] = dataframe['close'] - dataframe['low'].shift(1)
        else:
            dataframe['typical'] = dataframe['close'].shift(1) - dataframe['low']


        return dataframe


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


        dataframe['deviation'] = self.deviation_buy.value * ta.SMA(dataframe['typical'], timeperiod=int(self.period_1_buy.value))
        dataframe['pv_dev'] = dataframe['deviation'] * dataframe['volume']
        dataframe['dev_high'] = ta.SMA(dataframe['pv_dev'], timeperiod=int(self.period_2_buy.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_buy.value))
        dataframe['dev_low'] = self.dev_low_buy.value * dataframe['dev_high']
        dataframe['pv_med'] = dataframe['close'] * dataframe['volume']
        dataframe['med_avg'] = ta.SMA(dataframe['pv_med'], timeperiod=int(self.period_2_buy.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_buy.value))
        dataframe['pv_avg'] = dataframe['med_avg'] * dataframe['volume']
        dataframe['sylvain_lower'] = (ta.SMA(dataframe['pv_avg'], timeperiod=int(self.period_2_buy.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_buy.value))) - (dataframe['dev_low']*self.deviation_2_buy.value) 

  

        dataframe.loc[


            (  
                (qtpylib.crossed_below(dataframe['close'], dataframe['sylvain_lower'])) &
#                (qtpylib.crossed_above(dataframe['tsi'], dataframe['tsi_ema'])) &
                (dataframe['volume'] > 0)
            ),
            'buy'
        ] = 1
        return dataframe

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

        dataframe['deviation'] = self.deviation_sell.value * ta.SMA(dataframe['typical'], timeperiod=int(self.period_1_sell.value))
        dataframe['pv_dev'] = dataframe['deviation'] * dataframe['volume']
        dataframe['dev_high'] = ta.SMA(dataframe['pv_dev'], timeperiod=int(self.period_2_sell.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_sell.value))
        dataframe['dev_low'] = self.dev_low_sell.value * dataframe['dev_high']
        dataframe['pv_med'] = dataframe['close'] * dataframe['volume']
        dataframe['med_avg'] = ta.SMA(dataframe['pv_med'], timeperiod=int(self.period_2_sell.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_sell.value))
        dataframe['pv_avg'] = dataframe['med_avg'] * dataframe['volume']
        dataframe['sylvain_upper'] = (ta.SMA(dataframe['pv_avg'], timeperiod=int(self.period_2_sell.value)) /ta.SMA(dataframe['volume'], timeperiod=int(self.period_2_sell.value))) + (dataframe['dev_high']*self.deviation_2_sell.value) 



        dataframe.loc[
            (
                (qtpylib.crossed_above(dataframe['close'], dataframe['sylvain_upper'])) &
                (dataframe['volume'] > 0)
            )
            ,
            'sell'
        ] = 1
        return dataframe
