# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/KC_BB.py

from freqtrade.strategy.interface import IStrategy
from typing import Dict, List
from functools import reduce
from pandas import DataFrame, Series, DatetimeIndex, merge
from datetime import datetime, timedelta


import talib.abstract as ta
import numpy as np
import pandas_ta as pta
from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter, stoploss_from_open
import freqtrade.vendor.qtpylib.indicators as qtpylib

class Github_remiotore_freqtrade__KC_BB__20260111_210550(IStrategy):
    """

    author @jilv220
    Github_remiotore_freqtrade__KC_BB__20260111_210550 Stra

    """



    minimal_roi = {
        "0": 20.5
    }

    stoploss = -0.99

    use_custom_stoploss = True

    timeframe = '5m'

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
                        current_rate: float, current_profit: float, **kwargs) -> float:
        sl_new = 1

        if (current_profit > 0.2):
            sl_new = 0.05
        elif (current_profit > 0.1):
            sl_new = 0.03
        elif (current_profit > 0.06):
            sl_new = 0.02
        elif (current_profit > 0.03):
            sl_new = 0.015

        return sl_new


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

        dataframe['trange'] = ta.TRANGE(dataframe)

        dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
        dataframe['sma_28'] = ta.SMA(dataframe, timeperiod=28)

        dataframe['range_ma_20'] = ta.SMA(dataframe['trange'], 20)
        dataframe['kc_upperband_20_2'] = dataframe['sma_20'] + dataframe['range_ma_20'] * 2
        dataframe['kc_lowerband_20_2'] = dataframe['sma_20'] - dataframe['range_ma_20'] * 2

        dataframe['range_ma_28'] = ta.SMA(dataframe['trange'], 28)
        dataframe['kc_upperband_28_1'] = dataframe['sma_28'] + dataframe['range_ma_28']
        dataframe['kc_lowerband_28_1'] = dataframe['sma_28'] - dataframe['range_ma_28']

        bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
        dataframe['bb_lowerband2'] = bollinger2['lower']
        dataframe['bb_middleband2'] = bollinger2['mid']
        dataframe['bb_upperband2'] = bollinger2['upper']

        dataframe['kc_bb_delta'] =  ( dataframe['kc_lowerband_20_2'] - dataframe['bb_lowerband2'] ) / dataframe['bb_lowerband2'] * 100

        heikinashi = qtpylib.heikinashi(dataframe)
        dataframe['ha_open'] = heikinashi['open']
        dataframe['ha_close'] = heikinashi['close']
        dataframe['ha_high'] = heikinashi['high']
        dataframe['ha_low'] = heikinashi['low']

        dataframe['ha_closedelta'] = (dataframe['ha_close'] - dataframe['ha_close'].shift()).abs()

        rsi = ta.RSI(dataframe)
        dataframe["rsi"] = rsi
        rsi = 0.1 * (rsi - 50)
        dataframe["fisher"] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)

        dataframe['ema_fast'] = ta.EMA(dataframe['ha_close'], timeperiod=3)

        dataframe['r_14'] = williams_r(dataframe, period=14)

        return dataframe

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

        dataframe.loc[

                (dataframe['kc_lowerband_28_1'] < dataframe['bb_upperband2']) &
                (dataframe['kc_lowerband_28_1'] > dataframe['bb_lowerband2']) &
                (dataframe['kc_bb_delta'] < 1.5) &
                (dataframe['kc_bb_delta'] > 0.928) &
                (dataframe['r_14'] < -80) &
                (dataframe['r_14'] > -90) &
                (dataframe['ha_closedelta'] > dataframe['ha_close'] * 0.008)

            ,'buy'] = 1

        return dataframe

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

        dataframe.loc[

                (dataframe['fisher'] > 0.39075) &
                (dataframe['ha_high'].le(dataframe['ha_high'].shift(1))) &
                (dataframe['ha_high'].shift(1).le(dataframe['ha_high'].shift(2))) &
                (dataframe['ha_close'].le(dataframe['ha_close'].shift(1))) &
                (dataframe['ema_fast'] > dataframe['ha_close']) &
                (dataframe['ha_close'] * 0.99754 > dataframe['bb_middleband2']) &
                (dataframe['volume'] > 0)

            ,'sell'] = 1

        return dataframe

def williams_r(dataframe: DataFrame, period: int = 14) -> Series:
    """Williams %R, or just %R, is a technical analysis oscillator showing the current closing price in relation to the high and low
        of the past N days (for a given N). It was developed by a publisher and promoter of trading materials, Larry Williams.
        Its purpose is to tell whether a stock or commodity market is trading near the high or the low, or somewhere in between,
        of its recent trading range.
        The oscillator is on a negative scale, from âˆ’100 (lowest) up to 0 (highest).
    """

    highest_high = dataframe["high"].rolling(center=False, window=period).max()
    lowest_low = dataframe["low"].rolling(center=False, window=period).min()

    WR = Series(
        (highest_high - dataframe["close"]) / (highest_high - lowest_low),
        name=f"{period} Williams %R",
        )

    return WR * -100
