# source: https://raw.githubusercontent.com/DerSalvador/freqtrade-helm-chart/f80d4d8b77c53435e9c0a9045636f1bfb2b8c539/chart/deployed_strategies/binance-michael-k8s-namespace/ObeliskRSI_v6_1.py
# --- Do not remove these libs ---
from freqtrade.strategy.interface import IStrategy
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
# --------------------------------
import pandas as pd  # noqa
pd.options.mode.chained_assignment = None  # default='warn'
from technical.util import resample_to_interval, resampled_merge
from functools import reduce
from datetime import datetime, timedelta
# ObeliskRSI v6.1 - 2021-03-06
#
# by Obelisk 
# https://twitter.com/brookmiles
#
# Run at your own risk.
# I don't know what I'm doing.
# Backtests quite a bit better than it actually works.
# Let me know if you manage to improve it!
#
# Buys when RSI crosses the low threshold
# Doesn't wait for reversal, trying to anticipate the "bottom" of the dip.
#
# Sells on ROI (often), Stoploss (sometimes), or RSI high (rarely)
#
# Custom Stoploss starts wide and then narrows over time
# Combined with ROI, every trade will be forced to close in custom_stop_ramp_minutes, win or lose
#
# Bull/Bear trends
#
# Uses two different sets of entry/exit thresholds, which are used depending on the longer RSI trend
# Enter earlier and leave later when bullish; enter later and leave earlier when bearish
#
# Strengths
#
# Choppy markets - requires strong enough dips to trigger a entry, then we want a bounce back up
#
# Weaknesses
#
# Steady bull runs - no dips to entry, missed opportunity
# Sudden ongoing bear runs - if the market keeps dipping and dropping repeatedly that's bad,
# so use protections, eg.
#
# "protections": [
#     {
#         "method": "StoplossGuard",
#         "lookback_period": 720,
#         "trade_limit": 2,
#         "stop_duration": 720,
#         "only_per_pair": true
#     },
# ],  
# 
# Works best on high volume pairs with decent volatility eg.
#
# "SXP/USD",
# "MATIC/USD",
# "SUSHI/USD",
# "CHZ/USD",
#
# and not ETH/USD or BTC/USD

def easeInCubic(t):
    return t * t * t

def clamp(num, min_value, max_value):
    return max(min(num, max_value), min_value)

def clamp01(num):
    return clamp(num, 0, 1)

class Github_DerSalvador_freqtrade_helm_chart__ObeliskRSI_v6_1__20260416_224245(IStrategy):
    INTERFACE_VERSION = 3
    # Optimal timeframe for the strategy
    timeframe = '5m'
    startup_candle_count = 240
    process_only_new_candles = True
    # ROI table:
    minimal_roi = {'0': 0.15, '35': 0.04, '65': 0.01, '115': 0}
    # Buy hyperspace params:
    entry_params = {'bear-entry-rsi-value': 21, 'bull-entry-rsi-value': 35}
    # Sell hyperspace params:
    exit_params = {'bear-exit-rsi-value': 55, 'bull-exit-rsi-value': 69}
    # Stoploss:
    stoploss = -0.3
    use_custom_stoploss = True
    custom_stop_ramp_minutes = 110

    def get_ticker_indicator(self):
        return int(self.timeframe[:-1])

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        # longer RSI used for determining trend
        resample_rsi_indicator = self.get_ticker_indicator() * 12
        resample_rsi_key = 'resample_{}_rsi'.format(resample_rsi_indicator)
        dataframe_long = resample_to_interval(dataframe, resample_rsi_indicator)
        dataframe_long['rsi'] = ta.RSI(dataframe_long, timeperiod=14)
        dataframe = resampled_merge(dataframe, dataframe_long)
        dataframe[resample_rsi_key].fillna(method='ffill', inplace=True)
        # bull used to select between two different sets of entry/exit threshold values
        # based on long RSI
        dataframe['bull'] = dataframe[resample_rsi_key].gt(60).astype('int')
        # normal rsi acts mainly as the entry trigger
        # used for exit as well, but more likely to ROI or stop out
        dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
        return dataframe
    # entry low

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        params = self.entry_params
        conditions = []
        conditions.append(dataframe['volume'] > 0)
        conditions.append((dataframe['bull'] > 0) & qtpylib.crossed_below(dataframe['rsi'], params['bull-entry-rsi-value']) | ~(dataframe['bull'] > 0) & qtpylib.crossed_below(dataframe['rsi'], params['bear-entry-rsi-value']))
        dataframe.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1
        return dataframe
    # exit high

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        params = self.exit_params
        conditions = []
        conditions.append(dataframe['volume'] > 0)
        conditions.append((dataframe['bull'] > 0) & (dataframe['rsi'] > params['bull-exit-rsi-value']) | ~(dataframe['bull'] > 0) & (dataframe['rsi'] > params['bear-exit-rsi-value']))
        dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
        return dataframe
    # Custom stoploss starts at the basic stoploss, and ramps towards zero in a curve, 
    # narrowing the trailing stoploss until forcing the trade to stop out after custom_stop_ramp_minutes

    def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float:
        since_open = current_time - trade.open_date
        sl_pct = 1 - easeInCubic(clamp01(since_open / timedelta(minutes=self.custom_stop_ramp_minutes)))
        sl_ramp = abs(self.stoploss) * sl_pct
        return sl_ramp + 0.001  # we can't go all the way to zero