Multi-Timeframe RSI Entry Signals Across Crypto Markets
Summary
This Freqtrade strategy example uses a five-minute trading timeframe and RSI readings from several higher timeframes and related markets. It calculates RSI for the traded pair on the base, 30-minute, and hourly periods, as well as for BTC against the stake currency and ETH against BTC. Additional BTC RSI readings use shorter lookback periods. Long entries require these readings to be low together, with the base-pair RSI below its hourly value and positive volume. Exits occur when the base RSI is above 70, exceeds its hourly counterpart, and volume is positive.
The example also sets a startup candle requirement, a fixed ROI target, and a stop-loss, while disabling trailing stops. The source explicitly labels the strategy unsuitable for live use. It contains implementation logic but no backtest results, rationale for the thresholds, or discussion of fees, slippage, pair selection, or parameter robustness. Its synchronized oversold conditions may be highly selective, but the document provides no evidence that they predict profitable reversals. Treat it as an illustrative multi-timeframe indicator setup, not a validated trading system.
Key ideas
- The strategy uses five-minute candles with RSI information from higher timeframes and related crypto pairs.
- Long entries require several RSI readings to be low simultaneously and positive traded-pair volume.
- The exit condition combines an RSI above 70 with the base RSI exceeding its hourly reading.
- The example defines ROI and stop-loss settings but disables trailing stops.
- The source warns against live use and supplies no evidence of profitability or robustness.
Tags
Full text
# multi_tf.py
```py
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
import talib.abstract as ta
from freqtrade.strategy import (IStrategy, informative)
from pandas import DataFrame, Series
import talib.abstract as ta
import math
import pandas_ta as pta
# from finta import TA as fta
import logging
from logging import FATAL
logger = logging.getLogger(__name__)
# NOT TO BE USED FOR LIVE!!!!!!
class multi_tf (IStrategy):
def version(self) -> str:
return "v1"
INTERFACE_VERSION = 3
# ROI table:
minimal_roi = {
"0": 0.2
}
# Stoploss:
stoploss = -0.1
# Trailing stop:
trailing_stop = False
trailing_stop_positive = 0.001
trailing_stop_positive_offset = 0.01
trailing_only_offset_is_reached = True
# Sell signal
use_exit_signal = True
exit_profit_only = False
exit_profit_offset = 0.01
ignore_roi_if_entry_signal = False
timeframe = '5m'
process_only_new_candles = True
startup_candle_count = 100
# This method is not required.
# def informative_pairs(self): ...
# Define informative upper timeframe for each pair. Decorators can be stacked on same
# method. Available in populate_indicators as 'rsi_30m' and 'rsi_1h'.
@informative('30m')
@informative('1h')
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/STAKE informative pair. Available in populate_indicators and other methods as
# 'btc_rsi_1h'. Current stake currency should be specified as {stake} format variable
# instead of hard-coding actual stake currency. Available in populate_indicators and other
# methods as 'btc_usdt_rsi_1h' (when stake currency is USDT).
@informative('1h', 'BTC/{stake}')
def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/ETH informative pair. You must specify quote currency if it is different from
# stake currency. Available in populate_indicators and other methods as 'eth_btc_rsi_1h'.
@informative('1h', 'ETH/BTC')
def populate_indicators_eth_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/STAKE informative pair. A custom formatter may be specified for formatting
# column names. A callable `fmt(**kwargs) -> str` may be specified, to implement custom
# formatting. Available in populate_indicators and other methods as 'rsi_fast_upper'.
# Resulting column names: `BTC_rsi_fast_upper_1h`, `BTC_close_1h` ...
@informative('1h', 'BTC/{stake}', 'BTC_{column}_{timeframe}')
def populate_indicators_btc_1h_2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi_fast_upper'] = ta.RSI(dataframe, timeperiod=4)
return dataframe
# Define BTC/STAKE informative pair. A custom formatter may be specified for formatting
# column names. A callable `fmt(**kwargs) -> str` may be specified, to implement custom
# formatting. Available in populate_indicators and other methods as 'btc_rsi_super_fast_1h'.
@informative('1h', 'BTC/{stake}', '{base}_{column}_{timeframe}')
def populate_indicators_btc_1h_3(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi_super_fast'] = ta.RSI(dataframe, timeperiod=2)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Strategy timeframe indicators for current pair.
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# Informative pairs are available in this method.
dataframe['rsi_less'] = dataframe['rsi'] < dataframe['rsi_1h']
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
stake = self.config['stake_currency'].lower()
dataframe.loc[
(
(dataframe[f'btc_{stake}_rsi_1h'] < 35)
&
(dataframe['eth_btc_rsi_1h'] < 50)
&
(dataframe['BTC_rsi_fast_upper_1h'] < 40)
&
(dataframe['btc_rsi_super_fast_1h'] < 30)
&
(dataframe['rsi_30m'] < 40)
&
(dataframe['rsi_1h'] < 40)
&
(dataframe['rsi'] < 30)
&
(dataframe['rsi_less'] == True)
&
(dataframe['volume'] > 0)
),
['enter_long', 'enter_tag']] = (1, 'buy_signal_rsi')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] > 70)
&
(dataframe['rsi_less'] == False)
&
(dataframe['volume'] > 0)
),
['exit_long', 'exit_tag']] = (1, 'exit_signal_rsi')
return dataframe
```Shown in full with attribution under the source's licence. Licence: GPL-3.0
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.