# source: https://raw.githubusercontent.com/RoboticAutomations/freqtradestrategies/52c4bd40414645f079a980cf4486dc7af4061efb/AIRA%20-%20open%20code%20v2/strategies/channels/KC_NOBB.py
# directory_url: https://github.com/RoboticAutomations/freqtradestrategies/blob/main/AIRA - open code v2/strategies/channels/
# User: RoboticAutomations
# Repository: freqtradestrategies
# --------------------from datetime import datetime, timedelta
from typing import Optional, Dict, Any, Callable, List, Union
import numpy as np  # noqa
from pandas import DataFrame
import talib.abstract as ta
from freqtrade.persistence import Trade
from freqtrade.strategy import (DecimalParameter,
                                IntParameter, IStrategy, stoploss_from_absolute, informative)
from freqtrade.optimize.space import SKDecimal, Dimension 
import freqtrade.vendor.qtpylib.indicators as qtpylib


class Github_RoboticAutomations_freqtradestrategies__KC_NOBB__20260915_233254(IStrategy):

    minimal_roi = {
        "0": 0.6,
        "4320": 0
    }

    order_types = {
            'entry': 'limit',
            'exit': 'limit',
            'stoploss': 'limit',
            'emergency_exit': 'market',
            'force_exit': 'market',
            'force_entry': 'market',
            'stoploss_on_exchange': True,
            'stoploss_on_exchange_interval': 60,
            'stoploss_on_exchange_limit_ratio': 0.99
    }

    stoploss = -0.6
    can_short = True

    trailing_stop = False
    trailing_only_offset_is_reached = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.013

    timeframe = '5m'
    process_only_new_candles = True
    startup_candle_count = 399

    abs_long = DecimalParameter(1.0, 8.0, decimals=1, default=3.0, space="buy")
    abs_short = DecimalParameter(1.0, 8.0, decimals=1, default=3.0, space="sell")
    abs_long_12h = DecimalParameter(1.0, 8.0, decimals=1, default=3.0, space="buy")
    abs_short_12h = DecimalParameter(1.0, 8.0, decimals=1, default=3.0, space="sell")
    linear_2h = IntParameter(5, 25, default=11, space="buy")
    linear_12h = IntParameter(5, 25, default=11, space="sell")
    dm = IntParameter(5, 35, default=14, space="sell")

    @informative('30m')
    def populate_indicators_30m(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['rsi'] = ta.RSI(dataframe)
        dataframe['rsi_ma'] = ta.SMA(dataframe['rsi'])
        return dataframe 

    
    @informative('8h')
    def populate_indicators_8h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['rsi'] = ta.RSI(dataframe)
        for val in self.linear_12h.range:
            dataframe[f'linear_open_{val}'] = ta.LINEARREG(dataframe['open'], timeperiod=val)
            dataframe[f'linear_close_{val}'] = ta.LINEARREG(dataframe['close'], timeperiod=val)
        return dataframe

    @informative('4h')
    def populate_indicators_4h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        bollinger = ta.BBANDS(dataframe,timeperiod=20)
        dataframe['bb_lowerband'] = bollinger['lowerband']
        dataframe['bb_middleband'] = bollinger['middleband']
        dataframe['bb_upperband'] = bollinger['upperband']
        dataframe["bb_width"] = ((dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband'] * 100)

        return dataframe
    
    @informative('2h')
    def populate_indicators_2h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        for val in self.linear_2h.range:
            dataframe[f'linear_open_{val}'] = ta.LINEARREG(dataframe['open'], timeperiod=val)
            dataframe[f'linear_close_{val}'] = ta.LINEARREG(dataframe['close'], timeperiod=val)
        for val in self.dm.range:
            dataframe[f'plus_dm_{val}'] = ta.PLUS_DI(dataframe, val)
            dataframe[f'minus_dm_{val}'] = ta.MINUS_DI(dataframe, val)
        for val in self.abs_long.range:
            dataframe[f'abs_long_{val}'] = val
        for val in self.abs_short.range:
            dataframe[f'abs_short_{val}'] = val

        return dataframe


    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        keltner = qtpylib.keltner_channel(dataframe,window=20, atrs=2.6)
        dataframe["kc_upperband"] = keltner["upper"]
        dataframe["kc_lowerband"] = keltner["lower"]
        dataframe["kc_middleband"] = keltner["mid"]

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            (
                (
                    (dataframe[f'linear_close_{self.linear_2h.value}_2h'] > dataframe[f'linear_open_{self.linear_2h.value}_2h']) &
                    (dataframe[f'linear_close_{self.linear_12h.value}_8h'] > dataframe[f'linear_open_{self.linear_12h.value}_8h']) &
                    ((dataframe[f'plus_dm_{self.dm.value}_2h'] - dataframe[f'minus_dm_{self.dm.value}_2h']).abs() > dataframe[f'abs_long_{self.abs_long.value}_2h']) &
                    (dataframe['rsi_8h'] < 72) &
                    (dataframe['rsi_30m'] > dataframe['rsi_ma_30m']) &
                    (dataframe['bb_width_4h'] > 7.0) &

                    (dataframe['low'] < dataframe['kc_lowerband']) 
                )
           
            ),
            'enter_long'] = 1
        

        dataframe.loc[
            (
                (
                    (dataframe[f'linear_close_{self.linear_2h.value}_2h'] < dataframe[f'linear_open_{self.linear_2h.value}_2h']) &
                    (dataframe[f'linear_close_{self.linear_12h.value}_8h'] < dataframe[f'linear_open_{self.linear_12h.value}_8h']) &
                    ((dataframe[f'plus_dm_{self.dm.value}_2h'] - dataframe[f'minus_dm_{self.dm.value}_2h']).abs() > dataframe[f'abs_short_{self.abs_short.value}_2h']) &
                    (dataframe['rsi_8h'] > 28) &
                    (dataframe['rsi_30m'] < dataframe['rsi_ma_30m']) &
                    (dataframe['bb_width_4h'] > 7.0) &

                    (dataframe['high'] > dataframe['kc_upperband']) 
                )

            ),
            'enter_short'] = 1

        
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe.loc[
            ((dataframe['enter_long'] == 1)),
            'exit_short'] = 1
        dataframe.loc[
            ((dataframe['enter_short'] == 1)),
            'exit_long'] = 1
        
        return dataframe


    def leverage(self, pair: str, current_time: datetime, current_rate: float,
                 proposed_leverage: float, max_leverage: float, side: str,
                 **kwargs) -> float:
        return 15.0
