# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
from functools import reduce
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Dict, Optional, Union, Tuple
from freqtrade.strategy import (
IStrategy,
Trade,
Order,
PairLocks,
informative,
BooleanParameter,
CategoricalParameter,
DecimalParameter,
IntParameter,
RealParameter,
timeframe_to_minutes,
timeframe_to_next_date,
timeframe_to_prev_date,
merge_informative_pair,
stoploss_from_absolute,
stoploss_from_open,
AnnotationType,
)
import talib.abstract as ta
from technical import qtpylib
class OptimizedStrategy(IStrategy):
"""
RSI Mean Reversion — No Trailing Stop.
In a strong uptrend, trailing stops are your enemy.
Stay in on RSI oversold, exit on RSI overbought.
"""
INTERFACE_VERSION = 3
timeframe = "5m"
can_short: bool = False
minimal_roi = {} # No ROI — RSI exits only
stoploss = -0.03
trailing_stop = False # DISABLED — let RSI handle exits
process_only_new_candles = True
use_exit_signal = True
exit_profit_only = False
ignore_roi_if_entry_signal = False
startup_candle_count: int = 300
# ===================== HYPEROPT PARAMETERS =====================
buy_rsi = IntParameter(10, 40, default=25, space="buy", optimize=True)
buy_adx = IntParameter(5, 25, default=10, space="buy", optimize=True)
sell_rsi = IntParameter(60, 85, default=75, space="sell", optimize=True)
# ===================== INDICATORS =====================
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['ema200'] = ta.EMA(dataframe, timeperiod=200)
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
dataframe['adx'] = ta.ADX(dataframe, timeperiod=14)
return dataframe
# ===================== ENTRY SIGNALS =====================
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value)) &
(dataframe['close'] > dataframe['ema200']) &
(dataframe['adx'] > self.buy_adx.value) &
(dataframe['volume'] > 0)
),
'enter_long'
] = 1
return dataframe
# ===================== EXIT SIGNALS =====================
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) &
(dataframe['volume'] > 0)
),
'exit_long'
] = 1
return dataframe