# source: https://raw.githubusercontent.com/viktors1982/trading/e2fba2a4608c6bd6d1ca7e117c80cad2f692dec1/freqtrade/strategies/LuxOSC.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401

# --- Do not remove these libs ---
import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame

from freqtrade.strategy import IStrategy
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter

# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
 
def LUX_SuperTrendOscillator(dtloc, source = 'close', length = 6, mult = 9, smooth = 72):
    """
    // This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
    // © LuxAlgo
      https://www.tradingview.com/script/dVau7zqn-LUX-SuperTrend-Oscillator/
     :return: List of tuples in the format (osc, signal, histogram)   
     translated for freqtrade: viksal1982  viktors.s@gmail.com
    """
    def_proc_name = '_LUX_SuperTrendOscillator'
    atrcol        = 'atr'    + def_proc_name
    hl2col        = 'hl2'    + def_proc_name
    upcol         = 'up'     + def_proc_name
    dncol         = 'dn'     + def_proc_name
    uppercol      = 'upper'  + def_proc_name
    lowercol      = 'lower'  + def_proc_name
    trendcol      = 'trend'  + def_proc_name
    sptcol        = 'spt'    + def_proc_name
    osc1col       = 'osc1'   + def_proc_name
    osc2col       = 'osc2'   + def_proc_name
    osccol        = 'osc'    + def_proc_name
    alphacol      = 'alpha'  + def_proc_name
    amacol        = 'ama'    + def_proc_name
    histcol       = 'hist'   + def_proc_name


    dtS = dtloc.copy().fillna(0)
    dtS[atrcol] = ta.ATR(dtloc, timeperiod = length) * mult
    dtS[hl2col] =  (dtS['high'] + dtS['low'] )/2
    dtS[upcol] =  dtS[hl2col] + dtS[atrcol]
    dtS[dncol] =  dtS[hl2col] - dtS[atrcol]
    def calc_upper(dfr, init=0):
        global calc_Lux_STO_upper
        global calc_Lux_STO_src
        if init == 1:
            calc_Lux_STO_upper = 0.0
            calc_Lux_STO_src = 0.0
            return
        if calc_Lux_STO_src < calc_Lux_STO_upper:
            calc_Lux_STO_upper = min(dfr[upcol], calc_Lux_STO_upper)
        else:
            calc_Lux_STO_upper = dfr[upcol]
        calc_Lux_STO_src = dfr[source]
        return calc_Lux_STO_upper
    calc_upper(None, init=1)
    dtS[uppercol] = dtS.apply(calc_upper, axis = 1)
    def calc_lower(dfr, init=0):
        global calc_Lux_STO_lower
        global calc_Lux_STO_src
        if init == 1:
            calc_Lux_STO_lower = 0.0
            calc_Lux_STO_src = 0.0
            return
        if calc_Lux_STO_src > calc_Lux_STO_lower:
            calc_Lux_STO_lower= max(dfr[dncol], calc_Lux_STO_lower)
        else:
            calc_Lux_STO_lower = dfr[dncol]
        calc_Lux_STO_src = dfr[source]
        return calc_Lux_STO_lower
    calc_lower(None, init=1)
    dtS[lowercol] = dtS.apply(calc_lower, axis = 1)
    def calc_trend(dfr, init=0):
        global calc_Lux_STO_trend
        global calc_Lux_STO_lower
        global calc_Lux_STO_upper
        if init == 1:
            calc_Lux_STO_trend = 0.0
            calc_Lux_STO_lower = 0.0
            calc_Lux_STO_upper = 0.0
            return
        if dfr[source] > calc_Lux_STO_upper:
            calc_Lux_STO_trend = 1
        elif dfr[source] < calc_Lux_STO_lower:
            calc_Lux_STO_trend = 0
        calc_Lux_STO_upper = dfr[uppercol]
        calc_Lux_STO_lower = dfr[lowercol]
        return calc_Lux_STO_trend
    calc_trend(None, init=1)
    dtS[trendcol] = dtS.apply(calc_trend, axis = 1)
    dtS[sptcol] = dtS[trendcol] * dtS[lowercol] + (1-dtS[trendcol] ) * dtS[uppercol]
    dtS[osc1col] = (dtS[source] - dtS[sptcol]) / (dtS[uppercol] - dtS[lowercol])
    dtS[osc2col] = np.where(dtS[osc1col] < 1, dtS[osc1col], 1 )
    dtS[osccol] = np.where(dtS[osc2col] > -1, dtS[osc2col], -1)
    dtS[alphacol] = dtS[osccol].pow(2)/length
    def calc_ama(dfr, init=0):
        global calc_Lux_STO_ama
        if init == 1:
            calc_Lux_STO_ama = 0.0
            return
        calc_Lux_STO_ama = calc_Lux_STO_ama + dfr[alphacol] * (dfr[osccol] - calc_Lux_STO_ama)
        return calc_Lux_STO_ama
    calc_ama(None, init=1)
    dtS[amacol] = dtS.apply(calc_ama, axis = 1)
    dtS[histcol] = ta.EMA((dtS[osccol]- dtS[amacol]),timeperiod = smooth)

    return dtS[osccol] * 100,  dtS[amacol] * 100 , dtS[histcol]  * 100, dtS[sptcol]
 
class Github_viktors1982_trading__LuxOSC__20220718_143423(IStrategy):

    INTERFACE_VERSION = 2

    # Buy hyperspace params:
    buy_params = {
        "cross_buy": -100,
        "length_buy": 6,
        "mult_buy": 9,
        "smooth_buy": 72,
    }

    # Sell hyperspace params:
    sell_params = {
        "cross_sell": 50,
    }
    length_buy = IntParameter(2, 100, default= int(buy_params['length_buy']), space='buy')
    mult_buy = IntParameter(2, 100, default= int(buy_params['mult_buy']), space='buy')
    smooth_buy = IntParameter(2, 100, default= int(buy_params['smooth_buy']), space='buy')
    cross_buy = IntParameter(-100, 100, default= int(buy_params['cross_buy']), space='buy')
    cross_sell = IntParameter(-100, 100, default= int(sell_params['cross_sell']), space='sell')
    
    stoploss = -0.99

    # Trailing stoploss
    trailing_stop = False
   

    timeframe = '5m'
    custom_info = {}
  
    process_only_new_candles = False

  
    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = False

   
    startup_candle_count: int = 30

    # 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'
    }
    
    plot_config = {
        # Main plot indicators (Moving averages, ...)
        'main_plot': {
            'supertrend': {'color': 'green'},
        },
        'subplots': {
            # Subplots - each dict defines one additional plot
            "OSC": {
                'osc': {'color': 'blue'},
                'signal': {'color': 'orange'},
                'histogram': {'color': 'green'},
            } 
        }
    }

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        
        dataframe['osc'],  dataframe['signal'] , dataframe['histogram'], dataframe['supertrend'] = LUX_SuperTrendOscillator(dataframe, length = int(self.length_buy.value), mult = int(self.mult_buy.value), smooth = int(self.smooth_buy.value)) 
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                
                (qtpylib.crossed_above(dataframe['osc'], int(self.cross_buy.value))) &  
                (dataframe['supertrend'] >  dataframe['close'] ) &
                (dataframe['volume'] > 0)  
            ),
            'buy'] = 1
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (qtpylib.crossed_below(dataframe['osc'], int(self.cross_sell.value))) &  
                (dataframe['volume'] > 0)  
            ),
            'sell'] = 1
        return dataframe
    