# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/E4ber.py
import logging
from functools import reduce
from datetime import datetime
from typing import Optional
from typing import Dict, List
import pandas as pd
import numpy as np
import math
import technical.indicators as ftt
import talib.abstract as ta
from pandas import DataFrame
from technical import qtpylib
from freqtrade.persistence import Trade
from datetime import datetime, timedelta

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


logger = logging.getLogger(__name__)

def EWO(dataframe, ema_length=5, ema2_length=3):
    df = dataframe.copy()
    ema1 = ta.EMA(df, timeperiod=ema_length)
    ema2 = ta.EMA(df, timeperiod=ema2_length)
    emadif = (ema1 - ema2) / df['close'] * 100
    return emadif


class Github_remiotore_freqtrade__E4ber__20260111_210550(IStrategy):

    """
          ______   __          __              __    __   ______   __    __        __     __    __             ______            
     /      \ /  |       _/  |            /  |  /  | /      \ /  \  /  |      /  |   /  |  /  |           /      \           
    /$$$$$$  |$$ |____  / $$ |    _______ $$ | /$$/ /$$$$$$  |$$  \ $$ |     _$$ |_  $$ |  $$ |  _______ /$$$$$$  |  _______ 
    $$ |  $$/ $$      \ $$$$ |   /       |$$ |/$$/  $$ ___$$ |$$$  \$$ |    / $$   | $$ |__$$ | /       |$$$  \$$ | /       |
    $$ |      $$$$$$$  |  $$ |  /$$$$$$$/ $$  $$<     /   $$< $$$$  $$ |    $$$$$$/  $$    $$ |/$$$$$$$/ $$$$  $$ |/$$$$$$$/ 
    $$ |   __ $$ |  $$ |  $$ |  $$ |      $$$$$  \   _$$$$$  |$$ $$ $$ |      $$ | __$$$$$$$$ |$$ |      $$ $$ $$ |$$      \ 
    $$ \__/  |$$ |  $$ | _$$ |_ $$ \_____ $$ |$$  \ /  \__$$ |$$ |$$$$ |      $$ |/  |     $$ |$$ \_____ $$ \$$$$ | $$$$$$  |
    $$    $$/ $$ |  $$ |/ $$   |$$       |$$ | $$  |$$    $$/ $$ | $$$ |______$$  $$/      $$ |$$       |$$   $$$/ /     $$/ 
     $$$$$$/  $$/   $$/ $$$$$$/  $$$$$$$/ $$/   $$/  $$$$$$/  $$/   $$//      |$$$$/       $$/  $$$$$$$/  $$$$$$/  $$$$$$$/  
                                                                       $$$$$$/                                               
Here be stonks
1. freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy RL_kdog_spot --freqaimodel ReinforcementLearnerSpot --spaces roi stoploss --timerange "$(date --date='-1 week' '+%Y%m%d')"-"$(date '+%Y%m%d')" -e 1000
2. freqtrade trade --logfile ./logs --freqaimodel ReinforcementLearnerSpot --strategy RL_kdog_spot
    """

    minimal_roi = {"0": 0.1, "2400": -1}

    plot_config = {
        "main_plot": {},
        "subplots": {
            "prediction": {"prediction": {"color": "blue"}},
            "target_roi": {
                "target_roi": {"color": "brown"},
            },
            "do_predict": {
                "do_predict": {"color": "brown"},
            },
            "&-action": {
                "&-action": {"color": "green"},
            },
        },
    }
    timeframe = '5m'



    process_only_new_candles = True
    stoploss = -0.3
    use_exit_signal = True
    startup_candle_count: int = 300
    can_short = False

    linear_roi_offset = DecimalParameter(0.00, 0.02, default=0.005, space="sell", optimize=False, load=True)
    max_roi_time_long = IntParameter(0, 800, default=400, space="sell", optimize=False, load=True)

    buy_params = {
        "base_nb_candles_buy": 12,
        "rsi_buy": 58,
        "low_offset": 0.987,
        "lambo2_ema_14_factor": 0.981,
        "lambo2_enabled": True,
        "lambo2_rsi_14_limit": 39,
        "lambo2_rsi_4_limit": 44,
        "buy_adx": 20,
        "buy_fastd": 20,
        "buy_fastk": 22,
        "buy_ema_cofi": 0.98,
        "buy_ewo_high": 4.179
    }

    sell_params = {
        "base_nb_candles_sell": 22,
        "high_offset": 1.014,
        "high_offset_2": 1.01
    }

    @property
    def protections(self):
        return [
            {
                "method": "CooldownPeriod",
                "stop_duration_candles": 5
            },
            {
                "method": "MaxDrawdown",
                "lookback_period_candles": 48,
                "trade_limit": 20,
                "stop_duration_candles": 4,
                "max_allowed_drawdown": 0.2
            },
            {
                "method": "StoplossGuard",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": 2,
                "only_per_pair": False
            },
            {
                "method": "LowProfitPairs",
                "lookback_period_candles": 6,
                "trade_limit": 2,
                "stop_duration_candles": 60,
                "required_profit": 0.02
            },
            {
                "method": "LowProfitPairs",
                "lookback_period_candles": 24,
                "trade_limit": 4,
                "stop_duration_candles": 2,
                "required_profit": 0.01
            }
        ]

    minimal_roi = {
        "0": 0.99,
        
    }

    stoploss = -0.99

    base_nb_candles_buy = IntParameter(8, 20, default=buy_params['base_nb_candles_buy'], space='buy', optimize=False)
    base_nb_candles_sell = IntParameter(8, 20, default=sell_params['base_nb_candles_sell'], space='sell', optimize=False)
    low_offset = DecimalParameter(0.985, 0.995, default=buy_params['low_offset'], space='buy', optimize=True)
    high_offset = DecimalParameter(1.005, 1.015, default=sell_params['high_offset'], space='sell', optimize=True)
    high_offset_2 = DecimalParameter(1.010, 1.020, default=sell_params['high_offset_2'], space='sell', optimize=True)

    lambo2_ema_14_factor = DecimalParameter(0.8, 1.2, decimals=3,  default=buy_params['lambo2_ema_14_factor'], space='buy', optimize=True)
    lambo2_rsi_4_limit = IntParameter(5, 60, default=buy_params['lambo2_rsi_4_limit'], space='buy', optimize=True)
    lambo2_rsi_14_limit = IntParameter(5, 60, default=buy_params['lambo2_rsi_14_limit'], space='buy', optimize=True)

    fast_ewo = 50
    slow_ewo = 200

    rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=False)

    is_optimize_cofi = False
    buy_ema_cofi = DecimalParameter(0.96, 0.98, default=0.97 , optimize = is_optimize_cofi)
    buy_fastk = IntParameter(20, 30, default=20, optimize = is_optimize_cofi)
    buy_fastd = IntParameter(20, 30, default=20, optimize = is_optimize_cofi)
    buy_adx = IntParameter(20, 30, default=30, optimize = is_optimize_cofi)
    buy_ewo_high = DecimalParameter(2, 12, default=3.553, optimize = is_optimize_cofi)

    atr_length = IntParameter(10, 30, default=14, space='buy', optimize=True)
    increment = DecimalParameter(low=1.0005, high=1.001, default=1.0007, decimals=4 ,space='buy', optimize=True, load=True)

    use_custom_stoploss = True
    process_only_new_candles = True

    last_entry_price = None















    def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata, **kwargs) -> DataFrame:
        if metadata["tf"] != "5m":
            dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
            dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period)
            dataframe["%-rocr-period"] = ta.ROCR(dataframe, timeperiod=period)
            dataframe["%-chop-period"] = qtpylib.chopiness(dataframe, period)
            dataframe["%-linear-period"] = ta.LINEARREG_ANGLE(
                dataframe['close'], timeperiod=period)
            dataframe["%-atr-period"] = ta.ATR(dataframe, timeperiod=period)
            dataframe["%-atr-periodp"] = dataframe["%-atr-period"] / \
                dataframe['close']

        return dataframe

    def feature_engineering_expand_basic(self, dataframe, metadata, **kwargs):
        if metadata["tf"] != "5m":
            dataframe['%-OHLC4'] = (dataframe['open'] + dataframe['high'] + dataframe['low'] + dataframe['close']) / 4

            dataframe['%-max'] = dataframe['%-OHLC4'].rolling(4).max() / dataframe['%-OHLC4'] - 1
            dataframe['%-min'] = abs(dataframe['%-OHLC4'].rolling(4).min() / dataframe['%-OHLC4'] - 1)

            dataframe['%-max_l'] = dataframe['%-OHLC4'].rolling(120).max() / dataframe['%-OHLC4'] - 1
            dataframe['%-min_l'] = abs(dataframe['%-OHLC4'].rolling(120).min() / dataframe['%-OHLC4'] - 1)

            rolling_window = dataframe['%-OHLC4'].rolling(8) 
            rolling_max = rolling_window.max()
            rolling_min = rolling_window.min()

            ptp_value = rolling_window.apply(lambda x: np.ptp(x))

            dataframe['%-move'] = ptp_value / dataframe['%-OHLC4']
            dataframe['%-move_mean'] = dataframe['%-move'].mean()
            dataframe['%-move_mean_x'] = dataframe['%-move'].mean() * 1.6
            dataframe['%-exit_mean'] = rolling_min * (1 + dataframe['%-move_mean'])
            dataframe['%-exit_mean_x'] = rolling_min * (1 + dataframe['%-move_mean_x'])
            dataframe['%-enter_mean'] = rolling_max * (1 - dataframe['%-move_mean'])
            dataframe['%-enter_mean_x'] = rolling_max * (1 - dataframe['%-move_mean_x'])
            dataframe['%-atr_pcnt'] = (ta.ATR(dataframe, timeperiod=5) / dataframe['%-OHLC4'])
            dataframe["%-raw_volume"] = dataframe["volume"]
            dataframe["%-obv"] = ta.OBV(dataframe)

        return dataframe

    def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame:


        for val in self.base_nb_candles_buy.range:
            dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val)

        for val in self.base_nb_candles_sell.range:
            dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val)

        dataframe['%-ma_lo'] = dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * (self.low_offset.value)
        dataframe['%-hi'] = dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * (self.high_offset.value)
        dataframe['%-ma_hi_2'] = dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * (self.high_offset_2.value)

        dataframe['%-hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50)

        dataframe['%-HMA_SQZ'] = (((dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] - dataframe['%-hma_50']) 
            / dataframe[f'ma_buy_{self.base_nb_candles_buy.value}']) * 100)


        dataframe['zero'] = 0

        dataframe['%-EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)
        dataframe.loc[dataframe['%-EWO'] > 0, "EWO_UP"] = dataframe['%-EWO']
        dataframe.loc[dataframe['%-EWO'] < 0, "EWO_DN"] = dataframe['%-EWO']
        dataframe['EWO_UP'].ffill()
        dataframe['EWO_DN'].ffill()
        dataframe['%-EWO_MEAN_UP'] = dataframe['EWO_UP'].mean()
        dataframe['%-EWO_MEAN_DN'] = dataframe['EWO_DN'].mean()
        dataframe['%-EWO_UP_FIB'] = dataframe['%-EWO_MEAN_UP'] * 1.618
        dataframe['%-EWO_DN_FIB'] = dataframe['%-EWO_MEAN_DN'] * 1.618

        dataframe['%-rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['%-rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['%-rsi_slow'] = ta.RSI(dataframe, timeperiod=20)

        dataframe['%-ema_14'] = ta.EMA(dataframe, timeperiod=14)
        dataframe['%-rsi_4'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['%-rsi_14'] = ta.RSI(dataframe, timeperiod=14)

        stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0)
        dataframe['%-fastd'] = stoch_fast['fastd']
        dataframe['%-fastk'] = stoch_fast['fastk']
        dataframe['%-adx'] = ta.ADX(dataframe)
        dataframe['%-ema_8'] = ta.EMA(dataframe, timeperiod=8)

        dataframe['%-OHLC4'] = (dataframe['open'] + dataframe['high'] + dataframe['low'] + dataframe['close']) / 4

        dataframe['%-max'] = dataframe['%-OHLC4'].rolling(12).max() / dataframe['%-OHLC4'] - 1
        dataframe['%-min'] = abs(dataframe['%-OHLC4'].rolling(12).min() / dataframe['%-OHLC4'] - 1)

        dataframe['%-max_l'] = dataframe['%-OHLC4'].rolling(360).max() / dataframe['%-OHLC4'] - 1
        dataframe['%-min_l'] = abs(dataframe['%-OHLC4'].rolling(360).min() / dataframe['%-OHLC4'] - 1)

        rolling_window = dataframe['%-OHLC4'].rolling(48) 
        rolling_max = rolling_window.max()
        rolling_min = rolling_window.min()

        ptp_value = rolling_window.apply(lambda x: np.ptp(x))

        dataframe['move'] = ptp_value / dataframe['%-OHLC4']
        dataframe['mov'] = dataframe['move']
        dataframe.loc[dataframe['%-OHLC4'] <  dataframe['%-OHLC4'].shift(48), 'mov'] = dataframe['mov'] * -1
        dataframe.loc[dataframe['mov'] > 0, '%-mov_mean_up'] = dataframe['mov']
        dataframe.loc[dataframe['mov'] < 0, '%-mov_mean_dn'] = dataframe['mov']
        dataframe['%-mov_mean_up'].ffill()
        dataframe['%-mov_mean_dn'].ffill()
        dataframe['%-mov_mean_up'] = dataframe['%-mov_mean_up'].mean() * 1.618
        dataframe['%-mov_mean_dn'] = dataframe['%-mov_mean_dn'].mean() * 1.618
        dataframe['%-move_mean'] = dataframe['move'].mean()
        dataframe['%-move_mean_x'] = dataframe['move'].mean() * 1.6
        dataframe['%-exit_mean'] = rolling_min * (1 + dataframe['%-move_mean'])
        dataframe['%-exit_mean_x'] = rolling_min * (1 + dataframe['%-move_mean_x'])
        dataframe['%-enter_mean'] = rolling_max * (1 - dataframe['%-move_mean'])
        dataframe['%-enter_mean_x'] = rolling_max * (1 - dataframe['%-move_mean_x'])
        dataframe['%-atr_pcnt'] = (ta.ATR(dataframe, timeperiod=5) / dataframe['%-OHLC4'])
        dataframe[f"%-raw_close"] = dataframe["close"]
        dataframe[f"%-raw_open"] = dataframe["open"]
        dataframe[f"%-raw_high"] = dataframe["high"]
        dataframe[f"%-raw_low"] = dataframe["low"]

        return dataframe


    def set_freqai_targets(self, dataframe, **kwargs):
        dataframe['OHLC4'] = (dataframe['open'] + dataframe['high'] + dataframe['low'] + dataframe['close']) / 4

        rolling_window = dataframe['OHLC4'].rolling(48) 
        rolling_max = rolling_window.max()
        rolling_min = rolling_window.min()

        ptp_value = rolling_window.apply(lambda x: np.ptp(x))

        dataframe['move'] = ptp_value / dataframe['OHLC4']
        dataframe['mov'] = dataframe['move']
        dataframe.loc[dataframe['OHLC4'] <  dataframe['OHLC4'].shift(48), 'mov'] = dataframe['mov'] * -1
        dataframe['&s-move_target'] = dataframe['mov']
      
        return dataframe

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

        dataframe = self.freqai.start(dataframe, metadata, self)

        for val in self.base_nb_candles_buy.range:
            dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val)

        for val in self.base_nb_candles_sell.range:
            dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val)

        dataframe['ma_lo'] = dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * (self.low_offset.value)
        dataframe['ma_hi'] = dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * (self.high_offset.value)
        dataframe['ma_hi_2'] = dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * (self.high_offset_2.value)

        dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50)

        dataframe['HMA_SQZ'] = (((dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] - dataframe['hma_50']) 
            / dataframe[f'ma_buy_{self.base_nb_candles_buy.value}']) * 100)

        dataframe.loc[dataframe['HMA_SQZ'] > 0, "HMA_SQZ_UP"] = dataframe['HMA_SQZ']
        dataframe.loc[dataframe['HMA_SQZ'] < 0, "HMA_SQZ_DN"] = dataframe['HMA_SQZ']
        dataframe['HMA_SQZ_UP'].ffill()
        dataframe['HMA_SQZ_DN'].ffill()
        dataframe['HMA_SQZ_MEAN_UP'] = dataframe['HMA_SQZ_UP'].mean()
        dataframe['HMA_SQZ_MEAN_DN'] = dataframe['HMA_SQZ_DN'].mean()


        dataframe['zero'] = 0

        dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)
        dataframe.loc[dataframe['EWO'] > 0, "EWO_UP"] = dataframe['EWO']
        dataframe.loc[dataframe['EWO'] < 0, "EWO_DN"] = dataframe['EWO']
        dataframe['EWO_UP'].ffill()
        dataframe['EWO_DN'].ffill()
        dataframe['EWO_MEAN_UP'] = dataframe['EWO_UP'].mean()
        dataframe['EWO_MEAN_DN'] = dataframe['EWO_DN'].mean()
        dataframe['EWO_UP_FIB'] = dataframe['EWO_MEAN_UP'] * 1.618
        dataframe['EWO_DN_FIB'] = dataframe['EWO_MEAN_DN'] * 1.618

        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20)

        dataframe['ema_14'] = ta.EMA(dataframe, timeperiod=14)
        dataframe['rsi_4'] = ta.RSI(dataframe, timeperiod=4)
        dataframe['rsi_14'] = ta.RSI(dataframe, timeperiod=14)

        stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0)
        dataframe['fastd'] = stoch_fast['fastd']
        dataframe['fastk'] = stoch_fast['fastk']
        dataframe['adx'] = ta.ADX(dataframe)
        dataframe['ema_8'] = ta.EMA(dataframe, timeperiod=8)

        dataframe['OHLC4'] = (dataframe['open'] + dataframe['high'] + dataframe['low'] + dataframe['close']) / 4


        dataframe['max'] = dataframe['OHLC4'].rolling(4).max() / dataframe['OHLC4'] - 1
        dataframe['min'] = abs(dataframe['OHLC4'].rolling(4).min() / dataframe['OHLC4'] - 1)

        dataframe['max_l'] = dataframe['OHLC4'].rolling(120).max() / dataframe['OHLC4'] - 1
        dataframe['min_l'] = abs(dataframe['OHLC4'].rolling(120).min() / dataframe['OHLC4'] - 1)

        rolling_window = dataframe['OHLC4'].rolling(48) 
        rolling_max = rolling_window.max()
        rolling_min = rolling_window.min()

        ptp_value = rolling_window.apply(lambda x: np.ptp(x))

        dataframe['move'] = ptp_value / dataframe['OHLC4']
        dataframe['move_mean'] = dataframe['move'].mean()
        dataframe['move_mean_x'] = dataframe['move'].mean() * 1.6
        dataframe['exit_mean'] = rolling_min * (1 + dataframe['move_mean'])
        dataframe['exit_mean_x'] = rolling_min * (1 + dataframe['move_mean_x'])
        dataframe['enter_mean'] = rolling_max * (1 - dataframe['move_mean'])
        dataframe['enter_mean_x'] = rolling_max * (1 - dataframe['move_mean_x'])
        dataframe['atr_pcnt'] = (ta.ATR(dataframe, timeperiod=5) / dataframe['OHLC4'])

        dataframe.loc[dataframe['&s-move_target'] >= 0, "move_target_up"] = dataframe['&s-move_target']
        dataframe.loc[dataframe['&s-move_target'] <= 0, "move_target_dn"] = dataframe['&s-move_target']
        dataframe['smooth_move'] = ta.SMA(dataframe['&s-move_target'], 5)
        dataframe["move_target_up"].ffill()
        dataframe["move_target_dn"].ffill()
        dataframe["move_target_mean_up"] = dataframe["move_target_up"].mean()
        dataframe["move_target_mean_dn"] = dataframe["move_target_dn"].mean()
        dataframe["move_target_fib_up"] = dataframe["move_target_mean_up"] * 1.618
        dataframe["move_target_fib_dn"] = dataframe["move_target_mean_dn"] * 1.618

        return dataframe

    def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame:

        lambo2 = (
            (df['close'] < (df['ema_14'] * self.lambo2_ema_14_factor.value)) &
            (df['rsi_4'] < int(self.lambo2_rsi_4_limit.value)) &
            (df['rsi_14'] < int(self.lambo2_rsi_14_limit.value)) &
            (df['atr_pcnt'] > df['min_l']) &
            (df['do_predict'] == 1) &

            (df['volume'] > 0) 
        )
        df.loc[lambo2, 'enter_long'] = 1
        df.loc[lambo2, 'enter_tag'] = 'lambo '

        buy1ewo = (
            (df['rsi_fast'] < 35 ) &
            (df['close'] < df['ma_lo']) &
            (df['EWO'] > df['EWO_MEAN_UP']) &
            (df['close'] < df['enter_mean_x']) &
            (df['close'].shift() < df['enter_mean_x'].shift()) &
            (df['rsi'] < self.rsi_buy.value) &
            (df['atr_pcnt'] > df['min']) &
            (df['do_predict'] == 1) &

            (df['volume'] > 0) 
        )
        df.loc[buy1ewo, 'enter_long'] = 1
        df.loc[buy1ewo, 'enter_tag'] = 'buy1ewo'

        buy2ewo = (
            (df['rsi_fast'] < 35) &
            (df['close'] < df['ma_lo']) &
            (df['EWO'] < df['EWO_DN_FIB']) &
            (df['atr_pcnt'] > df['min']) &
            (df['do_predict'] == 1) &

            (df['volume'] > 0) 
        )
        df.loc[buy2ewo, 'enter_long'] = 1
        df.loc[buy2ewo, 'enter_tag'] = 'buy2ewo'

        is_cofi = (
            (df['open'] < df['ema_8'] * self.buy_ema_cofi.value) &
            (qtpylib.crossed_above(df['fastk'], df['fastd'])) &
            (df['fastk'] < self.buy_fastk.value) &
            (df['fastd'] < self.buy_fastd.value) &
            (df['adx'] > self.buy_adx.value) &
            (df['EWO'] > df['EWO_MEAN_UP']) &
            (df['atr_pcnt'] > df['min']) &
            (df['do_predict'] == 1) &

            (df['volume'] > 0) 
            )
        df.loc[is_cofi, 'enter_long'] = 1
        df.loc[is_cofi, 'enter_tag'] = 'cofi'









        return df

    def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame:

        condition5 = (
                (df['close'] > df['hma_50']) &
                (df['close'] > df['ma_hi_2']) &
                (df['close'] > df['exit_mean_x']) &
                (df['rsi'] > 50 ) &
                (df['do_predict'] == 1) &

                (df['volume'] > 0 ) &
                (df['rsi_fast']>df['rsi_slow'])

            )
        df.loc[condition5, 'exit_long'] = 1
        df.loc[condition5, 'exit_tag'] = 'Close > Offset Hi 2'


        
        condition6 = (
                (df['close'] < df['hma_50']) &
                (df['close'] > df['ma_hi']) &
                (df['volume'] > 0) &
                (df['do_predict'] == 1) &

                (df['rsi_fast']>df['rsi_slow'])

            )
        df.loc[condition6, 'exit_long'] = 1
        df.loc[condition6, 'exit_tag'] = 'Close > Offset Hi 1'









        return df



























































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


        dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
        current_candle = dataframe.iloc[-1].squeeze()
        SLT1 = current_candle['move_mean']
        SL1 = 0.013
        SLT2 = current_candle['move_mean_x']
        SL2 = current_candle['move_mean_x'] - current_candle['move_mean']
        display_profit = current_profit * 100
        slt1 = SLT1 * 100
        sl1 = SL1 * 100
        slt2 = SLT2 * 100
        sl2 = SL2 * 100


        if current_candle['max_l'] > .003: #ignore stoploss if setting new highs
            if SLT2 is not None and current_profit > SLT2:
                self.dp.send_msg(f'*** {pair} *** Profit {display_profit:.2f}% - {slt2:.2f}%/{sl2:.2f}% activated')
                logger.info(f'*** {pair} *** Profit {display_profit:.2f}% - {slt2:.2f}%/{sl2:.2f}% activated')
                return SL2
            if SLT1 is not None and current_profit > SLT1:
                self.dp.send_msg(f'*** {pair} *** Profit {display_profit:.2f}% - {SLT1:.2f}%/{SL1:.2f}% activated')
                logger.info(f'*** {pair} *** Profit {display_profit:.2f}% - {slt1:.2f}%/{sl1:.2f}% activated')
                return SL1

        else:
            if SLT1 is not None and current_profit > SL1:
                self.dp.send_msg(f'*** {pair} *** Profit {display_profit:.2f}% SWINGING FOR THE MOON!!!')
                logger.info(f'*** {pair} *** Profit {display_profit:.2f}% SWINGING FOR THE MOON!!!')
                return 0.99

        return self.stoploss


    def custom_entry_price(self, pair: str, trade: Optional['Trade'], current_time: datetime, proposed_rate: float,
                           entry_tag: Optional[str], side: str, **kwargs) -> float:

        dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
                                                                timeframe=self.timeframe)

        entry_price = (dataframe['close'].iat[-1] + dataframe['open'].iat[-1] + proposed_rate + proposed_rate) / 4
        logger.info(f"{pair} Using Entry Price: {entry_price} | close: {dataframe['close'].iat[-1]} open: {dataframe['open'].iat[-1]} proposed_rate: {proposed_rate}") 

        if self.last_entry_price is not None and abs(entry_price - self.last_entry_price) < 0.0001:  # Tolerance for floating-point comparison
            entry_price *= self.increment.value # Increment by 0.2%
            logger.info(f"{pair} Incremented entry price: {entry_price} based on previous entry price : {self.last_entry_price}.")

        self.last_entry_price = entry_price

        return entry_price


    def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
                           rate: float, time_in_force: str, exit_reason: str,
                           current_time: datetime, **kwargs) -> bool:
        
        dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
        last_candle = dataframe.iloc[-1].squeeze()

        if exit_reason == 'roi' and (last_candle['max_l'] < 0.003):
            return False


        if exit_reason == 'Down Trend Soon' and trade.calc_profit_ratio(rate) < 0.003:
            logger.info(f"{trade.pair} Waiting for Profit")
            self.dp.send_msg(f'{trade.pair} Waiting for Profit')
            return False

        if exit_reason == 'roi' and trade.calc_profit_ratio(rate) < 0.003:
            logger.info(f"{trade.pair} ROI is below 0")
            self.dp.send_msg(f'{trade.pair} ROI is below 0')
            return False

        if exit_reason == 'partial_exit' and trade.calc_profit_ratio(rate) < 0:
            logger.info(f"{trade.pair} partial exit is below 0")
            self.dp.send_msg(f'{trade.pair} partial exit is below 0')
            return False

        if exit_reason == 'trailing_stop_loss' and trade.calc_profit_ratio(rate) < 0:
            logger.info(f"{trade.pair} trailing stop price is below 0")
            self.dp.send_msg(f'{trade.pair} trailing stop price is below 0')
            return False

        return True

    def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, **kwargs):

        if current_profit < -0.04 and (current_time - trade.open_date_utc).days >= 4:
            return 'unclog'

    use_sell_signal = True
    sell_profit_only = True
    sell_profit_offset = 0.01
    ignore_roi_if_buy_signal = False

    def pct_change(a, b):
        return (b - a) / a