# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/cipher5m.py
import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame
from pandas.core.series import Series
from functools import reduce
import pandas_ta as pta
import technical.indicators as technicali

from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
                                IStrategy, IntParameter)


import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib

rangeUpper = 60
rangeLower = 5
def valuewhen(dataframe, condition, source, occurrence):
    copy = dataframe.copy()
    copy['colFromIndex'] = copy.index
    copy = copy.sort_values(by=[condition, 'colFromIndex'], ascending=False).reset_index(drop=True)
    copy['valuewhen'] = np.where(copy[condition] > 0, copy[source].shift(-occurrence), 100)
    copy['valuewhen'] = copy['valuewhen'].fillna(100)
    copy['barrsince'] = copy['colFromIndex'] - copy['colFromIndex'].shift(-occurrence)
    copy.loc[
        (
            (rangeLower <= copy['barrsince']) &
            (copy['barrsince']  <= rangeUpper)
        )
    , "in_range"] = 1
    copy['in_range'] = copy['in_range'].fillna(0)
    copy = copy.sort_values(by=['colFromIndex'], ascending=True).reset_index(drop=True)
    return copy['valuewhen'], copy['in_range']

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

def wavetrend(df:DataFrame) -> Series:

    n1 = 9  # Channel Length
    n2 = 12  # Average Length
    ap = (df['high'] + df['low'] + df['close']) / 3  # HLC3

    esa = ta.EMA(ap, timeperiod=3)
    d = ta.EMA(abs(ap - esa), timeperiod=9)
    ci = (ap - esa) / (0.015 * d)
    wt1 = ta.EMA(ci, timeperiod=n2)
    wt2 = ta.SMA(wt1, timeperiod=3)
    wtVWAP = wt1 - wt2

    return pd.Series(data={
        "wt1": wt1,
        "wt2": wt2,
        "wtVWAP": wtVWAP
        })

def hlc3(df):
    return (df['high'] + df['low'] + df['close']) / 3

def fractalize(osrc):
    fcopy = osrc.copy()
    top_fractal = fcopy.shift(4) < fcopy.shift (2) & fcopy.shift(3) < fcopy.shift(2) & fcopy.shift(2) > fcopy.shift(1) & fcopy.shift(2) > fcopy
    bot_fractal = fcopy.shift(4) > fcopy.shift (2) & fcopy.shift(3) > fcopy.shift(2) & fcopy.shift(2) < fcopy.shift(1) & fcopy.shift(2) < fcopy
   
class Github_remiotore_freqtrade__cipher5m__20260111_210550(IStrategy):


    INTERFACE_VERSION = 2

    '''minimal_roi = {
        "0": 0.438,
        "86": 0.162,
        "241": 0.061,
        "435": 0
    }'''
    minimal_roi = {
        "0": 0.191,
        "12": 0.066,
        "65": 0.018,
        "185": 0
    }

    stoploss = -0.329

    
    buy_params = {
        "buy_aroondown": 40,
        "buy_aroonup": 85,
        "buy_arrondown_cat": False,
        "buy_arronup_cat": False,
        "buy_mfi": 46,
        "buy_schaff_cat": False,
        "buy_schafff_val": 31,
        "buy_vwap_cat": True,
        "buy_wt_oversold": -30,
        "ewo_high": 4.839,
        "fast_ewo": 57,
        "rsi_buy": 58,
        "slow_ewo": 163,
        "use_bull": False,
        "use_hidden_bull": False,
    }

    sell_params = {
        "sell_aroondown": 100,
        "sell_aroonup": 27,
        "sell_arrondown_cat": True,
        "sell_arronup_cat": True,
        "sell_mfi": 18,
        "sell_schaff_cat": True,
        "sell_schafff_val": 68,
        "sell_vwap_cat": True,
        "sell_wt_overbought": 53,
        "use_bear": True,
        "use_hidden_bear": False,
    }

    trailing_stop = True
    trailing_stop_positive = 0.255
    trailing_stop_positive_offset = 0.329
    trailing_only_offset_is_reached = False

    use_custom_stoploss = False

    timeframe = '5m'


    process_only_new_candles = True

    use_sell_signal = True
    sell_profit_only = False
    ignore_roi_if_buy_signal = True

    startup_candle_count: int = 30



    period = 10

    buy_mfi = IntParameter(10, 90, default = 50, space = 'buy' )
    fast_ewo = IntParameter(35, 75, default = 50, space = 'buy' )
    slow_ewo = IntParameter(130, 210, default = 200, space = 'buy' )
    buy_wt_oversold = IntParameter(-65, -30, default = -53, space = 'buy' )
    buy_aroonup = IntParameter(40, 100, default = 77, space = 'buy')
    buy_aroondown = IntParameter(0, 40, default = 24, space = 'buy' )
    buy_schafff_val = IntParameter(20, 40, default = 25, space = 'buy' )

    sell_mfi = IntParameter(10, 90, default = 50, space = 'sell' )
    sell_wt_overbought = IntParameter(30, 65, default = 53, space = 'sell' )
    sell_aroonup = IntParameter(0, 75, default = 24, space = 'sell' )
    sell_aroondown = IntParameter(40, 100, default = 68, space = 'sell')
    sell_schafff_val = IntParameter(65, 90, default = 75, space = 'sell' )


    buy_vwap_cat = CategoricalParameter([True, False], default = True, space = 'buy' )
    buy_arrondown_cat = CategoricalParameter([True, False], default = True, space = 'buy' )
    buy_arronup_cat = CategoricalParameter([True, False], default = True, space = 'buy' )

    buy_schaff_cat = CategoricalParameter([True, False], default = True, space = 'buy' )



    sell_vwap_cat = CategoricalParameter([True, False], default = True, space = 'sell' )
    sell_arronup_cat = CategoricalParameter([True, False], default = True, space = 'sell' )
    sell_arrondown_cat = CategoricalParameter([True, False], default = True, space = 'sell' )
    sell_schaff_cat = CategoricalParameter([True, False], default = True, space = 'sell' )

    
    use_bull = CategoricalParameter([True, False], default = True, space = 'buy' )
    use_hidden_bull = CategoricalParameter([True, False], default = True, space = 'buy' )
    use_bear = CategoricalParameter([True, False], default = True, space = 'sell' )
    use_hidden_bear = CategoricalParameter([True, False], default = True, space = 'sell' )
    ewo_high = DecimalParameter(0, 7.0, default=5.835, space='buy', optimize=True)
    rsi_buy = IntParameter(30, 70, default=50, space='buy', optimize=True)

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


        

        dataframe['mfi'] = ta.MFI(dataframe, timeperiod = 60)

        
        dataframe['vwap'] = qtpylib.rolling_vwap(dataframe)

        wavetrendi = wavetrend(dataframe)
        dataframe['wt1'] = wavetrendi['wt1']
        dataframe['wt2'] = wavetrendi['wt2']
        dataframe['wtVWAP'] = wavetrendi['wtVWAP']
        '''''
        wbl = 60
        dataframe['oscwt'] = dataframe['wt2'].fillna(0)

        dataframe['wtmin'] = dataframe['oscwt'].rolling(wbl).min()
        dataframe['wtprevmin'] = np.where(dataframe['wtmin'] > dataframe['wtmin'].shift(), dataframe['wtmin'].shift(), dataframe['wtmin'])
        dataframe.loc[
            (dataframe['oscwt '] == dataframe['wtprevmin']),
            'wtplfound'] = 1
        
        dataframe['wtplfound'] = dataframe['wtplfound'].fillna(0)

        dataframe['wtmax'] = dataframe['oscwt'].rolling(wbl).max()
        dataframe['wtprevmax'] = np.where(dataframe['wtmax'] < dataframe['wtmax'].shift(), dataframe['wtmax'].shift(), dataframe['wtmax'])
        dataframe.loc[
            (dataframe['oscwt'] == dataframe['wtprevmax']),

        'wtphfound'] = 1
        dataframe['phfound'] = dataframe['phfound'].fillna(0)

        dataframe['wtvaluwhen_plfoundd_osc'], dataframe['wtinrange_plfound_osc'] = valuewhen(dataframe, 'wtplfound', 'oscwt', 1)
        dataframe.loc[
            (
                (dataframe['oscwt'] > dataframe['wtvaluewhen_plfound_osc'])&
                ( dataframe['wtinrange_plfound_osc'] == 1)
            
            ),


        'wtoschl'] = 1
        dataframe['wtvaluewhen_plfound_low']
        
    ''' 



        

        dataframe['schaff'] = pta.stc(dataframe)

        aroon = ta.AROON(dataframe)
        dataframe['aroonup'] = aroon['aroonup']
        dataframe['aroondown'] = aroon['aroondown']

        dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo)

        len = 14
        src = dataframe['close']
        lbL = 10#5
        dataframe['osc'] = ta.RSI(src, len)
        dataframe['osc'] = dataframe['osc'].fillna(0)

        dataframe['min'] = dataframe['osc'].rolling(lbL).min()
        dataframe['prevMin'] = np.where(dataframe['min'] > dataframe['min'].shift(), dataframe['min'].shift(), dataframe['min'])
        dataframe.loc[
            (dataframe['osc'] == dataframe['prevMin'])
        , 'plFound'] = 1
        dataframe['plFound'] = dataframe['plFound'].fillna(0)

        dataframe['max'] = dataframe['osc'].rolling(lbL).max()
        dataframe['prevMax'] = np.where(dataframe['max'] < dataframe['max'].shift(), dataframe['max'].shift(), dataframe['max'])
        dataframe.loc[
            (dataframe['osc'] == dataframe['prevMax'])
        , 'phFound'] = 1
        dataframe['phFound'] = dataframe['phFound'].fillna(0)




        dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(dataframe, 'plFound', 'osc', 1)
        dataframe.loc[
            (
                (dataframe['osc'] > dataframe['valuewhen_plFound_osc']) &
                (dataframe['inrange_plFound_osc'] == 1)
             )
        , 'oscHL'] = 1


        dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(dataframe, 'plFound', 'low', 1)
        dataframe.loc[
            (dataframe['low'] < dataframe['valuewhen_plFound_low'])
            , 'priceLL'] = 1

        dataframe.loc[
            (
                (dataframe['priceLL'] == 1) &
                (dataframe['oscHL'] == 1) &
                (dataframe['plFound'] == 1)
            )
            , 'bullCond'] = 1























        dataframe['valuewhen_plFound_osc'], dataframe['inrange_plFound_osc'] = valuewhen(dataframe, 'plFound', 'osc', 1)
        dataframe.loc[
            (
                (dataframe['osc'] < dataframe['valuewhen_plFound_osc']) &
                (dataframe['inrange_plFound_osc'] == 1)
             )
        , 'oscLL'] = 1




        dataframe['valuewhen_plFound_low'], dataframe['inrange_plFound_low'] = valuewhen(dataframe,'plFound', 'low', 1)
        dataframe.loc[
            (dataframe['low'] > dataframe['valuewhen_plFound_low'])
            , 'priceHL'] = 1

        dataframe.loc[
            (
                (dataframe['priceHL'] == 1) &
                (dataframe['oscLL'] == 1) &
                (dataframe['plFound'] == 1)
            )
            , 'hiddenBullCond'] = 1

























        dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(dataframe, 'phFound', 'osc', 1)
        dataframe.loc[
            (
                (dataframe['osc'] < dataframe['valuewhen_phFound_osc']) &
                (dataframe['inrange_phFound_osc'] == 1)
             )
        , 'oscLH'] = 1




        dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(dataframe, 'phFound', 'high', 1)
        dataframe.loc[
            (dataframe['high'] > dataframe['valuewhen_phFound_high'])
            , 'priceHH'] = 1


        dataframe.loc[
            (
                (dataframe['priceHH'] == 1) &
                (dataframe['oscLH'] == 1) &
                (dataframe['phFound'] == 1)
            )
            , 'bearCond'] = 1

























        dataframe['valuewhen_phFound_osc'], dataframe['inrange_phFound_osc'] = valuewhen(dataframe, 'phFound', 'osc', 1)
        dataframe.loc[
            (
                (dataframe['osc'] > dataframe['valuewhen_phFound_osc']) &
                (dataframe['inrange_phFound_osc'] == 1)
             )
        , 'oscHH'] = 1




        dataframe['valuewhen_phFound_high'], dataframe['inrange_phFound_high'] = valuewhen(dataframe, 'phFound', 'high', 1)
        dataframe.loc[
            (dataframe['high'] < dataframe['valuewhen_phFound_high'])
            , 'priceLH'] = 1


        dataframe.loc[
            (
                (dataframe['priceLH'] == 1) &
                (dataframe['oscHH'] == 1) &
                (dataframe['phFound'] == 1)
            )
            , 'hiddenBearCond'] = 1























        return dataframe
    


    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
         bconditions = []

         bconditions.append(qtpylib.crossed_above(dataframe['mfi'], self.buy_mfi.value))

         if self.use_bull.value:
            bconditions.append(
                    (
                        (dataframe['bullCond'] > 0) &
                        (dataframe['EWO'] > self.ewo_high.value) &

                        (dataframe['volume'] > 0)
                    )
                )
         if self.use_hidden_bull.value:
            bconditions.append(
                (
                    (dataframe['hiddenBullCond'] > 0) &
                    (dataframe['EWO'] > self.ewo_high.value) &

                    (dataframe['volume'] > 0)
                )
            )

         bconditions.append(qtpylib.crossed_above(dataframe['wt1'], dataframe['wt2'])&
                                ((dataframe['wt2']-dataframe['wt1']) <=0)&
                                (dataframe['wt2']<= self.buy_wt_oversold.value)
             
             
             )

         if self.buy_vwap_cat.value:
             bconditions.append(dataframe["close"] <= dataframe['vwap'])

         if self.buy_arronup_cat.value == True:
            bconditions.append(qtpylib.crossed_above(dataframe['aroonup'], self.buy_aroonup.value))

         if self.buy_arrondown_cat.value == True:
            bconditions.append(qtpylib.crossed_above(dataframe['aroondown'], self.buy_aroondown.value))

         if self.buy_schaff_cat.value:
             bconditions.append(qtpylib.crossed_above(dataframe['schaff'], self.buy_schafff_val.value))

         bconditions.append(dataframe['volume'] > 0)


         if bconditions:
            dataframe.loc[
                reduce(lambda x, y: x & y, bconditions),
                'buy'] = 1
            return dataframe 
    

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

        sconditions = []

        sconditions.append(qtpylib.crossed_below(dataframe['mfi'], self.sell_mfi.value))

        if self.use_bear.value:
            sconditions.append(
                (
                    (dataframe['bearCond'] > 0) &
                    (dataframe['volume'] > 0)
                )
            )

        if self.use_hidden_bear.value:
            sconditions.append(
                (
                    (dataframe['hiddenBearCond'] > 0) &
                    (dataframe['volume'] > 0)
                )
            )

        sconditions.append(qtpylib.crossed_below(dataframe['wt1'], dataframe['wt2'])&
                                ((dataframe['wt2']-dataframe['wt1']) >=0)&
                                (dataframe['wt2']>= self.sell_wt_overbought.value)
             
             
             )
        
        if self.sell_vwap_cat.value:
             sconditions.append(dataframe["close"] >=  dataframe['vwap'])
        
        if self.sell_arrondown_cat.value == True:
            sconditions.append(qtpylib.crossed_above(dataframe['aroondown'], self.sell_aroondown.value))
        if self.sell_arronup_cat.value == True:
            sconditions.append(qtpylib.crossed_below(dataframe['aroonup'], self.sell_aroonup.value))

        if self.sell_schaff_cat.value:
            sconditions.append(qtpylib.crossed_below(dataframe['schaff'], self.sell_schafff_val.value))
        
        sconditions.append(dataframe['volume'] > 0)
        

        if sconditions:
            dataframe.loc[
                reduce(lambda x, y: x & y, sconditions),
                'sell'] = 1
            return dataframe