# source: https://raw.githubusercontent.com/D3SP4IR/TechnicalBot/154ed796b6cd6c6573d2077b4f9332ca10780128/backtest_summary/Grid_ETH_USDT_1h/Grid.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__Grid__20220401_005012(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 = 3300 # (USDT) The highest price
    minPrice = 2500 # (USDT) The lowest price
    gridCount = 30 # 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)

    for i in range(gridCount):
        linePrice = minPrice + (maxPrice - minPrice) / (gridCount - 1) * i
        gridLines.append({'active' : True, 'price' : linePrice, 'side' : ''})

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

    def updategithub_D3SP4IR_TechnicalBot__Grid__20220401_005012Lines(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 ''

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

    firstTime = True
    foundSignal = False

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

        for x in range(len(dataframe.index)):
            lastPrice = dataframe['close'].iloc[x]

            if self.firstTime:
                # Find the nearest grid line and set gridLines[nearestLine]['active'] to False by updategithub_D3SP4IR_TechnicalBot__Grid__20220401_005012Lines()
                # updategithub_D3SP4IR_TechnicalBot__Grid__20220401_005012Lines() --> 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__Grid__20220401_005012Lines(nearestLine)
                self.firstTime = False
                dataframe['signal'] = ''
            
            self.foundSignal = False

            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/ETH at grid no.{i}')
                    dataframe.at[x, 'signal'] = 'BUY'
                    self.updategithub_D3SP4IR_TechnicalBot__Grid__20220401_005012Lines(i)
                    self.foundSignal = True
                    break

            if self.foundSignal:
                continue
                        
            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/ETH at grid no.{i}')
                    dataframe.at[x, 'signal'] = 'SELL'
                    self.updategithub_D3SP4IR_TechnicalBot__Grid__20220401_005012Lines(i)
                    break
                        
        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 ######################################################
##################################################################################################################
