def test_auto_hyperopt_interface(default_conf): default_conf.update({'strategy': 'HyperoptableStrategy'}) PairLocks.timeframe = default_conf['timeframe'] strategy = StrategyResolver.load_strategy(default_conf) with pytest.raises(OperationalException): next(strategy.enumerate_parameters('deadBeef')) assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi'] # PlusDI is NOT in the buy-params, so default should be used assert strategy.buy_plusdi.value == 0.5 assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi'] assert repr(strategy.sell_rsi) == 'IntParameter(74)' # Parameter is disabled - so value from sell_param dict will NOT be used. assert strategy.sell_minusdi.value == 0.5 all_params = strategy.detect_all_parameters() assert isinstance(all_params, dict) assert len(all_params['buy']) == 2 assert len(all_params['sell']) == 2 # Number of Hyperoptable parameters assert all_params['count'] == 6 strategy.__class__.sell_rsi = IntParameter([0, 10], default=5, space='buy') with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"): [x for x in strategy.detect_parameters('sell')]
def test_hyperopt_parameters(): from skopt.space import Categorical, Integer, Real with pytest.raises(OperationalException, match=r"Name is determined.*"): IntParameter(low=0, high=5, default=1, name='hello') with pytest.raises(OperationalException, match=r"IntParameter space must be.*"): IntParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"RealParameter space must be.*"): RealParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"DecimalParameter space must be.*"): DecimalParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"IntParameter space invalid\."): IntParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"RealParameter space invalid\."): RealParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"DecimalParameter space invalid\."): DecimalParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"CategoricalParameter space must.*"): CategoricalParameter(['aa'], default='aa', space='buy') with pytest.raises(TypeError): BaseParameter(opt_range=[0, 1], default=1, space='buy') intpar = IntParameter(low=0, high=5, default=1, space='buy') assert intpar.value == 1 assert isinstance(intpar.get_space(''), Integer) fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy') assert isinstance(fltpar.get_space(''), Real) assert fltpar.value == 1 fltpar = DecimalParameter(low=0.0, high=5.5, default=1.0004, decimals=3, space='buy') assert isinstance(fltpar.get_space(''), Integer) assert fltpar.value == 1 fltpar._set_value(2222) assert fltpar.value == 2.222 catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'], default='buy_macd', space='buy') assert isinstance(catpar.get_space(''), Categorical) assert catpar.value == 'buy_macd'
def test_auto_hyperopt_interface(default_conf): default_conf.update({'strategy': 'HyperoptableStrategy'}) PairLocks.timeframe = default_conf['timeframe'] strategy = StrategyResolver.load_strategy(default_conf) assert strategy.buy_rsi.value == strategy.buy_params['buy_rsi'] # PlusDI is NOT in the buy-params, so default should be used assert strategy.buy_plusdi.value == 0.5 assert strategy.sell_rsi.value == strategy.sell_params['sell_rsi'] # Parameter is disabled - so value from sell_param dict will NOT be used. assert strategy.sell_minusdi.value == 0.5 strategy.sell_rsi = IntParameter([0, 10], default=5, space='buy') with pytest.raises(OperationalException, match=r"Inconclusive parameter.*"): [x for x in strategy.enumerate_parameters('sell')]
class MarketChyperHyperTestStrategy(IStrategy): # If enabled all Weighted Signal results will be added to the dataframe for easy debugging with BreakPoints # Warning: Disable this for anything else then debugging in an IDE! (Integrated Development Environment) debuggable_weighted_signal_dataframe = False # Ps: Documentation has been moved to the Buy/Sell HyperOpt Space Parameters sections below this copy-paste section #################################################################################################################### # START OF HYPEROPT RESULTS COPY-PASTE SECTION # #################################################################################################################### # Buy hyperspace params: buy_params = { 'buy_downtrend_oslevel': -37, 'buy_downtrend_rsi_div_value': 79, 'buy_downtrend_rsi_divergence_weight': 50, 'buy_downtrend_total_signal_needed': 70, 'buy_downtrend_wavetrend_weight': 96, 'buy_sideways_oslevel': -28, 'buy_sideways_rsi_div_value': 45, 'buy_sideways_rsi_divergence_weight': 35, 'buy_sideways_total_signal_needed': 80, 'buy_sideways_wavetrend_weight': 5, 'buy_uptrend_oslevel': -43, 'buy_uptrend_rsi_div_value': 93, 'buy_uptrend_rsi_divergence_weight': 84, 'buy_uptrend_total_signal_needed': 25, 'buy_uptrend_wavetrend_weight': 91 } # Sell hyperspace params: sell_params = { 'sell_downtrend_oblevel': 75.67481, 'sell_downtrend_rsi_divergence_weight': 90, 'sell_downtrend_total_signal_needed': 51, 'sell_downtrend_wavetrend_weight': 30, 'sell_sideways_oblevel': 1.93351, 'sell_sideways_rsi_divergence_weight': 59, 'sell_sideways_total_signal_needed': 36, 'sell_sideways_wavetrend_weight': 83, 'sell_uptrend_oblevel': 37.98512, 'sell_uptrend_rsi_divergence_weight': 99, 'sell_uptrend_total_signal_needed': 93, 'sell_uptrend_wavetrend_weight': 43 } # ROI table: minimal_roi = {"0": 0.23733, "238": 0.20624, "846": 0.08939, "1834": 0} # Stoploss: stoploss = -0.12447 # Trailing stop: trailing_stop = True trailing_stop_positive = 0.01658 trailing_stop_positive_offset = 0.10224 trailing_only_offset_is_reached = True #################################################################################################################### # END OF HYPEROPT RESULTS COPY-PASTE SECTION # #################################################################################################################### # Optimal timeframe for the strategy. timeframe = '30m' # Run "populate_indicators()" only for new candle. process_only_new_candles = False # These values can be overridden in the "ask_strategy" section in the config. use_sell_signal = True sell_profit_only = False ignore_roi_if_buy_signal = False # Number of candles the strategy requires before producing valid signals startup_candle_count: int = 400 # SMA200 needs 200 candles before producing valid signals # EMA200 needs an extra 200 candles of SMA200 before producing valid signals # Optional order type mapping. order_types = { 'buy': 'limit', 'sell': 'limit', 'stoploss': 'market', 'stoploss_on_exchange': False } # Optional order time in force. order_time_in_force = {'buy': 'gtc', 'sell': 'gtc'} # Uptrend Trend Buy # ------------------- # Total Buy Signal Percentage needed for a signal to be positive # im testing number of signals * 50 / 2 buy___trades_when_downwards = \ CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True) buy___trades_when_sideways = \ CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True) buy___trades_when_upwards = \ CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True) buy_uptrend_total_signal_needed = IntParameter(0, 100, default=65, space='buy', optimize=True, load=True) #wave trend buy_uptrend_wavetrend_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) #rsi divs buy_uptrend_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) # buy_rsi_div_value (rsi used in condition of bullish div) buy_uptrend_rsi_div_value = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) buy_uptrend_oslevel = \ IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True) # Sideways Trend Buy # ------------------- buy_sideways_total_signal_needed = IntParameter(0, 100, default=65, space='buy', optimize=True, load=True) #wave trend buy_sideways_wavetrend_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) #rsi divs buy_sideways_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) # buy_rsi_div_value (rsi used in condition of bullish div) buy_sideways_rsi_div_value = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) buy_sideways_oslevel = \ IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True) # Downtrend Trend Buy # ------------------- buy_downtrend_total_signal_needed = IntParameter(0, 100, default=65, space='buy', optimize=True, load=True) #wave trend buy_downtrend_wavetrend_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) #rsi divs buy_downtrend_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) # buy_rsi_div_value (rsi used in condition of bullish div) buy_downtrend_rsi_div_value = \ IntParameter(0, 100, default=0, space='buy', optimize=True, load=True) buy_downtrend_oslevel = \ IntParameter(-100, 0, default=0, space='buy', optimize=True, load=True) #sell?? sell___trades_when_downwards = \ CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True) sell___trades_when_sideways = \ CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True) sell___trades_when_upwards = \ CategoricalParameter([True, False], default=True, space='sell', optimize=True, load=True) # Uptrend Trend Sell # -------------------- # Total Sell Signal Percentage needed for a signal to be positive sell_uptrend_total_signal_needed = IntParameter(0, 100, default=65, space='sell', optimize=True, load=True) #wave trend sell_uptrend_wavetrend_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) #rsi divs sell_uptrend_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) sell_uptrend_oblevel = \ RealParameter(0, 100, default=0, space='sell', optimize=True, load=True) # Sidewyas Trend Sell # -------------------- # Total Sell Signal Percentage needed for a signal to be positive sell_sideways_total_signal_needed = IntParameter(0, 100, default=65, space='sell', optimize=True, load=True) #wave trend sell_sideways_wavetrend_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) #rsi divs sell_sideways_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) sell_sideways_oblevel = \ RealParameter(0, 100, default=0, space='sell', optimize=True, load=True) # Downtrend Trend Sell # -------------------- sell_downtrend_total_signal_needed = IntParameter(0, 100, default=65, space='sell', optimize=True, load=True) #wave trend sell_downtrend_wavetrend_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) #rsi divs sell_downtrend_rsi_divergence_weight = \ IntParameter(0, 100, default=0, space='sell', optimize=True, load=True) sell_downtrend_oblevel = \ RealParameter(0, 100, default=0, space='sell', optimize=True, load=True) # ---------------------------------------------------------------- # # Custom HyperOpt Space Parameters # # ---------------------------------------------------------------- # # class HyperOpt: # # Define a custom stoploss space. # @staticmethod # def stoploss_space(): # return [Real(-0.01, -0.35, name='stoploss')] def informative_pairs(self): """ Define additional, informative pair/interval combinations to be cached from the exchange. These pair/interval combinations are non-tradeable, unless they are part of the whitelist as well. For more information, please consult the documentation :return: List of tuples in the format (pair, interval) Sample: return [("ETH/USDT", "5m"), ("BTC/USDT", "15m"), ] """ return [] def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame Performance Note: For the best performance be frugal on the number of indicators you are using. Let uncomment only the indicator you are using in your strategies or your hyperopt configuration, otherwise you will waste your memory and CPU usage. :param dataframe: Dataframe with data from the exchange :param metadata: Additional information, like the currently traded pair :return: a Dataframe with all mandatory indicators for the strategies """ # Momentum Indicators (timeperiod is expressed in candles) # ------------------- # ADX - Average Directional Index (The Trend Strength Indicator) dataframe['adx'] = ta.ADX( dataframe, timeperiod=14) # 14 timeperiods is usually used for ADX # +DM (Positive Directional Indicator) = current high - previous high dataframe['plus_di'] = ta.PLUS_DI(dataframe, timeperiod=25) # -DM (Negative Directional Indicator) = previous low - current low dataframe['minus_di'] = ta.MINUS_DI(dataframe, timeperiod=25) # RSI - Relative Strength Index (Under bought / Over sold & Over bought / Under sold indicator Indicator) dataframe['rsi'] = ta.RSI(dataframe) # MACD - Moving Average Convergence Divergence macd = ta.MACD(dataframe) dataframe['macd'] = macd[ 'macd'] # MACD - Blue TradingView Line (Bullish if on top) dataframe['macdsignal'] = macd[ 'macdsignal'] # Signal - Orange TradingView Line (Bearish if on top) # Initialize total signal variables (should be 0 = false by default) dataframe['total_buy_signal_strength'] = dataframe[ 'total_sell_signal_strength'] = 0 #divergences dataframe = self.divergences(dataframe) #get trend dataframe.loc[(dataframe['adx'] > 20) & (dataframe['plus_di'] < dataframe['minus_di']), 'trend'] = 'downwards' dataframe.loc[dataframe['adx'] < 20, 'trend'] = 'sideways' dataframe.loc[(dataframe['adx'] > 20) & (dataframe['plus_di'] > dataframe['minus_di']), 'trend'] = 'upwards' 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 populated with indicators :param metadata: Additional information, like the currently traded pair :return: DataFrame with buy column """ dataframe = self.market_cipher(dataframe) #CALCULATE WT OVERSOLD dataframe.loc[(dataframe['trend'] == 'downwards'), 'wtOversold'] = (dataframe['wt2'] <= self.buy_downtrend_oslevel.value) dataframe.loc[(dataframe['trend'] == 'sideways'), 'wtOversold'] = (dataframe['wt2'] <= self.buy_sideways_oslevel.value) dataframe.loc[(dataframe['trend'] == 'upwards'), 'wtOversold'] = (dataframe['wt2'] <= self.buy_uptrend_oslevel.value) #SUM dataframe.loc[ (dataframe['trend'] == 'downwards') & (dataframe['wtCrossUp'] & dataframe['wtOversold']), 'buy_wavetrend_weight'] = self.buy_downtrend_wavetrend_weight.value dataframe.loc[ (dataframe['trend'] == 'sideways') & (dataframe['wtCrossUp'] & dataframe['wtOversold']), 'buy_wavetrend_weight'] = self.buy_sideways_wavetrend_weight.value dataframe.loc[ (dataframe['trend'] == 'upwards') & (dataframe['wtCrossUp'] & dataframe['wtOversold']), 'buy_wavetrend_weight'] = self.buy_uptrend_wavetrend_weight.value dataframe['total_buy_signal_strength'] += dataframe[ 'buy_wavetrend_weight'] #rsi div and rsi vañur buy_rsi_div buy_rsi_div_weight dataframe.loc[(dataframe['trend'] == 'downwards') & ( dataframe['bullish_div'] & (dataframe['rsi'] <= self.buy_downtrend_rsi_div_value.value) ), 'buy_rsi_divergence_weight'] = self.buy_downtrend_rsi_divergence_weight.value dataframe.loc[(dataframe['trend'] == 'sideways') & ( dataframe['bullish_div'] & (dataframe['rsi'] <= self.buy_sideways_rsi_div_value.value) ), 'buy_rsi_divergence_weight'] = self.buy_sideways_rsi_divergence_weight.value dataframe.loc[(dataframe['trend'] == 'upwards') & ( dataframe['bullish_div'] & (dataframe['rsi'] <= self.buy_uptrend_rsi_div_value.value) ), 'buy_rsi_divergence_weight'] = self.buy_uptrend_rsi_divergence_weight.value dataframe['total_buy_signal_strength'] += dataframe[ 'buy_rsi_divergence_weight'] # Check if buy signal should be sent depending on the current trend # Check if buy signal should be sent depending on the current trend dataframe.loc[((dataframe['trend'] == 'downwards') & (dataframe['total_buy_signal_strength'] >= self. buy_downtrend_total_signal_needed.value)) | ((dataframe['trend'] == 'sideways') & (dataframe['total_buy_signal_strength'] >= self. buy_sideways_total_signal_needed.value)) | ((dataframe['trend'] == 'upwards') & (dataframe['total_buy_signal_strength'] >= self. buy_uptrend_total_signal_needed.value)), 'buy'] = 1 # Override Buy Signal: When configured buy signals can be completely turned off for each kind of trend if not self.buy___trades_when_downwards.value: dataframe.loc[dataframe['trend'] == 'downwards', 'buy'] = 0 if not self.buy___trades_when_sideways.value: dataframe.loc[dataframe['trend'] == 'sideways', 'buy'] = 0 if not self.buy___trades_when_upwards.value: dataframe.loc[dataframe['trend'] == 'upwards', 'buy'] = 0 return dataframe return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = self.market_cipher(dataframe) #CALCULATE WT OVERSOLD dataframe.loc[(dataframe['trend'] == 'downwards'), 'wtOverbought'] = (dataframe['wt2'] >= self.sell_downtrend_oblevel.value) dataframe.loc[(dataframe['trend'] == 'sideways'), 'wtOverbought'] = (dataframe['wt2'] >= self.sell_sideways_oblevel.value) dataframe.loc[(dataframe['trend'] == 'upwards'), 'wtOverbought'] = (dataframe['wt2'] >= self.sell_uptrend_oblevel.value) #SUM dataframe.loc[(dataframe['trend'] == 'downwards') & ( dataframe['wtCrossDown'] & dataframe['wtOverbought'] ), 'sell_wavetrend_weight'] = self.sell_downtrend_wavetrend_weight.value dataframe.loc[(dataframe['trend'] == 'sideways') & ( dataframe['wtCrossDown'] & dataframe['wtOverbought'] ), 'sell_wavetrend_weight'] = self.sell_sideways_wavetrend_weight.value dataframe.loc[ (dataframe['trend'] == 'upwards') & (dataframe['wtCrossDown'] & dataframe['wtOverbought']), 'sell_wavetrend_weight'] = self.sell_uptrend_wavetrend_weight.value dataframe['total_sell_signal_strength'] += dataframe[ 'sell_wavetrend_weight'] #rsi div and rsi vañur buy_rsi_div buy_rsi_div_weight dataframe.loc[(dataframe['trend'] == 'downwards') & ( dataframe['bearish_div'] ), 'sell_rsi_divergence_weight'] = self.sell_downtrend_rsi_divergence_weight.value dataframe.loc[(dataframe['trend'] == 'sideways') & ( dataframe['bearish_div'] ), 'sell_rsi_divergence_weight'] = self.sell_sideways_rsi_divergence_weight.value dataframe.loc[(dataframe['trend'] == 'upwards') & ( dataframe['bearish_div'] ), 'sell_rsi_divergence_weight'] = self.sell_uptrend_rsi_divergence_weight.value dataframe['total_sell_signal_strength'] += dataframe[ 'sell_rsi_divergence_weight'] # Check if buy signal should be sent depending on the current trend # Check if buy signal should be sent depending on the current trend dataframe.loc[((dataframe['trend'] == 'downwards') & (dataframe['total_sell_signal_strength'] >= self. sell_downtrend_total_signal_needed.value)) | ((dataframe['trend'] == 'sideways') & (dataframe['total_sell_signal_strength'] >= self. sell_sideways_total_signal_needed.value)) | ((dataframe['trend'] == 'upwards') & (dataframe['total_sell_signal_strength'] >= self. sell_uptrend_total_signal_needed.value)), 'sell'] = 1 return dataframe #wavetrend, market cypher def market_cipher(self, dataframe) -> DataFrame: self.n1 = 10 #WT Channel Length self.n2 = 21 #WT Average Length dataframe['ap'] = (dataframe['high'] + dataframe['low'] + dataframe['close']) / 3 dataframe['esa'] = ta.EMA(dataframe['ap'], self.n1) dataframe['d'] = ta.EMA((dataframe['ap'] - dataframe['esa']).abs(), self.n1) dataframe['ci'] = (dataframe['ap'] - dataframe['esa']) / (0.015 * dataframe['d']) dataframe['tci'] = ta.EMA(dataframe['ci'], self.n2) dataframe['wt1'] = dataframe['tci'] dataframe['wt2'] = ta.SMA(dataframe['wt1'], 4) dataframe['wtVwap'] = dataframe['wt1'] - dataframe['wt2'] dataframe['wtCrossUp'] = dataframe['wt2'] - dataframe['wt1'] <= 0 dataframe['wtCrossDown'] = dataframe['wt2'] - dataframe['wt1'] >= 0 dataframe['crossed_above'] = qtpylib.crossed_above( dataframe['wt2'], dataframe['wt1']) dataframe['crossed_below'] = qtpylib.crossed_below( dataframe['wt2'], dataframe['wt1']) return dataframe #rsi divergences dataframe['bullish_div'] dataframe['bearish_div'] def divergences(self, dataframe) -> DataFrame: dataframe['bullish_div'] = ( (dataframe['close'].shift(4) > dataframe['close'].shift(2)) & (dataframe['close'].shift(3) > dataframe['close'].shift(2)) & (dataframe['close'].shift(2) < dataframe['close'].shift(1)) & (dataframe['close'].shift(2) < dataframe['close'])) dataframe['bearish_div'] = ( (dataframe['close'].shift(4) < dataframe['close'].shift(2)) & (dataframe['close'].shift(3) < dataframe['close'].shift(2)) & (dataframe['close'].shift(2) > dataframe['close'].shift(1)) & (dataframe['close'].shift(2) > dataframe['close'])) return dataframe
def test_hyperopt_parameters(): from skopt.space import Categorical, Integer, Real with pytest.raises(OperationalException, match=r"Name is determined.*"): IntParameter(low=0, high=5, default=1, name='hello') with pytest.raises(OperationalException, match=r"IntParameter space must be.*"): IntParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"RealParameter space must be.*"): RealParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"DecimalParameter space must be.*"): DecimalParameter(low=0, default=5, space='buy') with pytest.raises(OperationalException, match=r"IntParameter space invalid\."): IntParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"RealParameter space invalid\."): RealParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"DecimalParameter space invalid\."): DecimalParameter([0, 10], high=7, default=5, space='buy') with pytest.raises(OperationalException, match=r"CategoricalParameter space must.*"): CategoricalParameter(['aa'], default='aa', space='buy') with pytest.raises(TypeError): BaseParameter(opt_range=[0, 1], default=1, space='buy') intpar = IntParameter(low=0, high=5, default=1, space='buy') assert intpar.value == 1 assert isinstance(intpar.get_space(''), Integer) assert isinstance(intpar.range, range) assert len(list(intpar.range)) == 1 # Range contains ONLY the default / value. assert list(intpar.range) == [intpar.value] intpar.in_space = True assert len(list(intpar.range)) == 6 assert list(intpar.range) == [0, 1, 2, 3, 4, 5] fltpar = RealParameter(low=0.0, high=5.5, default=1.0, space='buy') assert isinstance(fltpar.get_space(''), Real) assert fltpar.value == 1 fltpar = DecimalParameter(low=0.0, high=5.5, default=1.0004, decimals=3, space='buy') assert isinstance(fltpar.get_space(''), Integer) assert fltpar.value == 1 catpar = CategoricalParameter(['buy_rsi', 'buy_macd', 'buy_none'], default='buy_macd', space='buy') assert isinstance(catpar.get_space(''), Categorical) assert catpar.value == 'buy_macd'
class mabStra(IStrategy): # #################### RESULTS PASTE PLACE #################### # ROI table: minimal_roi = {"0": 0.598, "644": 0.166, "3269": 0.115, "7289": 0} # Stoploss: stoploss = -0.128 # Buy hypers timeframe = '4h' # #################### END OF RESULT PLACE #################### # buy params buy_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='buy') buy_fast_ma_timeframe = IntParameter(2, 100, default=14, space='buy') buy_slow_ma_timeframe = IntParameter(2, 100, default=28, space='buy') buy_div_max = DecimalParameter(0, 2, decimals=4, default=2.25446, space='buy') buy_div_min = DecimalParameter(0, 2, decimals=4, default=0.29497, space='buy') # sell params sell_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='sell') sell_fast_ma_timeframe = IntParameter(2, 100, default=14, space='sell') sell_slow_ma_timeframe = IntParameter(2, 100, default=28, space='sell') sell_div_max = DecimalParameter(0, 2, decimals=4, default=1.54593, space='sell') sell_div_min = DecimalParameter(0, 2, decimals=4, default=2.81436, space='sell') def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # SMA - ex Moving Average dataframe['buy-mojoMA'] = ta.SMA( dataframe, timeperiod=self.buy_mojo_ma_timeframe.value) dataframe['buy-fastMA'] = ta.SMA( dataframe, timeperiod=self.buy_fast_ma_timeframe.value) dataframe['buy-slowMA'] = ta.SMA( dataframe, timeperiod=self.buy_slow_ma_timeframe.value) dataframe['sell-mojoMA'] = ta.SMA( dataframe, timeperiod=self.sell_mojo_ma_timeframe.value) dataframe['sell-fastMA'] = ta.SMA( dataframe, timeperiod=self.sell_fast_ma_timeframe.value) dataframe['sell-slowMA'] = ta.SMA( dataframe, timeperiod=self.sell_slow_ma_timeframe.value) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[( (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) > self. buy_div_min.value) & (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) < self. buy_div_max.value) & (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) > self. buy_div_min.value) & (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) < self. buy_div_max.value)), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[( (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) > self. sell_div_min.value) & (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) < self. sell_div_max.value) & (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) > self. sell_div_min.value) & (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) < self. sell_div_max.value)), 'sell'] = 1 return dataframe
class Heracles(IStrategy): ########################################## RESULT PASTE PLACE ########################################## # 10/100: 25 trades. 18/4/3 Wins/Draws/Losses. Avg profit 5.92%. Median profit 6.33%. Total profit 0.04888306 BTC ( 48.88Σ%). Avg duration 4 days, 6:24:00 min. Objective: -11.42103 # Buy hyperspace params: buy_params = { "buy_crossed_indicator_shift": 9, "buy_div_max": 0.75, "buy_div_min": 0.16, "buy_indicator_shift": 15, } # Sell hyperspace params: sell_params = {} # ROI table: minimal_roi = {"0": 0.598, "644": 0.166, "3269": 0.115, "7289": 0} # Stoploss: stoploss = -0.256 # Optimal timeframe use it in your config timeframe = '4h' ########################################## END RESULT PASTE PLACE ###################################### # buy params buy_div_min = DecimalParameter(0, 1, default=0.16, decimals=2, space='buy') buy_div_max = DecimalParameter(0, 1, default=0.75, decimals=2, space='buy') buy_indicator_shift = IntParameter(0, 20, default=16, space='buy') buy_crossed_indicator_shift = IntParameter(0, 20, default=9, space='buy') def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = dropna(dataframe) dataframe['volatility_kcw'] = ta.volatility.keltner_channel_wband( dataframe['high'], dataframe['low'], dataframe['close'], window=20, window_atr=10, fillna=False, original_version=True) dataframe['volatility_dcp'] = ta.volatility.donchian_channel_pband( dataframe['high'], dataframe['low'], dataframe['close'], window=10, offset=0, fillna=False) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Buy strategy Hyperopt will build and use. """ conditions = [] IND = 'volatility_dcp' CRS = 'volatility_kcw' DFIND = dataframe[IND] DFCRS = dataframe[CRS] d = DFIND.shift(self.buy_indicator_shift.value).div( DFCRS.shift(self.buy_crossed_indicator_shift.value)) # print(d.min(), "\t", d.max()) conditions.append( d.between(self.buy_div_min.value, self.buy_div_max.value)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Sell strategy Hyperopt will build and use. """ dataframe.loc[:, 'sell'] = 0 return dataframe
class Supertrend(IStrategy): # Buy params, Sell params, ROI, Stoploss and Trailing Stop are values generated by 'freqtrade hyperopt --strategy Supertrend --hyperopt-loss ShortTradeDurHyperOptLoss --timerange=20210101- --timeframe=1h --spaces all' # It's encourage you find the values that better suites your needs and risk management strategies # Buy hyperspace params: buy_params = { "buy_m1": 4, "buy_m2": 7, "buy_m3": 1, "buy_p1": 8, "buy_p2": 9, "buy_p3": 8, } # Sell hyperspace params: sell_params = { "sell_m1": 1, "sell_m2": 3, "sell_m3": 6, "sell_p1": 16, "sell_p2": 18, "sell_p3": 18, } # ROI table: minimal_roi = {"0": 0.087, "372": 0.058, "861": 0.029, "2221": 0} # Stoploss: stoploss = -0.265 # Trailing stop: trailing_stop = True trailing_stop_positive = 0.05 trailing_stop_positive_offset = 0.144 trailing_only_offset_is_reached = False timeframe = '1h' startup_candle_count = 18 buy_m1 = IntParameter(1, 7, default=4) buy_m2 = IntParameter(1, 7, default=4) buy_m3 = IntParameter(1, 7, default=4) buy_p1 = IntParameter(7, 21, default=14) buy_p2 = IntParameter(7, 21, default=14) buy_p3 = IntParameter(7, 21, default=14) sell_m1 = IntParameter(1, 7, default=4) sell_m2 = IntParameter(1, 7, default=4) sell_m3 = IntParameter(1, 7, default=4) sell_p1 = IntParameter(7, 21, default=14) sell_p2 = IntParameter(7, 21, default=14) sell_p3 = IntParameter(7, 21, default=14) def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: for multiplier in self.buy_m1.range: for period in self.buy_p1.range: dataframe[ f'supertrend_1_buy_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] for multiplier in self.buy_m2.range: for period in self.buy_p2.range: dataframe[ f'supertrend_2_buy_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] for multiplier in self.buy_m3.range: for period in self.buy_p3.range: dataframe[ f'supertrend_3_buy_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] for multiplier in self.sell_m1.range: for period in self.sell_p1.range: dataframe[ f'supertrend_1_sell_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] for multiplier in self.sell_m2.range: for period in self.sell_p2.range: dataframe[ f'supertrend_2_sell_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] for multiplier in self.sell_m3.range: for period in self.sell_p3.range: dataframe[ f'supertrend_3_sell_{multiplier}_{period}'] = self.supertrend( dataframe, multiplier, period)['STX'] return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[( (dataframe[ f'supertrend_1_buy_{self.buy_m1.value}_{self.buy_p1.value}'] == 'up') & (dataframe[ f'supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}'] == 'up') & (dataframe[ f'supertrend_3_buy_{self.buy_m3.value}_{self.buy_p3.value}'] == 'up') & # The three indicators are 'up' for the current candle (dataframe['volume'] > 0) # There is at least some trading volume ), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[( (dataframe[ f'supertrend_1_sell_{self.sell_m1.value}_{self.sell_p1.value}'] == 'down') & (dataframe[ f'supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}'] == 'down') & (dataframe[ f'supertrend_3_sell_{self.sell_m3.value}_{self.sell_p3.value}'] == 'down') & # The three indicators are 'down' for the current candle (dataframe['volume'] > 0) # There is at least some trading volume ), 'sell'] = 1 return dataframe """ Supertrend Indicator; adapted for freqtrade from: https://github.com/freqtrade/freqtrade-strategies/issues/30 """ def supertrend(self, dataframe: DataFrame, multiplier, period): df = dataframe.copy() df['TR'] = ta.TRANGE(df) df['ATR'] = ta.SMA(df['TR'], period) st = 'ST_' + str(period) + '_' + str(multiplier) stx = 'STX_' + str(period) + '_' + str(multiplier) # Compute basic upper and lower bands df['basic_ub'] = (df['high'] + df['low']) / 2 + multiplier * df['ATR'] df['basic_lb'] = (df['high'] + df['low']) / 2 - multiplier * df['ATR'] # Compute final upper and lower bands df['final_ub'] = 0.00 df['final_lb'] = 0.00 for i in range(period, len(df)): df['final_ub'].iat[i] = df['basic_ub'].iat[ i] if df['basic_ub'].iat[i] < df['final_ub'].iat[ i - 1] or df['close'].iat[i - 1] > df['final_ub'].iat[ i - 1] else df['final_ub'].iat[i - 1] df['final_lb'].iat[i] = df['basic_lb'].iat[ i] if df['basic_lb'].iat[i] > df['final_lb'].iat[ i - 1] or df['close'].iat[i - 1] < df['final_lb'].iat[ i - 1] else df['final_lb'].iat[i - 1] # Set the Supertrend value df[st] = 0.00 for i in range(period, len(df)): df[st].iat[i] = df['final_ub'].iat[i] if df[st].iat[i - 1] == df['final_ub'].iat[i - 1] and df['close'].iat[i] <= df['final_ub'].iat[i] else \ df['final_lb'].iat[i] if df[st].iat[i - 1] == df['final_ub'].iat[i - 1] and df['close'].iat[i] > df['final_ub'].iat[i] else \ df['final_lb'].iat[i] if df[st].iat[i - 1] == df['final_lb'].iat[i - 1] and df['close'].iat[i] >= df['final_lb'].iat[i] else \ df['final_ub'].iat[i] if df[st].iat[i - 1] == df['final_lb'].iat[i - 1] and df['close'].iat[i] < df['final_lb'].iat[i] else 0.00 # Mark the trend direction up/down df[stx] = np.where((df[st] > 0.00), np.where((df['close'] < df[st]), 'down', 'up'), np.NaN) # Remove basic and final bands from the columns df.drop(['basic_ub', 'basic_lb', 'final_ub', 'final_lb'], inplace=True, axis=1) df.fillna(0, inplace=True) return DataFrame(index=df.index, data={'ST': df[st], 'STX': df[stx]})
class mabStra(IStrategy): # buy params buy_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='buy') buy_fast_ma_timeframe = IntParameter(2, 100, default=14, space='buy') buy_slow_ma_timeframe = IntParameter(2, 100, default=28, space='buy') buy_div_max = DecimalParameter(0, 2, decimals=4, default=2.25446, space='buy') buy_div_min = DecimalParameter(0, 2, decimals=4, default=0.29497, space='buy') # sell params sell_mojo_ma_timeframe = IntParameter(2, 100, default=7, space='sell') sell_fast_ma_timeframe = IntParameter(2, 100, default=14, space='sell') sell_slow_ma_timeframe = IntParameter(2, 100, default=28, space='sell') sell_div_max = DecimalParameter(0, 2, decimals=4, default=1.54593, space='sell') sell_div_min = DecimalParameter(0, 2, decimals=4, default=2.81436, space='sell') stoploss = -0.1 # Optimal timeframe use it in your config timeframe = '4h' def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # SMA - ex Moving Average dataframe['buy-mojoMA'] = ta.SMA(dataframe, timeperiod=self.buy_mojo_ma_timeframe.value) dataframe['buy-fastMA'] = ta.SMA(dataframe, timeperiod=self.buy_fast_ma_timeframe.value) dataframe['buy-slowMA'] = ta.SMA(dataframe, timeperiod=self.buy_slow_ma_timeframe.value) dataframe['sell-mojoMA'] = ta.SMA(dataframe, timeperiod=self.sell_mojo_ma_timeframe.value) dataframe['sell-fastMA'] = ta.SMA(dataframe, timeperiod=self.sell_fast_ma_timeframe.value) dataframe['sell-slowMA'] = ta.SMA(dataframe, timeperiod=self.sell_slow_ma_timeframe.value) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) > self.buy_div_min.value) & (dataframe['buy-mojoMA'].div(dataframe['buy-fastMA']) < self.buy_div_max.value) & (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) > self.buy_div_min.value) & (dataframe['buy-fastMA'].div(dataframe['buy-slowMA']) < self.buy_div_max.value) ), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) > self.sell_div_min.value) & (dataframe['sell-fastMA'].div(dataframe['sell-mojoMA']) < self.sell_div_max.value) & (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) > self.sell_div_min.value) & (dataframe['sell-slowMA'].div(dataframe['sell-fastMA']) < self.sell_div_max.value) ), 'sell'] = 1 return dataframe
class Diamond(IStrategy): # ###################### RESULT PLACE ###################### # Config: 5 x UNLIMITED STOCK costume pair list, # hyperopt : 5000 x SortinoHyperOptLossDaily, # 34/5000: 297 trades. 136/156/5 Wins/Draws/Losses. Avg profit 0.49%. Median profit 0.00%. Total profit 45.84477237 USDT ( 33.96Σ%). Avg duration 11:54:00 min. Objective: -46.50379 # Buy hyperspace params: buy_params = { "buy_fast_key": "high", "buy_horizontal_push": 7, "buy_slow_key": "volume", "buy_vertical_push": 0.942, } # Sell hyperspace params: sell_params = { "sell_fast_key": "high", "sell_horizontal_push": 10, "sell_slow_key": "low", "sell_vertical_push": 1.184, } # ROI table: minimal_roi = {"0": 0.242, "13": 0.044, "51": 0.02, "170": 0} # Stoploss: stoploss = -0.271 # Trailing stop: trailing_stop = True trailing_stop_positive = 0.011 trailing_stop_positive_offset = 0.054 trailing_only_offset_is_reached = False # timeframe timeframe = '5m' # #################### END OF RESULT PLACE #################### buy_vertical_push = DecimalParameter(0.5, 1.5, decimals=3, default=1, space='buy') buy_horizontal_push = IntParameter(0, 10, default=0, space='buy') buy_fast_key = CategoricalParameter( [ 'open', 'high', 'low', 'close', 'volume', # you can not enable this lines befour you # populate an indicator for them and set # the same key name for it # 'ma_fast', 'ma_slow', {...} ], default='ma_fast', space='buy') buy_slow_key = CategoricalParameter( [ 'open', 'high', 'low', 'close', 'volume', # 'ma_fast', 'ma_slow', {...} ], default='ma_slow', space='buy') sell_vertical_push = DecimalParameter(0.5, 1.5, decimals=3, default=1, space='sell') sell_horizontal_push = IntParameter(0, 10, default=0, space='sell') sell_fast_key = CategoricalParameter( [ 'open', 'high', 'low', 'close', 'volume', # 'ma_fast', 'ma_slow', {...} ], default='ma_fast', space='sell') sell_slow_key = CategoricalParameter( [ 'open', 'high', 'low', 'close', 'volume', # 'ma_fast', 'ma_slow', {...} ], default='ma_slow', space='sell') def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # you can add new indicators and enable them inside # hyperoptable categorical params on the top # dataframe['ma_fast'] = ta.SMA(dataframe, timeperiod=9) # dataframe['ma_slow'] = ta.SMA(dataframe, timeperiod=18) # dataframe['{...}'] = ta.{...}(dataframe, timeperiod={...}) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append( qtpylib.crossed_above( dataframe[self.buy_fast_key.value].shift( self.buy_horizontal_push.value), dataframe[self.buy_slow_key.value] * self.buy_vertical_push.value)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append( qtpylib.crossed_below( dataframe[self.sell_fast_key.value].shift( self.sell_horizontal_push.value), dataframe[self.sell_slow_key.value] * self.sell_vertical_push.value)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe
class MultiMa(IStrategy): buy_ma_count = IntParameter(2, 10, default=10, space='buy') buy_ma_gap = IntParameter(2, 10, default=2, space='buy') buy_ma_shift = IntParameter(0, 10, default=0, space='buy') # buy_ma_rolling = IntParameter(0, 10, default=0, space='buy') sell_ma_count = IntParameter(2, 10, default=10, space='sell') sell_ma_gap = IntParameter(2, 10, default=2, space='sell') sell_ma_shift = IntParameter(0, 10, default=0, space='sell') # sell_ma_rolling = IntParameter(0, 10, default=0, space='sell') # ROI table: minimal_roi = {"0": 0.30873, "569": 0.16689, "3211": 0.06473, "7617": 0} # Stoploss: stoploss = -0.1 # Buy hypers timeframe = '4h' def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # We will dinamicly generate the indicators # cuz this method just run one time in hyperopts # if you have static timeframes you can move first loop of buy and sell trends populators inside this method return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: for i in self.buy_ma_count.range: dataframe[f'buy-ma-{i+1}'] = ta.SMA( dataframe, timeperiod=int((i + 1) * self.buy_ma_gap.value)) conditions = [] for i in self.buy_ma_count.range: if i > 1: shift = self.buy_ma_shift.value for shift in self.buy_ma_shift.range: conditions.append(dataframe[f'buy-ma-{i}'].shift(shift) > dataframe[f'buy-ma-{i-1}'].shift(shift)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'buy'] = 1 return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: for i in self.sell_ma_count.range: dataframe[f'sell-ma-{i+1}'] = ta.SMA( dataframe, timeperiod=int((i + 1) * self.sell_ma_gap.value)) conditions = [] for i in self.sell_ma_count.range: if i > 1: shift = self.sell_ma_shift.value for shift in self.sell_ma_shift.range: conditions.append(dataframe[f'sell-ma-{i}'].shift(shift) < dataframe[f'sell-ma-{i-1}'].shift(shift)) if conditions: dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 return dataframe