The easiest way to define informative timeframe(s) is by using the decorator, as shown in the example below
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 from typing import Dict, List, Optional, Tuple from freqtrade.persistence import Trade import talib.abstract as ta import time # 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'. @informative('1h', 'BTC/{stake}', '{column}') 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'] dataframe.loc[ ( (dataframe[f'btc_{stake}_rsi_1h'] < 35) & (dataframe['eth_btc_rsi_1h'] < 50) & (dataframe['rsi_fast_upper'] < 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
If you need to use data from one informative timeframe on another informative timeframe, the decorator won’t work for you in that case. In this situation, you would need to employ the more extensive method, for instance
def info_tf_btc_indicators(self, dataframe, metadata): # Indicators # ----------------------------------------------------------------------------------------- dataframe['rsi_14'] = ta.RSI(dataframe, timeperiod=14) dataframe['not_downtrend'] = ((dataframe['close'] > dataframe['close'].shift(2)) | (dataframe['rsi_14'] > 50)) # Add prefix # ----------------------------------------------------------------------------------------- ignore_columns = ['date', 'open', 'high', 'low', 'close', 'volume'] dataframe.rename(columns=lambda s: f"btc_{s}" if s not in ignore_columns else s, inplace=True) return dataframe def indicators_15m(self, informative_15m, metadata): informative_15m['rsi'] = ta.RSI(informative_15m, timeperiod=14) informative_15m['cmf'] = chaikin_money_flow(informative_15m, 20) informative_15m['cti'] = pta.cti(informative_15m["close"], length=20) return informative_15m def informative_pairs(self): pairs = self.dp.current_whitelist() informative_pairs = [(pair, '15m') for pair in pairs] informative_pairs.extend([(pair, '30m') for pair in pairs]) btc_info_pair = f"BTC/{self.config['stake_currency']}" informative_pairs.append((btc_info_pair, '5m')) informative_pairs.append((btc_info_pair, '15m')) return informative_pairs def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: btc_info_pair = f"BTC/{self.config['stake_currency']}" btc_info_tf = self.dp.get_pair_dataframe(btc_info_pair, '15m') btc_info_tf = self.info_tf_btc_indicators(btc_info_tf, metadata) dataframe = merge_informative_pair(dataframe, btc_info_tf, '5m', '15m', ffill=True) drop_columns = [f"{s}_15m" for s in ['date', 'open', 'high', 'low', 'close', 'volume']] dataframe.drop(columns=dataframe.columns.intersection(drop_columns), inplace=True) informative_15m = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='15m') informative_15m = self.indicators_15m(informative_15m, metadata) dataframe = merge_informative_pair(dataframe, informative_15m, '5m', '15m', ffill=True) return dataframe
[…] Define informative timeframe(s) […]
wow! wanted to thank you.
I found “Bot Academy” one of the most valuable websites ever have seen.
The information you provided is really valuable 🙂
[…] timeframes, the base timeframe must be the 15m. 30m and 1h is our informative timeframes. There are 2 ways to define informative. I will use the easiest way, which is using informative decorator. Since I will calculate same […]