import freqtrade.vendor.qtpylib.indicators as qtpylib import numpy as np import talib.abstract as ta from freqtrade.persistence import Trade from freqtrade.strategy.interface import IStrategy from datetime import datetime, timedelta from pandas import DataFrame, Series, concat from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter, stoploss_from_open from functools import reduce from technical.indicators import RMI, vwmacd import logging import pandas_ta as pta from numpy import where import time import datetime ##################################################### BeastBot XBLR6 #################################################################### # don't need hyperopt for binance, thanks free comunity, it have parts other strategies, without freqtrade comunity this strategy is not possible # # if you earn money and consider rewarding the author ETH: 0xda884c4dbe47421ba63f033db3cc2ec49d552365 BTC: 1hxiKHLaPDKTWuXhVgTZvBdPZtjC9msxi # #################################################################################################################################################### # hyperopt for each conditions and finally all conditions true # backtesting: freqtrade backtesting -c config_test.json -s BeastBotXBLR6 --timerange 20210920-20220127 --breakdown day -v --enable-protections # 119 days # for each conditions # Trades | Win Draw Loss | Avg profit | Profit | Avg duration | Max Drawdown # Con1 12 | 11 0 1 | 2.63% | (15.82%) | 0 days 00:15:00 | (8.27%) | # Con2 16 | 15 0 1 | 2.47% | (19.77%) | 0 days 01:19:00 | (5.15%) | # Con3 12 | 12 0 0 | 2.85% | (17.11%) | 0 days 00:31:00 | -- | # Con4 18 | 16 0 2 | 2.29% | (20.61%) | 0 days 03:11:00 | (5.23%) | # Con6 11 | 10 0 1 | 2.73% | (15.05%) | 0 days 03:15:00 | (0.75%) | # Con7 1 | 1 0 0 | 9.37% | (4.69%) | 0 days 00:30:00 | -- | # Con8 13 | 12 0 1 | 2.31% | (15.06%) | 0 days 05:19:00 | (5.09%) | # Con9 7 | 7 0 0 | 2.62% | (9.17%) | 0 days 00:19:00 | -- | # con10 26 | 19 0 7 | 1.03% | (13.41%) | 0 days 02:39:00 | (3.76%) # all conditions true logger = logging.getLogger(__name__) # Williams %R def williams_r(dataframe: DataFrame, period: int=14) -> Series: """Williams %R, or just %R, is a technical analysis oscillator showing the current closing price in relation to the high and low of the past N days (for a given N). It was developed by a publisher and promoter of trading materials, Larry Williams. Its purpose is to tell whether a stock or commodity market is trading near the high or the low, or somewhere in between, of its recent trading range. The oscillator is on a negative scale, from −100 (lowest) up to 0 (highest). """ highest_high = dataframe['high'].rolling(center=False, window=period).max() lowest_low = dataframe['low'].rolling(center=False, window=period).min() WR = Series((highest_high - dataframe['close']) / (highest_high - lowest_low), name=f'{period} Williams %R') return WR * -100 def EWO(dataframe, ema_length=5, ema2_length=35): df = dataframe.copy() ema1 = ta.EMA(df, timeperiod=ema_length) ema2 = ta.EMA(df, timeperiod=ema2_length) emadif = (ema1 - ema2) / df['close'] * 100 return emadif def SROC(dataframe, roclen=21, emalen=13, smooth=21): df = dataframe.copy() roc = ta.ROC(df, timeperiod=roclen) ema = ta.EMA(df, timeperiod=emalen) sroc = ta.ROC(ema, timeperiod=smooth) return sroc def SSLChannels_ATR(dataframe, length=7): """ SSL Channels with ATR: https://www.tradingview.com/script/SKHqWzql-SSL-ATR-channel/ Credit to @JimmyNixx for python """ df = dataframe.copy() df['ATR'] = ta.ATR(df, timeperiod=14) df['smaHigh'] = df['high'].rolling(length).mean() + df['ATR'] df['smaLow'] = df['low'].rolling(length).mean() - df['ATR'] df['hlv'] = np.where(df['close'] > df['smaHigh'], 1, np.where(df['close'] < df['smaLow'], -1, np.NAN)) df['hlv'] = df['hlv'].ffill() df['sslDown'] = np.where(df['hlv'] < 0, df['smaHigh'], df['smaLow']) df['sslUp'] = np.where(df['hlv'] < 0, df['smaLow'], df['smaHigh']) return (df['sslDown'], df['sslUp']) class BeastBotXBLR6(IStrategy): INTERFACE_VERSION = 3 timeframe = '5m' inf_1h = '1h' info_timeframe_1d = '1d' has_BTC_info_tf = True # Buy hyperspace params: entry_params = {'entry_c10_1': -101.4, 'entry_c10_2': -0.86, 'entry_c9_1': 40.0, 'entry_c9_2': -70.4, 'entry_c9_3': -67.0, 'entry_c9_4': 41.8, 'entry_c9_5': 33.6, 'entry_c9_6': 82.7, 'entry_c9_7': -94.3, 'entry_con3_1': 0.016, 'entry_con3_2': 0.984, 'entry_con3_3': 0.966, 'entry_con3_4': -0.88, 'entry_macd_41': 0.08, 'entry_rsi_1h_42': 19.9, 'entry_volume_drop_41': 3.7, 'entry_volume_pump_41': 0.1, 'entry_bb_delta': 0.023, 'entry_bb_factor': 0.99, 'entry_bb_width': 0.097, 'entry_c2_1': 0.02, 'entry_c2_2': 0.991, 'entry_c2_3': -0.7, 'entry_c6_1': 0.16, 'entry_c6_2': 0.03, 'entry_c6_3': 0.02, 'entry_c6_4': 0.022, 'entry_c6_5': 0.387, 'entry_c7_1': 1.01, 'entry_c7_2': 0.99, 'entry_c7_3': -99, 'entry_c7_4': -64, 'entry_c7_5': 81.4, 'entry_cci': -112, 'entry_cci_length': 25, 'entry_closedelta': 12.232, 'entry_con1_enable': True, 'entry_con2_enable': True, 'entry_con3_enable': True, 'entry_con4_enable': True, 'entry_con6_enable': True, 'entry_condition_10_enable': True, 'entry_condition_7_enable': True, 'entry_condition_8_enable': True, 'entry_condition_9_enable': True, 'entry_dip_threshold_5': 0.05, 'entry_dip_threshold_6': 0.2, 'entry_dip_threshold_7': 0.4, 'entry_dip_threshold_8': 0.5, 'entry_mfi_1': 29.8, 'entry_min_inc_1': 0.025, 'entry_pump_pull_threshold_1': 1.75, 'entry_pump_threshold_1': 0.5, 'entry_rmi': 36, 'entry_rmi_length': 13, 'entry_rsi_1': 39.8, 'entry_rsi_1h_max_1': 73.8, 'entry_rsi_1h_min_1': 36.2, 'entry_srsi_fk': 49} # Sell hyperspace params: exit_params = {'exit_bb_relative_8': 1.1, 'exit_condition_1_enable': True, 'exit_condition_2_enable': True, 'exit_condition_3_enable': True, 'exit_condition_4_enable': True, 'exit_condition_5_enable': True, 'exit_condition_6_enable': True, 'exit_condition_7_enable': True, 'exit_condition_8_enable': True, 'exit_custom_dec_profit_1': 0.05, 'exit_custom_dec_profit_2': 0.07, 'exit_custom_profit_0': 0.01, 'exit_custom_profit_1': 0.03, 'exit_custom_profit_2': 0.05, 'exit_custom_profit_3': 0.08, 'exit_custom_profit_4': 0.25, 'exit_custom_profit_under_rel_1': 0.024, 'exit_custom_profit_under_rsi_diff_1': 4.4, 'exit_custom_rsi_0': 33.0, 'exit_custom_rsi_1': 38.0, 'exit_custom_rsi_2': 43.0, 'exit_custom_rsi_3': 48.0, 'exit_custom_rsi_4': 50.0, 'exit_custom_stoploss_under_rel_1': 0.004, 'exit_custom_stoploss_under_rsi_diff_1': 8.0, 'exit_custom_under_profit_1': 0.02, 'exit_custom_under_profit_2': 0.04, 'exit_custom_under_profit_3': 0.6, 'exit_custom_under_rsi_1': 56.0, 'exit_custom_under_rsi_2': 60.0, 'exit_custom_under_rsi_3': 62.0, 'exit_dual_rsi_rsi_1h_4': 79.6, 'exit_dual_rsi_rsi_4': 73.4, 'exit_ema_relative_5': 0.024, 'exit_profit_trendstop': 0.02, 'exit_rsi_1h_7': 81.7, 'exit_rsi_bb_1': 79.5, 'exit_rsi_bb_2': 81, 'exit_rsi_diff_5': 4.4, 'exit_rsi_main_3': 82, 'exit_rsi_under_6': 79.0, 'exit_time_stoploss': 114, 'exit_time_trendstop': 113, 'exit_trail_down_1': 0.18, 'exit_trail_down_2': 0.14, 'exit_trail_down_3': 0.01, 'exit_trail_profit_max_1': 0.46, 'exit_trail_profit_max_2': 0.12, 'exit_trail_profit_max_3': 0.1, 'exit_trail_profit_min_1': 0.15, 'exit_trail_profit_min_2': 0.01, 'exit_trail_profit_min_3': 0.05} minimal_roi = {'0': 100} # new exit stoploss = -0.99 use_custom_stoploss = False # Recommended use_exit_signal = True exit_profit_only = False ignore_roi_if_entry_signal = True # Required startup_candle_count: int = 300 process_only_new_candles = False # Strategy Specific Variable Storage custom_trade_info = {} custom_fiat = 'USD' # Only relevant if stake is BTC or ETH plot_config = {'main_plot': {'ema_50_1h': {'color': 'rgba(255,250,200,2.4)'}, 'bb_lowerband': {'color': '#792bbb', 'type': 'line'}, 'bb_upperband': {'color': '#bc281d', 'type': 'line'}}, 'subplots': {'RSI/BTC': {'mfi': {'color': '#e12a7c', 'type': 'line'}, 'cci': {'color': '#794491', 'type': 'line'}, 'ssl-dir_1h': {'color': '#2773a7', 'type': 'line'}, 'ssl-dir': {'color': '#5379a2', 'type': 'line'}}}} custom_trendBTC_info = {} if not 'trend' in custom_trendBTC_info: custom_trendBTC_info['trend'] = {} if not 'not_downtrend' in custom_trendBTC_info['trend']: custom_trendBTC_info['trend']['not_downtrend'] = 0 if not 'st' in custom_trendBTC_info['trend']: custom_trendBTC_info['trend']['st'] = 0 if not 'stx' in custom_trendBTC_info['trend']: custom_trendBTC_info['trend']['stx'] = 0 @property def protections(self): return [{'method': 'CooldownPeriod', 'stop_duration': 120}, {'method': 'StoplossGuard', 'lookback_period': 90, 'trade_limit': 2, 'stop_duration': 120, 'only_per_pair': False}, {'method': 'StoplossGuard', 'lookback_period': 90, 'trade_limit': 1, 'stop_duration': 120, 'only_per_pair': True}] ########################################################################### # Buy Optimize_condition = False entry_con1_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_con2_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_con3_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_con4_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_con6_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_condition_7_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_condition_8_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_condition_9_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) entry_condition_10_enable = CategoricalParameter([True, False], default=True, space='entry', optimize=Optimize_condition, load=True) optc1 = True entry_rmi_length = IntParameter(8, 20, default=8, optimize=optc1, load=True) entry_rmi = IntParameter(30, 50, default=35, optimize=optc1, load=True) entry_cci_length = IntParameter(25, 45, default=25, optimize=optc1, load=True) entry_cci = IntParameter(-135, -90, default=-133, optimize=optc1, load=True) entry_srsi_fk = IntParameter(30, 50, default=25, optimize=optc1, load=True) entry_bb_width = DecimalParameter(0.065, 0.135, default=0.095, optimize=optc1, load=True) entry_bb_delta = DecimalParameter(0.018, 0.035, default=0.025, optimize=optc1, load=True) entry_bb_factor = DecimalParameter(0.99, 0.999, default=0.995, optimize=optc1, load=True) entry_closedelta = DecimalParameter(12.0, 18.0, default=15.0, optimize=optc1, load=True) optc2 = False entry_c2_1 = DecimalParameter(0.01, 0.025, default=0.018, space='entry', decimals=3, optimize=optc2, load=True) entry_c2_2 = DecimalParameter(0.98, 0.995, default=0.982, space='entry', decimals=3, optimize=optc2, load=True) entry_c2_3 = DecimalParameter(-0.8, -0.3, default=-0.5, space='entry', decimals=1, optimize=optc2, load=True) optc3 = False entry_con3_1 = DecimalParameter(0.01, 0.025, default=0.017, space='entry', decimals=3, optimize=optc3, load=True) entry_con3_2 = DecimalParameter(0.98, 0.995, default=0.984, space='entry', decimals=3, optimize=optc3, load=True) entry_con3_3 = DecimalParameter(0.955, 0.975, default=0.965, space='entry', decimals=3, optimize=optc3, load=True) entry_con3_4 = DecimalParameter(-0.95, -0.7, default=-0.85, space='entry', decimals=2, optimize=optc3, load=True) optc4 = False entry_rsi_1h_42 = DecimalParameter(10.0, 50.0, default=15.0, space='entry', decimals=1, optimize=optc4, load=True) entry_macd_41 = DecimalParameter(0.01, 0.09, default=0.02, space='entry', decimals=2, optimize=optc4, load=True) entry_volume_pump_41 = DecimalParameter(0.1, 0.9, default=0.4, space='entry', decimals=1, optimize=optc4, load=True) entry_volume_drop_41 = DecimalParameter(1, 10, default=3.8, space='entry', decimals=1, optimize=optc4, load=True) optc6 = True entry_c6_2 = DecimalParameter(0.98, 0.999, default=0.985, space='entry', decimals=3, optimize=optc6, load=True) entry_c6_1 = DecimalParameter(0.08, 0.2, default=0.12, space='entry', decimals=2, optimize=optc6, load=True) entry_c6_2 = DecimalParameter(0.02, 0.4, default=0.28, space='entry', decimals=2, optimize=optc6, load=True) entry_c6_3 = DecimalParameter(0.005, 0.04, default=0.031, space='entry', decimals=3, optimize=optc6, load=True) entry_c6_4 = DecimalParameter(0.01, 0.03, default=0.021, space='entry', decimals=3, optimize=optc6, load=True) entry_c6_5 = DecimalParameter(0.2, 0.4, default=0.264, space='entry', decimals=3, optimize=optc6, load=True) optc7 = True entry_c7_1 = DecimalParameter(0.95, 1.1, default=1.01, space='entry', decimals=2, optimize=optc7, load=True) entry_c7_2 = DecimalParameter(0.95, 1.1, default=0.99, space='entry', decimals=2, optimize=optc7, load=True) entry_c7_3 = IntParameter(-100, -80, default=-94, space='entry', optimize=optc7, load=True) entry_c7_4 = IntParameter(-90, -60, default=-75, space='entry', optimize=optc7, load=True) entry_c7_5 = DecimalParameter(75.1, 90.1, default=80.0, space='entry', decimals=1, optimize=optc7, load=True) optc8 = False entry_min_inc_1 = DecimalParameter(0.01, 0.05, default=0.022, space='entry', decimals=3, optimize=optc8, load=True) entry_rsi_1h_min_1 = DecimalParameter(25.0, 40.0, default=30.0, space='entry', decimals=1, optimize=optc8, load=True) entry_rsi_1h_max_1 = DecimalParameter(70.0, 90.0, default=84.0, space='entry', decimals=1, optimize=optc8, load=True) entry_rsi_1 = DecimalParameter(20.0, 40.0, default=36.0, space='entry', decimals=1, optimize=optc8, load=True) entry_mfi_1 = DecimalParameter(20.0, 40.0, default=26.0, space='entry', decimals=1, optimize=optc8, load=True) optc9 = False entry_c9_1 = DecimalParameter(25.0, 44.0, default=36.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_2 = DecimalParameter(-80.0, -67.0, default=-75.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_3 = DecimalParameter(-80.0, -67.0, default=-75.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_4 = DecimalParameter(35.0, 54.0, default=46.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_5 = DecimalParameter(20.0, 44.0, default=30.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_6 = DecimalParameter(65.0, 94.0, default=84.0, space='entry', decimals=1, optimize=optc9, load=True) entry_c9_7 = DecimalParameter(-110.0, -80.0, default=-99.0, space='entry', decimals=1, optimize=optc9, load=True) optc10 = True entry_c10_1 = DecimalParameter(-110.0, -80.0, default=-99.0, space='entry', decimals=1, optimize=optc10, load=True) entry_c10_2 = DecimalParameter(-1, -0.5, default=-0.78, space='entry', decimals=2, optimize=optc10, load=True) entry_dip_threshold_5 = DecimalParameter(0.001, 0.05, default=0.015, space='entry', decimals=3, optimize=False, load=True) entry_dip_threshold_6 = DecimalParameter(0.01, 0.2, default=0.06, space='entry', decimals=3, optimize=False, load=True) entry_dip_threshold_7 = DecimalParameter(0.05, 0.4, default=0.24, space='entry', decimals=3, optimize=False, load=True) entry_dip_threshold_8 = DecimalParameter(0.2, 0.5, default=0.4, space='entry', decimals=3, optimize=False, load=True) # 24 hours entry_pump_pull_threshold_1 = DecimalParameter(1.5, 3.0, default=1.75, space='entry', decimals=2, optimize=False, load=True) entry_pump_threshold_1 = DecimalParameter(0.4, 1.0, default=0.5, space='entry', decimals=3, optimize=False, load=True) # Sell·································································· exit_condition_1_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_2_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_3_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_4_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_5_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_6_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_7_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_condition_8_enable = CategoricalParameter([True, False], default=True, space='exit', optimize=True, load=True) exit_rsi_bb_1 = DecimalParameter(60.0, 80.0, default=79.5, space='exit', decimals=1, optimize=False, load=True) exit_rsi_bb_2 = DecimalParameter(72.0, 90.0, default=81, space='exit', decimals=1, optimize=False, load=True) exit_rsi_main_3 = DecimalParameter(77.0, 90.0, default=82, space='exit', decimals=1, optimize=False, load=True) exit_dual_rsi_rsi_4 = DecimalParameter(72.0, 84.0, default=73.4, space='exit', decimals=1, optimize=False, load=True) exit_dual_rsi_rsi_1h_4 = DecimalParameter(78.0, 92.0, default=79.6, space='exit', decimals=1, optimize=False, load=True) exit_ema_relative_5 = DecimalParameter(0.005, 0.05, default=0.024, space='exit', optimize=False, load=True) exit_rsi_diff_5 = DecimalParameter(0.0, 20.0, default=4.4, space='exit', optimize=False, load=True) exit_rsi_under_6 = DecimalParameter(72.0, 90.0, default=79.0, space='exit', decimals=1, optimize=False, load=True) exit_rsi_1h_7 = DecimalParameter(80.0, 95.0, default=81.7, space='exit', decimals=1, optimize=False, load=True) exit_bb_relative_8 = DecimalParameter(1.05, 1.3, default=1.1, space='exit', decimals=3, optimize=False, load=True) optimize_exit = False exit_custom_profit_0 = DecimalParameter(0.01, 0.1, default=0.01, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_rsi_0 = DecimalParameter(30.0, 40.0, default=33.0, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_profit_1 = DecimalParameter(0.01, 0.1, default=0.03, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_rsi_1 = DecimalParameter(30.0, 50.0, default=38.0, space='exit', decimals=2, optimize=optimize_exit, load=True) exit_custom_profit_2 = DecimalParameter(0.01, 0.1, default=0.05, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_rsi_2 = DecimalParameter(34.0, 50.0, default=43.0, space='exit', decimals=2, optimize=optimize_exit, load=True) exit_custom_profit_3 = DecimalParameter(0.06, 0.3, default=0.08, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_rsi_3 = DecimalParameter(38.0, 55.0, default=48.0, space='exit', decimals=2, optimize=optimize_exit, load=True) exit_custom_profit_4 = DecimalParameter(0.3, 0.6, default=0.25, space='exit', decimals=3, optimize=optimize_exit, load=True) exit_custom_rsi_4 = DecimalParameter(40.0, 58.0, default=50.0, space='exit', decimals=2, optimize=optimize_exit, load=True) optimize_exit_u = False exit_custom_under_profit_1 = DecimalParameter(0.01, 0.1, default=0.02, space='exit', decimals=3, optimize=optimize_exit_u, load=True) exit_custom_under_rsi_1 = DecimalParameter(36.0, 60.0, default=56.0, space='exit', decimals=1, optimize=optimize_exit_u, load=True) exit_custom_under_profit_2 = DecimalParameter(0.01, 0.1, default=0.04, space='exit', decimals=3, optimize=optimize_exit_u, load=True) exit_custom_under_rsi_2 = DecimalParameter(46.0, 66.0, default=60.0, space='exit', decimals=1, optimize=optimize_exit_u, load=True) exit_custom_under_profit_3 = DecimalParameter(0.01, 0.1, default=0.6, space='exit', decimals=3, optimize=optimize_exit_u, load=True) exit_custom_under_rsi_3 = DecimalParameter(50.0, 68.0, default=62.0, space='exit', decimals=1, optimize=optimize_exit_u, load=True) exit_custom_dec_profit_1 = DecimalParameter(0.01, 0.1, default=0.05, space='exit', decimals=3, optimize=False, load=True) exit_custom_dec_profit_2 = DecimalParameter(0.05, 0.2, default=0.07, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_min_1 = DecimalParameter(0.1, 0.25, default=0.15, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_max_1 = DecimalParameter(0.3, 0.5, default=0.46, space='exit', decimals=2, optimize=False, load=True) exit_trail_down_1 = DecimalParameter(0.04, 0.2, default=0.18, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_min_2 = DecimalParameter(0.01, 0.1, default=0.01, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_max_2 = DecimalParameter(0.08, 0.25, default=0.12, space='exit', decimals=2, optimize=False, load=True) exit_trail_down_2 = DecimalParameter(0.04, 0.2, default=0.14, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_min_3 = DecimalParameter(0.01, 0.1, default=0.05, space='exit', decimals=3, optimize=False, load=True) exit_trail_profit_max_3 = DecimalParameter(0.08, 0.16, default=0.1, space='exit', decimals=2, optimize=False, load=True) exit_trail_down_3 = DecimalParameter(0.01, 0.04, default=0.01, space='exit', decimals=3, optimize=False, load=True) exit_custom_profit_under_rel_1 = DecimalParameter(0.01, 0.04, default=0.024, space='exit', optimize=False, load=True) exit_custom_profit_under_rsi_diff_1 = DecimalParameter(0.0, 20.0, default=4.4, space='exit', optimize=False, load=True) exit_custom_stoploss_under_rel_1 = DecimalParameter(0.001, 0.02, default=0.004, space='exit', optimize=False, load=True) exit_custom_stoploss_under_rsi_diff_1 = DecimalParameter(0.0, 20.0, default=8.0, space='exit', optimize=False, load=True) exit_time_stoploss = IntParameter(70, 120, default=90, space='exit', optimize=True, load=True) exit_time_trendstop = IntParameter(70, 120, default=90, space='exit', optimize=True, load=True) exit_profit_trendstop = DecimalParameter(0.009, 0.02, default=0.015, space='exit', optimize=True, load=True) ############################################################# def get_ticker_indicator(self): return int(self.timeframe[:-1]) def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, **kwargs): dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() enter_tag = 'empty' if hasattr(trade, 'enter_tag') and trade.entry_tag is not None: enter_tag = trade.entry_tag entry_tags = entry_tag.split() trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60) max_profit = (trade.max_rate - trade.open_rate) / trade.open_rate if last_candle is not None: if (current_profit > self.exit_custom_profit_4.value) & (last_candle['rsi'] < self.exit_custom_rsi_4.value): return f'sf_4( {enter_tag})' elif (current_profit > self.exit_custom_profit_3.value) & (last_candle['rsi'] < self.exit_custom_rsi_3.value): return f'sf_3( {enter_tag})' elif (current_profit > self.exit_custom_profit_2.value) & (last_candle['rsi'] < self.exit_custom_rsi_2.value): return f'sf_2( {enter_tag})' elif (current_profit > self.exit_custom_profit_1.value) & (last_candle['rsi'] < self.exit_custom_rsi_1.value): return f'sf_1( {enter_tag})' elif (current_profit > self.exit_custom_profit_0.value) & (last_candle['rsi'] < self.exit_custom_rsi_0.value): return f'sf_0( {enter_tag})' elif (current_profit > self.exit_custom_under_profit_1.value) & (last_candle['rsi'] < self.exit_custom_under_rsi_1.value) & (last_candle['close'] < last_candle['ema_200']): return f'sf_u_1( {enter_tag})' elif (current_profit > self.exit_custom_under_profit_2.value) & (last_candle['rsi'] < self.exit_custom_under_rsi_2.value) & (last_candle['close'] < last_candle['ema_200']): return f'sf_u_2( {enter_tag})' elif (current_profit > self.exit_custom_under_profit_3.value) & (last_candle['rsi'] < self.exit_custom_under_rsi_3.value) & (last_candle['close'] < last_candle['ema_200']): return f'sf_u_3( {enter_tag})' elif (current_profit > self.exit_custom_dec_profit_1.value) & last_candle['sma_200_dec']: return f'sf_d_1( {enter_tag})' elif (current_profit > self.exit_custom_dec_profit_2.value) & (last_candle['close'] < last_candle['ema_100']): return f'sf_d_2( {enter_tag})' elif (current_profit > self.exit_trail_profit_min_1.value) & (current_profit < self.exit_trail_profit_max_1.value) & (max_profit > current_profit + self.exit_trail_down_1.value): return f'sf_t_1( {enter_tag})' elif (current_profit > self.exit_trail_profit_min_2.value) & (current_profit < self.exit_trail_profit_max_2.value) & (max_profit > current_profit + self.exit_trail_down_2.value): return f'sf_t_2( {enter_tag})' elif (last_candle['close'] < last_candle['ema_200']) & (current_profit > self.exit_trail_profit_min_3.value) & (current_profit < self.exit_trail_profit_max_3.value) & (max_profit > current_profit + self.exit_trail_down_3.value): return f'sf_u_t_1( {enter_tag})' elif (current_profit > 0.0) & (last_candle['close'] < last_candle['ema_200']) & ((last_candle['ema_200'] - last_candle['close']) / last_candle['close'] < self.exit_custom_profit_under_rel_1.value) & (last_candle['rsi'] > last_candle['rsi_1h'] + self.exit_custom_profit_under_rsi_diff_1.value): return f'sf_u_e_1( {enter_tag})' elif (current_profit < -0.0) & (last_candle['close'] < last_candle['ema_200']) & ((last_candle['ema_200'] - last_candle['close']) / last_candle['close'] < self.exit_custom_stoploss_under_rel_1.value) & (last_candle['rsi'] > last_candle['rsi_1h'] + self.exit_custom_stoploss_under_rsi_diff_1.value): return f'stoploss ( {enter_tag})' elif (current_profit < -0.05) & (trade_dur > self.exit_time_stoploss.value) & (last_candle['ssl-dir'] == 'down'): return f'stoploss5 ( {enter_tag})' elif (enter_tag in [' trend ']) & (trade_dur > self.exit_time_trendstop.value) & ((last_candle['ssl-dir'] == 'down') & (current_profit < self.exit_profit_trendstop.value)): return f'trend_stop' elif current_profit < -0.08: return f'stoploss8 ( {enter_tag})' return None def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, time_in_force: str, exit_reason: str, **kwargs) -> bool: return True def informative_pairs(self): pairs = self.dp.current_whitelist() informative_pairs = [(pair, self.inf_1h) for pair in pairs] # informative_pairs.extend([(pair, self.info_timeframe_1d) for pair in pairs]) if self.config['stake_currency'] in ['USDT', 'BUSD', 'USDC', 'DAI', 'TUSD', 'PAX', 'USD', 'EUR', 'GBP']: btc_info_pair = f"BTC/{self.config['stake_currency']}" else: btc_info_pair = 'BTC/USDT' informative_pairs.append((btc_info_pair, self.timeframe)) informative_pairs.append((btc_info_pair, self.inf_1h)) informative_pairs.append((btc_info_pair, self.info_timeframe_1d)) return informative_pairs def informative_1h_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: assert self.dp, 'DataProvider is required for multiple timeframes.' # Get the informative pair informative_1h = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_1h) # EMA #informative_1h['ema_15'] = ta.EMA(informative_1h, timeperiod=15) informative_1h['ema_50'] = ta.EMA(informative_1h, timeperiod=50) informative_1h['ema_100'] = ta.EMA(informative_1h, timeperiod=100) informative_1h['ema_200'] = ta.EMA(informative_1h, timeperiod=200) informative_1h['rsi'] = ta.RSI(informative_1h, timeperiod=14) #informative_1h['not_downtrend'] = ((informative_1h['close'] > informative_1h['close'].shift(2)) | (informative_1h['rsi'] > 50)) informative_1h['r_480'] = williams_r(dataframe, period=480) informative_1h['safe_pump_24'] = ((informative_1h['open'].rolling(24).max() - informative_1h['close'].rolling(24).min()) / informative_1h['close'].rolling(24).min() < self.entry_pump_threshold_1.value) | ((informative_1h['open'].rolling(24).max() - informative_1h['close'].rolling(24).min()) / self.entry_pump_pull_threshold_1.value > informative_1h['close'] - informative_1h['close'].rolling(24).min()) informative_1h['cti'] = pta.cti(informative_1h['close'], length=20) ssldown, sslup = SSLChannels_ATR(informative_1h, 14) informative_1h['ssl-dir'] = np.where(sslup > ssldown, 'up', 'down') # informative_1h['cti'] = pta.cti(informative_1h["close"], length=20) return informative_1h def info_tf_btc_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # ----------------------------------------------------------------------------------------- if not 'trend' in self.custom_trendBTC_info: self.custom_trendBTC_info['trend'] = {} if not 'not_downtrend' in self.custom_trendBTC_info['trend']: self.custom_trendBTC_info['trend']['not_downtrend'] = 0 dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) dataframe['not_downtrend'] = (dataframe['close'] > dataframe['close'].shift(2)) | (dataframe['rsi'] > 50) self.custom_trendBTC_info['trend']['not_downtrend'] = {} self.custom_trendBTC_info['trend']['not_downtrend'] = dataframe['not_downtrend'] # ----------------------------------------------------------------------------------------- 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 normal_tf_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: 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'] # nuevo # bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3) dataframe['bb_lowerband3'] = bollinger3['lower'] dataframe['bb_middleband3'] = bollinger3['mid'] dataframe['bb_upperband3'] = bollinger3['upper'] dataframe['bb_width'] = (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband'] dataframe['bb_delta'] = (dataframe['bb_lowerband'] - dataframe['bb_lowerband3']) / dataframe['bb_lowerband'] dataframe['bb_bottom_cross'] = qtpylib.crossed_below(dataframe['close'], dataframe['bb_lowerband3']).astype('int') dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs() dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs() # CCI hyperopt for val in self.entry_cci_length.range: dataframe[f'cci_length_{val}'] = ta.CCI(dataframe, val) dataframe['cci'] = ta.CCI(dataframe, 26) # CTI dataframe['cti'] = pta.cti(dataframe['close'], length=20) # RMI hyperopt for val in self.entry_rmi_length.range: dataframe[f'rmi_length_{val}'] = RMI(dataframe, length=val, mom=4) #dataframe['rmi'] = RMI(dataframe, length=8, mom=4) # SRSI hyperopt ? stoch = ta.STOCHRSI(dataframe, 15, 20, 2, 2) dataframe['srsi_fk'] = stoch['fastk'] dataframe['srsi_fd'] = stoch['fastd'] # Volume dataframe['volume_mean_4'] = dataframe['volume'].rolling(4).mean().shift(1) dataframe['volume_mean_12'] = dataframe['volume'].rolling(12).mean().shift(1) dataframe['volume_mean_24'] = dataframe['volume'].rolling(24).mean().shift(1) dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=48).mean() #cols_to_norm = ['vwmacd','signal','hist'] normalize #dataframe[cols_to_norm] = dataframe[cols_to_norm].apply(lambda x: (x-x.mean())/ x.std(), axis=0) dataframe['r_14'] = williams_r(dataframe, period=14) dataframe['r_32'] = williams_r(dataframe, period=32) dataframe['r_64'] = williams_r(dataframe, period=64) # dataframe['r_480'] = williams_r(dataframe, period=480) # EMA 200 dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12) dataframe['ema_20'] = ta.EMA(dataframe, timeperiod=20) dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26) dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) dataframe['sma_200'] = ta.SMA(dataframe, timeperiod=200) dataframe['sma_200_dec'] = dataframe['sma_200'] < dataframe['sma_200'].shift(20) # MFI dataframe['mfi'] = ta.MFI(dataframe) # RSI dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) dataframe['safe_dips_strict'] = ((dataframe['open'] - dataframe['close']) / dataframe['close'] < self.entry_dip_threshold_5.value) & ((dataframe['open'].rolling(2).max() - dataframe['close']) / dataframe['close'] < self.entry_dip_threshold_6.value) & ((dataframe['open'].rolling(12).max() - dataframe['close']) / dataframe['close'] < self.entry_dip_threshold_7.value) & ((dataframe['open'].rolling(144).max() - dataframe['close']) / dataframe['close'] < self.entry_dip_threshold_8.value) return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: tik = time.perf_counter() '\n if self.config[\'stake_currency\'] in [\'USDT\',\'BUSD\',\'USDC\',\'DAI\',\'TUSD\',\'PAX\',\'USD\',\'EUR\',\'GBP\']:\n btc_info_pair = f"BTC/{self.config[\'stake_currency\']}"\n else:\n btc_info_pair = "BTC/USDT"\n\n if metadata[\'pair\'] in btc_info_pair:\n btc_info_tf = self.dp.get_pair_dataframe(btc_info_pair, self.inf_1h)\n btc_info_tfx = self.info_tf_btc_indicators(btc_info_tf, metadata)\n dataframe = merge_informative_pair(dataframe, btc_info_tfx, self.timeframe, self.inf_1h, ffill=True)\n drop_columns = [f"{s}_{self.inf_1h}" for s in [\'date\', \'open\', \'high\', \'low\', \'close\', \'volume\']]\n dataframe.drop(columns=dataframe.columns.intersection(drop_columns), inplace=True)\n ' # The indicators for the normal (5m) timeframe dataframe = self.normal_tf_indicators(dataframe, metadata) # The indicators for the 1h informative timeframe informative_1h = self.informative_1h_indicators(dataframe, metadata) dataframe = merge_informative_pair(dataframe, informative_1h, self.timeframe, self.inf_1h, ffill=True) ssldown, sslup = SSLChannels_ATR(dataframe, 64) dataframe['ssl-up'] = sslup dataframe['ssl-down'] = ssldown dataframe['ssl-dir'] = np.where(sslup > ssldown, 'up', 'down') dataframe['rmi'] = RMI(dataframe, length=24, mom=5) tok = time.perf_counter() logger.debug(f"[{metadata['pair']}] informative_1h_indicators took: {tok - tik:0.4f} seconds.") return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] con1 = self.entry_con1_enable.value & (dataframe[f'rmi_length_{self.entry_rmi_length.value}'] < self.entry_rmi.value) & (dataframe[f'cci_length_{self.entry_cci_length.value}'] <= self.entry_cci.value) & (dataframe['srsi_fk'] < self.entry_srsi_fk.value) & ((dataframe['bb_delta'] > self.entry_bb_delta.value) & (dataframe['bb_width'] > self.entry_bb_width.value)) & (dataframe['closedelta'] > dataframe['close'] * self.entry_closedelta.value / 1000) & (dataframe['close'] < dataframe['bb_lowerband3'] * self.entry_bb_factor.value) con2 = self.entry_con2_enable.value & (dataframe['ema_200_1h'] > dataframe['ema_200_1h'].shift(12)) & (dataframe['ema_200_1h'].shift(12) > dataframe['ema_200_1h'].shift(24)) & (dataframe['ema_26'] > dataframe['ema_12']) & (dataframe['ema_26'] - dataframe['ema_12'] > dataframe['open'] * self.entry_c2_1.value) & (dataframe['ema_26'].shift() - dataframe['ema_12'].shift() > dataframe['open'] / 100) & (dataframe['close'] < dataframe['bb_lowerband'] * self.entry_c2_2.value) & (dataframe['cti_1h'] > self.entry_c2_3.value) con3 = self.entry_con3_enable.value & (dataframe['ema_26'] > dataframe['ema_12']) & (dataframe['ema_26'] - dataframe['ema_12'] > dataframe['open'] * self.entry_con3_1.value) & (dataframe['ema_26'].shift() - dataframe['ema_12'].shift() > dataframe['open'] / 100) & (dataframe['close'] < dataframe['bb_lowerband'] * self.entry_con3_2.value) & (dataframe['close'] < dataframe['ema_20'] * self.entry_con3_3.value) & (dataframe['cti'] < self.entry_con3_4.value) con4 = self.entry_con4_enable.value & (dataframe['rsi_1h'] < self.entry_rsi_1h_42.value) & (dataframe['ema_26'] > dataframe['ema_12']) & (dataframe['ema_26'] - dataframe['ema_12'] > dataframe['open'] * self.entry_macd_41.value) & (dataframe['ema_26'].shift() - dataframe['ema_12'].shift() > dataframe['open'] / 100) & (dataframe['volume'] < dataframe['volume'].shift() * self.entry_volume_drop_41.value) & (dataframe['volume_mean_slow'] > dataframe['volume_mean_slow'].shift(48) * self.entry_volume_pump_41.value) & (dataframe['volume_mean_slow'] * self.entry_volume_pump_41.value < dataframe['volume_mean_slow'].shift(48)) & (dataframe['volume'] > 0) con6 = self.entry_con6_enable.value & (dataframe['close'] > dataframe['ema_200_1h']) & (dataframe['ema_50'] > dataframe['ema_200']) & (dataframe['ema_50_1h'] > dataframe['ema_200_1h']) & ((dataframe['open'].rolling(2).max() - dataframe['close']) / dataframe['close'] < self.entry_c6_1.value) & ((dataframe['open'].rolling(12).max() - dataframe['close']) / dataframe['close'] < self.entry_c6_2.value) & dataframe['bb_lowerband'].shift().gt(0) & dataframe['bb_delta'].gt(dataframe['close'] * self.entry_c6_3.value) & dataframe['closedelta'].gt(dataframe['close'] * self.entry_c6_4.value) & dataframe['tail'].lt(dataframe['bb_delta'] * self.entry_c6_5.value) & dataframe['close'].lt(dataframe['bb_lowerband'].shift()) & dataframe['close'].le(dataframe['close'].shift()) & (dataframe['volume'] > 0) con7 = self.entry_condition_7_enable.value & (dataframe['ema_200'] > dataframe['ema_200'].shift(12) * self.entry_c7_1.value) & (dataframe['close'] < dataframe['bb_lowerband'] * self.entry_c7_2.value) & (dataframe['r_14'] < self.entry_c7_3.value) & (dataframe['r_64'] < self.entry_c7_4.value) & (dataframe['rsi_1h'] < self.entry_c7_5.value) con8 = self.entry_condition_8_enable.value & (dataframe['ema_50_1h'] > dataframe['ema_200_1h']) & (dataframe['sma_200'] > dataframe['sma_200'].shift(50)) & dataframe['safe_dips_strict'] & dataframe['safe_pump_24_1h'] & ((dataframe['close'] - dataframe['open'].rolling(36).min()) / dataframe['open'].rolling(36).min() > self.entry_min_inc_1.value) & (dataframe['rsi_1h'] > self.entry_rsi_1h_min_1.value) & (dataframe['rsi_1h'] < self.entry_rsi_1h_max_1.value) & (dataframe['rsi'] < self.entry_rsi_1.value) & (dataframe['mfi'] < self.entry_mfi_1.value) & (dataframe['volume'] > 0) con9 = self.entry_condition_9_enable.value & ((dataframe['close'] - dataframe['open'].rolling(12).min()) / dataframe['open'].rolling(12).min() > 0.032) & (dataframe['rsi'] < self.entry_c9_1.value) & (dataframe['r_14'] < self.entry_c9_2.value) & (dataframe['r_32'] < self.entry_c9_3.value) & (dataframe['mfi'] < self.entry_c9_4.value) & (dataframe['rsi_1h'] > self.entry_c9_5.value) & (dataframe['rsi_1h'] < self.entry_c9_6.value) & (dataframe['r_480_1h'] > self.entry_c9_7.value) co10 = self.entry_condition_10_enable.value & (dataframe['close'].shift(4) < dataframe['close'].shift(3)) & (dataframe['close'].shift(3) < dataframe['close'].shift(2)) & (dataframe['close'].shift(2) < dataframe['close'].shift()) & (dataframe['close'].shift(1) < dataframe['close']) & (dataframe['ema_26'] > dataframe['ema_12']) & (dataframe['close'] > dataframe['open']) & (dataframe['cci'].shift() < dataframe['cci']) & (dataframe['ssl-dir_1h'] == 'up') & (dataframe['cci'] < self.entry_c10_1.value) & (dataframe['cti'] < self.entry_c10_2.value) & (dataframe['volume'] > 0) conditions.append(con1) conditions.append(con2) conditions.append(con3) conditions.append(con4) conditions.append(con6) conditions.append(con7) conditions.append(con8) conditions.append(con9) conditions.append(co10) dataframe.loc[con1, 'enter_tag'] = ' con1 ' dataframe.loc[con2, 'enter_tag'] = ' Andalusian ' dataframe.loc[con3, 'enter_tag'] = ' con3 ' dataframe.loc[con4, 'enter_tag'] = ' con4 ' dataframe.loc[con6, 'enter_tag'] = ' con6 ' dataframe.loc[con7, 'enter_tag'] = ' con7 ' dataframe.loc[con8, 'enter_tag'] = ' con8 ' dataframe.loc[con9, 'enter_tag'] = ' con9 ' dataframe.loc[co10, 'enter_tag'] = ' trend ' if conditions: dataframe.loc[reduce(lambda x, y: x | y, conditions), 'enter_long'] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: conditions = [] conditions.append(self.exit_condition_1_enable.value & (dataframe['rsi'] > self.exit_rsi_bb_1.value) & (dataframe['close'] > dataframe['bb_upperband']) & (dataframe['close'].shift(1) > dataframe['bb_upperband'].shift(1)) & (dataframe['close'].shift(2) > dataframe['bb_upperband'].shift(2)) & (dataframe['close'].shift(3) > dataframe['bb_upperband'].shift(3)) & (dataframe['close'].shift(4) > dataframe['bb_upperband'].shift(4)) & (dataframe['close'].shift(5) > dataframe['bb_upperband'].shift(5)) & (dataframe['volume'] > 0)) conditions.append(self.exit_condition_2_enable.value & (dataframe['rsi'] > self.exit_rsi_bb_2.value) & (dataframe['close'] > dataframe['bb_upperband']) & (dataframe['close'].shift(1) > dataframe['bb_upperband'].shift(1)) & (dataframe['close'].shift(2) > dataframe['bb_upperband'].shift(2)) & (dataframe['volume'] > 0)) conditions.append(self.exit_condition_3_enable.value & (dataframe['rsi'] > self.exit_rsi_main_3.value) & (dataframe['volume'] > 0)) conditions.append(self.exit_condition_4_enable.value & (dataframe['rsi'] > self.exit_dual_rsi_rsi_4.value) & (dataframe['rsi_1h'] > self.exit_dual_rsi_rsi_1h_4.value) & (dataframe['volume'] > 0)) conditions.append(self.exit_condition_6_enable.value & (dataframe['close'] < dataframe['ema_200']) & (dataframe['close'] > dataframe['ema_50']) & (dataframe['rsi'] > self.exit_rsi_under_6.value) & (dataframe['volume'] > 0)) conditions.append(self.exit_condition_7_enable.value & (dataframe['rsi_1h'] > self.exit_rsi_1h_7.value) & qtpylib.crossed_below(dataframe['ema_12'], dataframe['ema_26']) & (dataframe['volume'] > 0)) "\n for i in self.ma_types:\n conditions.append(\n (\n (dataframe['close'] > dataframe[f'{i}_offset_exit']) &\n (dataframe['volume'] > 0)\n )\n )\n " if conditions: dataframe.loc[reduce(lambda x, y: x | y, conditions), 'exit_long'] = 1 return dataframe