# source: https://raw.githubusercontent.com/D3SP4IR/TechnicalBot/d1891c124b752ad49f2f9cbdd28b4c46c82bb8a0/strategy_version/Grid%20percentGap%20(Dry%20and%20Live%20mode).py
##################################################################################################################
##################################################################################################################


# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file

import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame
from freqtrade.strategy import (IStrategy, IntParameter)


################################################ GRID CLASS ######################################################
##################################################################################################################


class github_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107(IStrategy):

    """
    You can:
        :return: a Dataframe with all mandatory indicators for the strategies
    - Rename the class name (Do not forget to update class_name)
    - Add any methods you want to build your strategy
    - Add any lib you need to build your strategy

    You must keep:
    - the lib in the section "Do not remove these libs"
    - the methods: populate_indicators, populate_buy_trend, populate_sell_trend
    You should keep:
    - timeframe, minimal_roi, stoploss, trailing_*
    """

    #########################
    # -CONFIG FILE SETTING- #
    #########################     

    # Strategy interface version - allow new iterations of the strategy interface.
    # Check the documentation or the Sample strategy to get the latest version.
    INTERFACE_VERSION = 2

    # Trailing stoploss
    trailing_stop = False
    # trailing_only_offset_is_reached = False
    # trailing_stop_positive = 0.01
    # trailing_stop_positive_offset = 0.0  # Disabled / not configured

    # Hyperoptable parameters
    buy_rsi = IntParameter(low=1, high=50, default=30, space='buy', optimize=True, load=True)
    sell_rsi = IntParameter(low=50, high=100, default=70, space='sell', optimize=True, load=True)

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

    # These values can be overridden in the "ask_strategy" section in the config.
    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = False

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

    # Optional order type mapping.
    order_types = {
        'buy': 'limit',
        'sell': 'limit',
        'stoploss': 'market',
        'stoploss_on_exchange': False
    }

    # Optional order time in force.
    order_time_in_force = {
        'buy': 'gtc',
        'sell': 'gtc'
    }

    ##################
    # -GRID SETTING- #
    ##################

    timeframe = '1h' # This attribute will be overridden
    stoploss = -0.10 # This attribute will be overridden
    minimal_roi = {"0": 100} # This attribute will be overridden

    maxPrice = 110 # (USDT) The highest price
    minPrice = 100 # (USDT) The lowest price
    gridCount = 20 # The number of splits to have between the min and max price

    dry_run_wallet = 1000 # (USDT) This attribute will be overridden
    tradable_balance_ratio = 1 # (0-1) This attribute will be overridden

    gridLines = []
    # gridLines[numOfLine]['active'] --> True or False (Boolean)
    # gridLines[numOfLine]['price'] --> 9999.9999 (Float)
    # gridLines[numOfLine]['side'] --> 'BUY' or 'SELL' (String)

    percentGap = ( (pow(maxPrice / minPrice, 1 / (gridCount - 1))) * 100 ) - 100 # The number of percent price between each grid line
    linePrice = minPrice

    for i in range(gridCount):
        #print(linePrice)
        gridLines.append({'active' : True, 'price' : linePrice, 'side' : ''})
        linePrice = linePrice + ((percentGap / 100) * linePrice)

    ##################################################################################################################

    def updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines(self, numOfLine):

        for i in range(self.gridCount):
            self.gridLines[i]['active'] = True if i != numOfLine else False
            self.gridLines[i]['side'] = 'SELL' if i > numOfLine else 'BUY' if i < numOfLine else ''

    ##################################################################################################################

    signalList = []

    def updateSignalList(self, signal):

        self.signalList.pop(0)
        self.signalList.append(signal)

    ##################################################################################################################

    firstTime = True
    prevCandle = ''

    def checkSignal(self, dataframe: DataFrame) -> list:

        lastCandle = len(dataframe.index) - 1 # last candle index
        lastPrice = dataframe['close'].iloc[lastCandle]

        if self.firstTime:
            # Find the nearest grid line and set gridLines[nearestLine]['active'] to False by updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines()
            # updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines() --> update gridLines active status and order side (BUY or SELL)
            nearestLine = sorted([[abs(lastPrice-self.gridLines[i]['price']), i] for i in range(self.gridCount)])[0][1]
            self.updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines(nearestLine)
            self.prevCandle = str(dataframe['date'].iloc[lastCandle])[-14:-6]
            self.signalList = ['OLD CANDLE' for _ in range(lastCandle + 1)]
            self.updateSignalList('NO SIGNAL')
            self.firstTime = False

        currentCandle = str(dataframe['date'].iloc[lastCandle])[-14:-6]
        if self.prevCandle == currentCandle:
            return self.signalList
        self.prevCandle = currentCandle

        for i in range(self.gridCount):
            if (self.gridLines[i]['active']) & (self.gridLines[i]['side'] == 'BUY') & (lastPrice <= self.gridLines[i]['price']):
                #print(f'BUY : {int(lastPrice)} USDT/LUNA at grid no.{i}')
                self.updateSignalList('BUY')
                self.updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines(i)
                return self.signalList
                        
        for i in range(self.gridCount-1, -1, -1):
            if (self.gridLines[i]['active']) & (self.gridLines[i]['side'] == 'SELL') & (lastPrice >= self.gridLines[i]['price']):
                #print(f'SELL: {int(lastPrice)} USDT/LUNA at grid no.{i}')
                self.updateSignalList('SELL')
                self.updategithub_D3SP4IR_TechnicalBot__GridpercentGap_DryandLivemode___20220402_123107Lines(i)
                return self.signalList
        
        self.updateSignalList('NO SIGNAL')
        #print(f'{self.signalList[-1]} at {lastPrice} USDT')

        return self.signalList

    ##################################################################################################################

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['signal'] = pd.Series(self.checkSignal(dataframe))
        #print(dataframe.head) # FOR DEBUGGING           
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[((dataframe['signal']=='BUY') & (dataframe['volume'] > 0)), 'buy'] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[((dataframe['signal']=='SELL') & (dataframe['volume'] > 0)), 'sell'] = 1
        return dataframe

    ##################################################################################################################


################################################ GRID CLASS ######################################################
##################################################################################################################
