""" RSI Oversold Bounce Strategy Buy when RSI drops below oversold threshold (default 30) then starts rising. Sell when RSI rises above overbought threshold (default 70). Includes ADX filter to avoid flat/ranging markets with weak signals. Timeframe: 1h Pairs: BTC/USDT, ETH/USDT, SOL/USDT, BNB/USDT """ import numpy as np import pandas as pd from datetime import datetime, timedelta, timezone from pandas import DataFrame from typing import Optional, Union from freqtrade.strategy import ( IStrategy, Trade, Order, PairLocks, BooleanParameter, CategoricalParameter, DecimalParameter, IntParameter, RealParameter, ) import talib.abstract as ta from technical import qtpylib class RsiOversoldStrategy(IStrategy): """ RSI Oversold Bounce strategy. Buy: RSI crosses above oversold level (coming from below). Sell: RSI crosses above overbought level. Filter: ADX > threshold to confirm trend strength. """ INTERFACE_VERSION = 3 can_short: bool = False minimal_roi = { "0": 0.06, "60": 0.04, "120": 0.02, "240": 0.0, } stoploss = -0.08 # 8% stop loss # Trailing stop trailing_stop = True trailing_stop_positive = 0.015 trailing_stop_positive_offset = 0.035 trailing_only_offset_is_reached = True timeframe = "1h" process_only_new_candles = True use_exit_signal = True exit_profit_only = False ignore_roi_if_entry_signal = False # Hyperoptable parameters buy_rsi = IntParameter(15, 40, default=30, space="buy", optimize=True) sell_rsi = IntParameter(60, 85, default=70, space="sell", optimize=True) buy_adx = IntParameter(15, 40, default=25, space="buy", optimize=True) buy_rsi_period = IntParameter(7, 21, default=14, space="buy", optimize=True) startup_candle_count: int = 50 order_types = { "entry": "limit", "exit": "limit", "stoploss": "market", "stoploss_on_exchange": False, } order_time_in_force = {"entry": "GTC", "exit": "GTC"} plot_config = { "main_plot": {}, "subplots": { "RSI": { "rsi": {"color": "red"}, }, "ADX": { "adx": {"color": "purple"}, }, }, } def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """Calculate RSI and ADX indicators.""" # RSI with multiple periods for hyperopt for period in range(7, 22): dataframe[f"rsi_{period}"] = ta.RSI(dataframe, timeperiod=period) # ADX for trend strength filter dataframe["adx"] = ta.ADX(dataframe) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """Buy when RSI crosses above oversold threshold with ADX confirmation.""" rsi_col = f"rsi_{self.buy_rsi_period.value}" dataframe.loc[ ( (qtpylib.crossed_above(dataframe[rsi_col], self.buy_rsi.value)) & (dataframe["adx"] > self.buy_adx.value) & (dataframe["volume"] > 0) ), "enter_long", ] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """Sell when RSI crosses above overbought threshold.""" rsi_col = f"rsi_{self.buy_rsi_period.value}" dataframe.loc[ ( (qtpylib.crossed_above(dataframe[rsi_col], self.sell_rsi.value)) & (dataframe["volume"] > 0) ), "exit_long", ] = 1 return dataframe