import freqtrade.vendor.qtpylib.indicators as qtpylib import numpy as np import talib.abstract as ta import logging from pandas import DataFrame, DatetimeIndex, merge from freqtrade.strategy import IStrategy from typing import Dict, List from skopt.space import Dimension, Real logger = logging.getLogger(__name__) class ReinforcedQuickieHyperStrategy(IStrategy): """ enhanced auto hyperoptable version based on https://github.com/back8/github_freqtrade_freqtrade-strategies/blob/master/user_data/strategies/berlinguyinca/ReinforcedQuickie.py !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! as of today (14.04.2021) you need the freqtrade/develop version to be able !!! !!! to run hyperopt/backtest with this new strategy format !!! !!! !!! !!! please check https://github.com/freqtrade/freqtrade/pull/4596 for further !!! !!! information about the new auto-hyperoptable strategies! !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! original author@: Gert Wohlgemuth works on new objectify branch! idea: only buy on an upward tending market """ minimal_roi = { "0": 0.01 } stoploss = -0.05 timeframe = '5m' resample_factor = 12 buy_params = { } sell_params = { } EMA_SHORT_TERM = 5 EMA_MEDIUM_TERM = 12 EMA_LONG_TERM = 21 def __init__(self, config: dict) -> None: super().__init__(config) try: from mergedeep import merge except ImportError as error: logger.info("could not import mergedeep, please check if pip is installed: %s", error) logger.info("therefor we are not able to merge parameters from config") else: logger.info('mergedeep found, so attempting to find strategy parameters in config file') if self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False): cfg_strategy_parameters = self.config.get('strategy_parameters', {}).get(self.__class__.__name__, False) logger.info('strategy_parameters from config: %s', repr(cfg_strategy_parameters)) if cfg_strategy_parameters.get('buy_params', {}): logger.info('merging buy_params from config: %s', cfg_strategy_parameters.get('buy_params')) merge(self.buy_params, cfg_strategy_parameters.get('buy_params')) if cfg_strategy_parameters.get('sell_params', {}): logger.info('merging sell_params from config: %s', cfg_strategy_parameters.get('sell_params')) merge(self.sell_params, cfg_strategy_parameters.get('sell_params')) else: logger.info('no strategy_parameters found in config') logger.info('final buy_params: %s', repr(self.buy_params)) logger.info('final sell_params: %s', repr(self.sell_params)) def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = self.resample(dataframe, self.timeframe, self.resample_factor) dataframe['ema_{}'.format(self.EMA_SHORT_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_SHORT_TERM ) dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_MEDIUM_TERM ) dataframe['ema_{}'.format(self.EMA_LONG_TERM)] = ta.EMA( dataframe, timeperiod=self.EMA_LONG_TERM ) bollinger = qtpylib.bollinger_bands( qtpylib.typical_price(dataframe), window=20, stds=2 ) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['min'] = ta.MIN(dataframe, timeperiod=self.EMA_MEDIUM_TERM) dataframe['max'] = ta.MAX(dataframe, timeperiod=self.EMA_MEDIUM_TERM) dataframe['cci'] = ta.CCI(dataframe) dataframe['mfi'] = ta.MFI(dataframe) dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7) dataframe['average'] = (dataframe['close'] + dataframe['open'] + dataframe['high'] + dataframe['low']) / 4 bollinger = qtpylib.bollinger_bands(dataframe['close'], window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['bb_middleband'] = bollinger['mid'] macd = ta.MACD(dataframe) dataframe['macd'] = macd['macd'] dataframe['macdsignal'] = macd['macdsignal'] dataframe['macdhist'] = macd['macdhist'] return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the buy signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ dataframe.loc[ ( ( ( (dataframe['close'] < dataframe['ema_{}'.format(self.EMA_SHORT_TERM)]) & (dataframe['close'] < dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)]) & (dataframe['close'] == dataframe['min']) & (dataframe['close'] <= dataframe['bb_lowerband']) ) | ( (dataframe['average'].shift(5) > dataframe['average'].shift(4)) & (dataframe['average'].shift(4) > dataframe['average'].shift(3)) & (dataframe['average'].shift(3) > dataframe['average'].shift(2)) & (dataframe['average'].shift(2) > dataframe['average'].shift(1)) & (dataframe['average'].shift(1) < dataframe['average'].shift(0)) & (dataframe['low'].shift(1) < dataframe['bb_middleband']) & (dataframe['cci'].shift(1) < -100) & (dataframe['rsi'].shift(1) < 30) & (dataframe['mfi'].shift(1) < 30) ) ) & ( (dataframe['volume'] < (dataframe['volume'].rolling(window=30).mean().shift(1) * 20)) & (dataframe['resample_sma'] < dataframe['close']) & (dataframe['resample_sma'].shift(1) < dataframe['resample_sma']) ) ) , 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Based on TA indicators, populates the sell signal for the given dataframe :param dataframe: DataFrame :return: DataFrame with buy column """ dataframe.loc[ ( (dataframe['close'] > dataframe['ema_{}'.format(self.EMA_SHORT_TERM)]) & (dataframe['close'] > dataframe['ema_{}'.format(self.EMA_MEDIUM_TERM)]) & (dataframe['close'] >= dataframe['max']) & (dataframe['close'] >= dataframe['bb_upperband']) & (dataframe['mfi'] > 80) ) | ( (dataframe['open'] < dataframe['close']) & (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & (dataframe['open'].shift(2) < dataframe['close'].shift(2)) & (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & (dataframe['open'].shift(4) < dataframe['close'].shift(4)) & (dataframe['open'].shift(5) < dataframe['close'].shift(5)) & (dataframe['open'].shift(6) < dataframe['close'].shift(6)) & (dataframe['open'].shift(7) < dataframe['close'].shift(7)) & (dataframe['rsi'] > 70) ) , 'sell' ] = 1 return dataframe def resample(self, dataframe, interval, factor): df = dataframe.copy() df = df.set_index(DatetimeIndex(df['date'])) ohlc_dict = { 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last' } df = df.resample(str(int(interval[:-1]) * factor) + 'min', label="right").agg(ohlc_dict).dropna(how='any') df['resample_sma'] = ta.SMA(df, timeperiod=25, price='close') df = df.drop(columns=['open', 'high', 'low', 'close']) df = df.resample(interval[:-1] + 'min') df = df.interpolate(method='time') df['date'] = df.index df.index = range(len(df)) dataframe = merge(dataframe, df, on='date', how='left') return dataframe class HyperOpt: @staticmethod def indicator_space() -> List[Dimension]: return [] @staticmethod def sell_indicator_space() -> List[Dimension]: return [] @staticmethod def stoploss_space() -> List[Dimension]: return [ Real(-0.05, -0.02, name='stoploss'), ]