commit 7c239227d84ede36fded70e979997a0dbd971d2a Author: Jérôme Delacotte Date: Thu Mar 6 11:01:43 2025 +0100 first commit diff --git a/BB_RTR_dca.py b/BB_RTR_dca.py new file mode 100644 index 0000000..594591e --- /dev/null +++ b/BB_RTR_dca.py @@ -0,0 +1,1049 @@ +# --- Do not remove these libs --- +import freqtrade.vendor.qtpylib.indicators as qtpylib +import logging +import math +import numpy as np +import talib.abstract as ta +import pandas_ta as pta + +from freqtrade.persistence import Trade +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame, Series, DatetimeIndex, merge +from datetime import datetime, timedelta +from freqtrade.strategy import merge_informative_pair, CategoricalParameter, DecimalParameter, IntParameter, stoploss_from_open +from functools import reduce +from technical.indicators import RMI, zema + +logger = logging.getLogger(__name__) + +# -------------------------------- +def ha_typical_price(bars): + res = (bars['ha_high'] + bars['ha_low'] + bars['ha_close']) / 3. + return Series(index=bars.index, data=res) + +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['low'] * 100 + return emadif + +# Volume Weighted Moving Average +def vwma(dataframe: DataFrame, length: int = 10): + """Indicator: Volume Weighted Moving Average (VWMA)""" + # Calculate Result + pv = dataframe['close'] * dataframe['volume'] + vwma = Series(ta.SMA(pv, timeperiod=length) / ta.SMA(dataframe['volume'], timeperiod=length)) + return vwma + +# Modified Elder Ray Index +def moderi(dataframe: DataFrame, len_slow_ma: int = 32) -> Series: + slow_ma = Series(ta.EMA(vwma(dataframe, length=len_slow_ma), timeperiod=len_slow_ma)) + return slow_ma >= slow_ma.shift(1) # we just need true & false for ERI trend + +# 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 + +# VWAP bands +def VWAPB(dataframe, window_size=20, num_of_std=1): + df = dataframe.copy() + df['vwap'] = qtpylib.rolling_vwap(df,window=window_size) + rolling_std = df['vwap'].rolling(window=window_size).std() + df['vwap_low'] = df['vwap'] - (rolling_std * num_of_std) + df['vwap_high'] = df['vwap'] + (rolling_std * num_of_std) + return df['vwap_low'], df['vwap'], df['vwap_high'] + +def top_percent_change(dataframe: DataFrame, length: int) -> float: + """ + Percentage change of the current close from the range maximum Open price + + :param dataframe: DataFrame The original OHLC dataframe + :param length: int The length to look back + """ + if length == 0: + return (dataframe['open'] - dataframe['close']) / dataframe['close'] + else: + return (dataframe['open'].rolling(length).max() - dataframe['close']) / dataframe['close'] + +class BB_RTR(IStrategy): + ''' + BB_RPB_TSL_RNG with conditions from true_lambo and dca + + (1) Improve 7_33 x_201 + ''' + + ########################################################################## + + # Hyperopt result area + + # buy space + buy_params = { + ## + "buy_pump_1_factor": 1.096, + "buy_pump_2_factor": 1.125, + ## + "buy_threshold": 0.003, + "buy_bb_factor": 0.999, + "buy_bb_delta": 0.025, + "buy_bb_width": 0.095, + ## + "buy_cci": -116, + "buy_cci_length": 25, + "buy_rmi": 49, + "buy_rmi_length": 17, + "buy_srsi_fk": 32, + ## + "buy_closedelta": 12.148, + "buy_ema_diff": 0.022, + ## + "buy_adx": 20, + "buy_fastd": 20, + "buy_fastk": 22, + "buy_ema_cofi": 0.98, + "buy_ewo_high": 4.179, + ## + "buy_ema_high": 0.968, + "buy_ema_low": 0.935, + "buy_ewo": -5.001, + "buy_rsi": 23, + "buy_rsi_fast": 44, + ## + "buy_ema_high_2": 1.087, + "buy_ema_low_2": 0.970, + ## + "buy_no_trend_cti_4": -0.597, + "buy_no_trend_factor_4": 0.024, + "buy_no_trend_r14_4": -44.062, + ## + "buy_V_bb_width_5": 0.063, + "buy_V_cti_5": -0.086, + "buy_V_mfi_5": 38.158, + "buy_V_r14_5": -41.493, + ## + "buy_vwap_closedelta": 26.941, + "buy_vwap_closedelta_2": 20.099, + "buy_vwap_closedelta_3": 27.654, + ## + "buy_vwap_cti": -0.087, + "buy_vwap_cti_2": -0.748, + "buy_vwap_cti_3": -0.2, + ## + "buy_vwap_width": 1.308, + "buy_vwap_width_2": 3.212, + "buy_vwap_width_3": 0.49, + ## + } + + # sell space + sell_params = { + "pHSL": -0.998, # Disable ? + "pPF_1": 0.019, + "pPF_2": 0.065, + "pSL_1": 0.019, + "pSL_2": 0.062, + ## + "high_offset_2": 0.997, + ## + "sell_cti_r_cti": 0.844, + "sell_cti_r_r": -19.99, + ## + "sell_u_e_2_cmf": -0.0, + "sell_u_e_2_ema_close_delta": 0.016, + "sell_u_e_2_rsi": 10, + ## + "sell_deadfish_profit": -0.063, + "sell_deadfish_bb_factor": 0.954, + "sell_deadfish_bb_width": 0.043, + "sell_deadfish_volume_factor": 2.37, + ## + "sell_cmf_div_1_cmf": 0.442, + "sell_cmf_div_1_profit": 0.02, + } + + # ROI + minimal_roi = { + "0": 0.10, + } + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + # Disabled + stoploss = -0.998 + + # Options + use_custom_stoploss = True + use_sell_signal = True + process_only_new_candles = True + startup_candle_count: int = 400 + + ############################################################################ + + ## Buy params + + is_optimize_dip = False + buy_rmi = IntParameter(30, 50, default=35, optimize= is_optimize_dip) + buy_cci = IntParameter(-135, -90, default=-133, optimize= is_optimize_dip) + buy_srsi_fk = IntParameter(30, 50, default=25, optimize= is_optimize_dip) + buy_cci_length = IntParameter(25, 45, default=25, optimize = is_optimize_dip) + buy_rmi_length = IntParameter(8, 20, default=8, optimize = is_optimize_dip) + + is_optimize_break = False + buy_bb_width = DecimalParameter(0.05, 0.2, default=0.15, optimize = is_optimize_break) + buy_bb_delta = DecimalParameter(0.025, 0.08, default=0.04, optimize = is_optimize_break) + + is_optimize_local_dip = False + buy_ema_diff = DecimalParameter(0.022, 0.027, default=0.025, optimize = is_optimize_local_dip) + buy_bb_factor = DecimalParameter(0.990, 0.999, default=0.995, optimize = False) + buy_closedelta = DecimalParameter(12.0, 18.0, default=15.0, optimize = is_optimize_local_dip) + + is_optimize_ewo = False + buy_rsi_fast = IntParameter(35, 50, default=45, optimize = False) + buy_rsi = IntParameter(15, 30, default=35, optimize = False) + buy_ewo = DecimalParameter(-6.0, 5, default=-5.585, optimize = is_optimize_ewo) + buy_ema_low = DecimalParameter(0.9, 0.99, default=0.942 , optimize = is_optimize_ewo) + buy_ema_high = DecimalParameter(0.95, 1.2, default=1.084 , optimize = is_optimize_ewo) + + is_optimize_ewo_2 = False + buy_ema_low_2 = DecimalParameter(0.96, 0.978, default=0.96 , optimize = is_optimize_ewo_2) + buy_ema_high_2 = DecimalParameter(1.05, 1.2, default=1.09 , optimize = is_optimize_ewo_2) + + is_optimize_cofi = False + buy_ema_cofi = DecimalParameter(0.96, 0.98, default=0.97 , optimize = is_optimize_cofi) + buy_fastk = IntParameter(20, 30, default=20, optimize = is_optimize_cofi) + buy_fastd = IntParameter(20, 30, default=20, optimize = is_optimize_cofi) + buy_adx = IntParameter(20, 30, default=30, optimize = is_optimize_cofi) + buy_ewo_high = DecimalParameter(2, 12, default=3.553, optimize = is_optimize_cofi) + + is_optimize_vwap = False + buy_vwap_width = DecimalParameter(0.05, 10.0, default=0.80 , optimize = is_optimize_vwap) + buy_vwap_closedelta = DecimalParameter(10.0, 30.0, default=15.0, optimize = is_optimize_vwap) + buy_vwap_cti = DecimalParameter(-0.9, -0.0, default=-0.6 , optimize = is_optimize_vwap) + + is_optimize_vwap_2 = False + buy_vwap_width_2 = DecimalParameter(0.05, 10.0, default=0.80 , optimize = is_optimize_vwap_2) + buy_vwap_closedelta_2 = DecimalParameter(10.0, 30.0, default=15.0, optimize = is_optimize_vwap_2) + buy_vwap_cti_2 = DecimalParameter(-0.9, -0.0, default=-0.6 , optimize = is_optimize_vwap_2) + + is_optimize_vwap_3 = True + buy_vwap_width_3 = DecimalParameter(0.05, 10.0, default=0.80 , optimize = is_optimize_vwap_3) + buy_vwap_closedelta_3 = DecimalParameter(10.0, 30.0, default=15.0, optimize = is_optimize_vwap_3) + buy_vwap_cti_3 = DecimalParameter(-0.9, -0.0, default=-0.6 , optimize = is_optimize_vwap_3) + + is_optimize_no_trend_4 = False + buy_no_trend_factor_4 = DecimalParameter(0.01, 0.05, default=0.030 , optimize = is_optimize_no_trend_4) + buy_no_trend_cti_4 = DecimalParameter(-0.9, -0.0, default=-0.6 , optimize = is_optimize_no_trend_4) + buy_no_trend_r14_4 = DecimalParameter(-100, -44, default=-80 , optimize = is_optimize_no_trend_4) + + is_optimize_V_5 = False + buy_V_bb_width_5 = DecimalParameter(0.01, 0.1, default=0.01 , optimize = is_optimize_V_5) + buy_V_cti_5 = DecimalParameter(-0.95, -0.0, default=-0.6 , optimize = is_optimize_V_5) + buy_V_r14_5 = DecimalParameter(-100, 0, default=-60 , optimize = is_optimize_V_5) + buy_V_mfi_5 = DecimalParameter(10, 40, default=30 , optimize = is_optimize_V_5) + + is_optimize_gumbo = False + buy_gumbo_ema = DecimalParameter(0.9, 1.2, default=0.97 , optimize = is_optimize_gumbo) + buy_gumbo_ewo_low = DecimalParameter(-12.0, 5, default=-5.585, optimize = is_optimize_gumbo) + buy_gumbo_cti = DecimalParameter(-0.9, -0.0, default=-0.5 , optimize = is_optimize_gumbo) + buy_gumbo_r14 = DecimalParameter(-100, -44, default=-60 , optimize = is_optimize_gumbo) + + is_optimize_gumbo_protection = False + buy_gumbo_tpct_0 = DecimalParameter(0.0, 0.25, default=0.131, decimals=2, optimize = is_optimize_gumbo_protection) + buy_gumbo_tpct_3 = DecimalParameter(0.0, 0.25, default=0.131, decimals=2, optimize = is_optimize_gumbo_protection) + buy_gumbo_tpct_9 = DecimalParameter(0.0, 0.25, default=0.131, decimals=2, optimize = is_optimize_gumbo_protection) + + # Buy params toggle + buy_is_dip_enabled = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True) + buy_is_break_enabled = CategoricalParameter([True, False], default=True, space='buy', optimize=False, load=True) + + is_optimize_pump_1 = False + buy_pump_1_factor = DecimalParameter(1.0, 1.25, default= 1.1 , optimize = is_optimize_pump_1) + + is_optimize_pump_2 = False + buy_pump_2_factor = DecimalParameter(1.0, 1.20, default= 1.1 , optimize = is_optimize_pump_2) + + ## Sell params + is_optimize_sell_offset = False + high_offset_2 = DecimalParameter(0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=is_optimize_sell_offset) + + is_optimize_sell_u_e_2 = False + sell_u_e_2_cmf = DecimalParameter(-0.4, 0.0, default=0.0, optimize = is_optimize_sell_u_e_2) + sell_u_e_2_ema_close_delta = DecimalParameter(0.001, 0.027, default= 0.024, optimize = is_optimize_sell_u_e_2) + sell_u_e_2_rsi = IntParameter(10, 30, default=24, optimize = is_optimize_sell_u_e_2) + + is_optimize_deadfish = False + sell_deadfish_bb_width = DecimalParameter(0.010, 0.025, default=0.05 , optimize = is_optimize_deadfish) + sell_deadfish_profit = DecimalParameter(-0.10, -0.05, default=-0.05 , optimize = is_optimize_deadfish) + sell_deadfish_bb_factor = DecimalParameter(0.90, 1.20, default=1.0 , optimize = is_optimize_deadfish) + sell_deadfish_volume_factor = DecimalParameter(1.5, 3, default=1.5 , optimize = is_optimize_deadfish) + + is_optimize_cti_r = False + sell_cti_r_cti = DecimalParameter(0.55, 1, default=0.5 , optimize = is_optimize_cti_r) + sell_cti_r_r = DecimalParameter(-15, 0, default=-20 , optimize = is_optimize_cti_r) + + is_optimize_cmf_div = True + sell_cmf_div_1_profit = DecimalParameter(0.005, 0.02, default=0.005 , optimize = is_optimize_cmf_div) + sell_cmf_div_1_cmf = DecimalParameter(0.0, 0.5, default=0.0 , optimize = is_optimize_cmf_div) + sell_cmf_div_2_profit = DecimalParameter(0.005, 0.02, default=0.005 , optimize = is_optimize_cmf_div) + sell_cmf_div_2_cmf = DecimalParameter(0.0, 0.5, default=0.0 , optimize = is_optimize_cmf_div) + + ## Trailing params + + # hard stoploss profit + is_optimize_trailing = False + pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', load=True, optimize=is_optimize_trailing) + # profit threshold 1, trigger point, SL_1 is used + pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', load=True, optimize=is_optimize_trailing) + pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', load=True, optimize=is_optimize_trailing) + + # profit threshold 2, SL_2 is used + pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', load=True, optimize=is_optimize_trailing) + pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', load=True, optimize=is_optimize_trailing) + + ############################################################################ + + def informative_pairs(self): + + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + ############################################################################ + + ## Custom Trailing stoploss ( credit to Perkmeister for this custom stoploss to help the strategy ride a green candle ) + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + # hard stoploss profit + HSL = self.pHSL.value + PF_1 = self.pPF_1.value + SL_1 = self.pSL_1.value + PF_2 = self.pPF_2.value + SL_2 = self.pSL_2.value + + # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + + if (current_profit > PF_2): + sl_profit = SL_2 + (current_profit - PF_2) + elif (current_profit > PF_1): + sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + else: + sl_profit = HSL + + # Only for hyperopt invalid return + if (sl_profit >= current_profit): + return -0.99 + + return stoploss_from_open(sl_profit, current_profit) + + def custom_sell(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] + previous_candle_1 = dataframe.iloc[-2] + previous_candle_2 = dataframe.iloc[-3] + + max_profit = ((trade.max_rate - trade.open_rate) / trade.open_rate) + max_loss = ((trade.open_rate - trade.min_rate) / trade.min_rate) + + buy_tag = 'empty' + if hasattr(trade, 'buy_tag') and trade.buy_tag is not None: + buy_tag = trade.buy_tag + buy_tags = buy_tag.split() + + # sell cti_r + if 0.012 > current_profit >= 0.0 : + if (last_candle['cti'] > self.sell_cti_r_cti.value) and (last_candle['r_14'] > self.sell_cti_r_r.value): + return f"sell_profit_cti_r_0_1( {buy_tag})" + + # main sell + if current_profit > 0.02: + if (last_candle['momdiv_sell_1h'] == True): + return f"signal_profit_q_momdiv_1h( {buy_tag})" + if (last_candle['momdiv_sell'] == True): + return f"signal_profit_q_momdiv( {buy_tag})" + if (last_candle['momdiv_coh'] == True): + return f"signal_profit_q_momdiv_coh( {buy_tag})" + if (last_candle['cti_40_1h'] > 0.844) and (last_candle['r_84_1h'] > -20): + return f"signal_profit_cti_r( {buy_tag})" + + # sell quick + if (0.06 > current_profit > 0.02) and (last_candle['rsi'] > 80.0): + return f"signal_profit_q_1( {buy_tag})" + + if (0.06 > current_profit > 0.02) and (last_candle['cti'] > 0.95): + return f"signal_profit_q_2( {buy_tag})" + + # sell recover + if (max_loss > 0.06) and (0.05 > current_profit > 0.01) and (last_candle['rsi'] < 46): + return f"signal_profit_r_1( {buy_tag})" + + # sell offset + if ( + (current_profit > 0.005) + and (last_candle['close'] > last_candle['sma_9']) + and (last_candle['close'] > last_candle['ema_24'] * self.high_offset_2.value) + and (last_candle['rsi'] > 50) + and (last_candle['rsi_fast'] > last_candle['rsi_slow']) + ): + return f"sell_offset( {buy_tag})" + + # sell vwap dump + if ( + (current_profit > 0.005) + and (last_candle['ema_vwap_diff_50'] > 0.0) + and (last_candle['ema_vwap_diff_50'] < 0.012) + ): + return f"sell_vwap_dump( {buy_tag})" + + # sell cmf div + if ( + (current_profit > 0.005) + and (last_candle['cmf'] > 0) + and (last_candle['cmf_div_slow'] == 1) + ): + return f"sell_cmf_div( {buy_tag})" + + # stoploss + if ( + (current_profit < -0.025) + and (last_candle['close'] < last_candle['ema_200']) + and (last_candle['cmf'] < self.sell_u_e_2_cmf.value) + and (((last_candle['ema_200'] - last_candle['close']) / last_candle['close']) < self.sell_u_e_2_ema_close_delta.value) + and last_candle['rsi'] > previous_candle_1['rsi'] + and (last_candle['rsi'] > (last_candle['rsi_1h'] + self.sell_u_e_2_rsi.value)) + ): + return f"sell_stoploss_u_e_2( {buy_tag})" + + # stoploss - deadfish + if ( (current_profit < self.sell_deadfish_profit.value) + and (last_candle['close'] < last_candle['ema_200']) + and (last_candle['bb_width'] < self.sell_deadfish_bb_width.value) + and (last_candle['close'] > last_candle['bb_middleband2'] * self.sell_deadfish_bb_factor.value) + and (last_candle['volume_mean_12'] < last_candle['volume_mean_24'] * self.sell_deadfish_volume_factor.value) + and (last_candle['cmf'] < 0.0) + ): + return f"sell_stoploss_deadfish( {buy_tag})" + + ############################################################################ + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + assert self.dp, "DataProvider is required for multiple timeframes." + + # Bollinger bands (hyperopt hard to implement) + bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) + dataframe['bb_lowerband2'] = bollinger2['lower'] + dataframe['bb_middleband2'] = bollinger2['mid'] + dataframe['bb_upperband2'] = bollinger2['upper'] + + 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'] + + ### Other checks + + dataframe['bb_width'] = ((dataframe['bb_upperband2'] - dataframe['bb_lowerband2']) / dataframe['bb_middleband2']) + dataframe['bb_delta'] = ((dataframe['bb_lowerband2'] - dataframe['bb_lowerband3']) / dataframe['bb_lowerband2']) + dataframe['bb_bottom_cross'] = qtpylib.crossed_below(dataframe['close'], dataframe['bb_lowerband3']).astype('int') + + # CCI hyperopt + for val in self.buy_cci_length.range: + dataframe[f'cci_length_{val}'] = ta.CCI(dataframe, val) + + dataframe['cci'] = ta.CCI(dataframe, 26) + dataframe['cci_long'] = ta.CCI(dataframe, 170) + + # RMI hyperopt + for val in self.buy_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'] + + # BinH + dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs() + + # SMA + dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15) + dataframe['sma_30'] = ta.SMA(dataframe, timeperiod=30) + + # CTI + dataframe['cti'] = pta.cti(dataframe["close"], length=20) + + # CMF + dataframe['cmf'] = chaikin_money_flow(dataframe, 20) + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # EMA + dataframe['ema_8'] = ta.EMA(dataframe, timeperiod=8) + dataframe['ema_12'] = ta.EMA(dataframe, timeperiod=12) + dataframe['ema_13'] = ta.EMA(dataframe, timeperiod=13) + dataframe['ema_16'] = ta.EMA(dataframe, timeperiod=16) + dataframe['ema_24'] = ta.EMA(dataframe, timeperiod=24) + dataframe['ema_26'] = ta.EMA(dataframe, timeperiod=26) + dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) + + # SMA + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + dataframe['sma_15'] = ta.SMA(dataframe, timeperiod=15) + dataframe['sma_21'] = ta.SMA(dataframe, timeperiod=21) + + # VWAP + vwap_low, vwap, vwap_high = VWAPB(dataframe, 20, 1) + dataframe['vwap_upperband'] = vwap_high + dataframe['vwap_middleband'] = vwap + dataframe['vwap_lowerband'] = vwap_low + dataframe['vwap_width'] = ( (dataframe['vwap_upperband'] - dataframe['vwap_lowerband']) / dataframe['vwap_middleband'] ) * 100 + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + dataframe['rsi_84'] = ta.RSI(dataframe, timeperiod=84) + dataframe['rsi_112'] = ta.RSI(dataframe, timeperiod=112) + + # Elliot + dataframe['EWO'] = EWO(dataframe, 50, 200) + + # Cofi + stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + dataframe['adx'] = ta.ADX(dataframe) + + # Heiken Ashi + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['ha_open'] = heikinashi['open'] + dataframe['ha_close'] = heikinashi['close'] + dataframe['ha_high'] = heikinashi['high'] + dataframe['ha_low'] = heikinashi['low'] + + ## BB 40 + bollinger2_40 = qtpylib.bollinger_bands(ha_typical_price(dataframe), window=40, stds=2) + dataframe['bb_lowerband2_40'] = bollinger2_40['lower'] + dataframe['bb_middleband2_40'] = bollinger2_40['mid'] + dataframe['bb_upperband2_40'] = bollinger2_40['upper'] + + # ClucHA + dataframe['bb_delta_cluc'] = (dataframe['bb_middleband2_40'] - dataframe['bb_lowerband2_40']).abs() + dataframe['ha_closedelta'] = (dataframe['ha_close'] - dataframe['ha_close'].shift()).abs() + dataframe['tail'] = (dataframe['ha_close'] - dataframe['ha_low']).abs() + dataframe['ema_slow'] = ta.EMA(dataframe['ha_close'], timeperiod=50) + dataframe['rocr'] = ta.ROCR(dataframe['ha_close'], timeperiod=28) + + # Williams %R + dataframe['r_14'] = williams_r(dataframe, period=14) + + # 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) + + # Diff + dataframe['ema_vwap_diff_50'] = ( ( dataframe['ema_50'] - dataframe['vwap_lowerband'] ) / dataframe['ema_50'] ) + + # Dip Protection + dataframe['tpct_change_1'] = top_percent_change(dataframe, 1) + dataframe['tpct_change_2'] = top_percent_change(dataframe, 2) + dataframe['tpct_change_4'] = top_percent_change(dataframe, 4) + + # MOMDIV + mom = momdiv(dataframe) + dataframe['momdiv_buy'] = mom['momdiv_buy'] + dataframe['momdiv_sell'] = mom['momdiv_sell'] + dataframe['momdiv_coh'] = mom['momdiv_coh'] + dataframe['momdiv_col'] = mom['momdiv_col'] + + # cmf div + dataframe['cmf_div_fast'] = ( ( dataframe['cmf'].rolling(12).max() >= dataframe['cmf'] * 1.025 ) ) + dataframe['cmf_div_slow'] = ( ( dataframe['cmf'].rolling(20).max() >= dataframe['cmf'] * 1.025 ) ) + + # Modified Elder Ray Index + dataframe['moderi_96'] = moderi(dataframe, 96) + + ############################################################################ + + # 1h tf + inf_tf = '1h' + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=inf_tf) + + # Heikin Ashi + inf_heikinashi = qtpylib.heikinashi(informative) + informative['ha_close'] = inf_heikinashi['close'] + informative['rocr'] = ta.ROCR(informative['ha_close'], timeperiod=168) + + # Bollinger bands + bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband2'] = bollinger2['lower'] + informative['bb_middleband2'] = bollinger2['mid'] + informative['bb_upperband2'] = bollinger2['upper'] + informative['bb_width'] = ((informative['bb_upperband2'] - informative['bb_lowerband2']) / informative['bb_middleband2']) + + # RSI + informative['rsi'] = ta.RSI(informative, timeperiod=14) + informative['rsi_28'] = ta.RSI(informative, timeperiod=28) + informative['rsi_42'] = ta.RSI(informative, timeperiod=42) + + # EMA + informative['ema_20'] = ta.EMA(informative, timeperiod=20) + informative['ema_26'] = ta.EMA(informative, timeperiod=26) + informative['ema_200'] = ta.EMA(informative, timeperiod=200) + + # Williams %R + informative['r_84'] = williams_r(informative, period=84) + + # CTI + informative['cti_40'] = pta.cti(informative["close"], length=40) + + # MOMDIV + mom = momdiv(informative) + informative['momdiv_buy'] = mom['momdiv_buy'] + informative['momdiv_sell'] = mom['momdiv_sell'] + informative['momdiv_coh'] = mom['momdiv_coh'] + informative['momdiv_col'] = mom['momdiv_col'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, inf_tf, ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = [] + dataframe.loc[:, 'buy_tag'] = '' + + ############################################################################ + + # Utils + + is_pump_1 = ( (dataframe['close'].rolling(48).max() >= (dataframe['close'] * self.buy_pump_1_factor.value )) ) + + pump_protection_strict = ( + (dataframe['close'].rolling(48).max() >= (dataframe['close'] * 1.125 )) & + ( (dataframe['close'].rolling(288).max() >= (dataframe['close'] * 1.225 )) ) + ) + + pump_protection_loose = ( + (dataframe['close'].rolling(48).max() >= (dataframe['close'] * 1.05 )) & + ( (dataframe['close'].rolling(288).max() >= (dataframe['close'] * 1.125 )) ) + ) + + is_pump_4 = ( + (dataframe['close'].rolling(48).max() >= (dataframe['close'] * 1.075 )) & + ( (dataframe['close'].rolling(288).max() >= (dataframe['close'] * 1.17 )) ) + ) + + is_crash_1 = ( + (dataframe['tpct_change_1'] < 0.08) & + (dataframe['tpct_change_2'] < 0.08) + ) + + is_crash_2 = ( + (dataframe['tpct_change_1'] < 0.06) & + (dataframe['tpct_change_2'] < 0.06) + ) + + is_crash_3 = ( + (dataframe['tpct_change_1'] < 0.055) & + (dataframe['tpct_change_2'] < 0.055) + ) + + rsi_check = ( + (dataframe['rsi_84'] < 60) & + (dataframe['rsi_112'] < 60) + ) + + min_EWO_check = ( (dataframe['EWO'] > -5.585) ) + + max_EWO_check = ( (dataframe['EWO'] < 10.6) ) + + ############################################################################ + + if self.buy_is_dip_enabled.value: + + is_dip = ( + (dataframe[f'rmi_length_{self.buy_rmi_length.value}'] < self.buy_rmi.value) & + (dataframe[f'cci_length_{self.buy_cci_length.value}'] <= self.buy_cci.value) & + (dataframe['srsi_fk'] < self.buy_srsi_fk.value) + ) + + if self.buy_is_break_enabled.value: + + is_break = ( + + ( (dataframe['bb_delta'] > self.buy_bb_delta.value) #"buy_bb_delta": 0.025 0.036 + & #"buy_bb_width": 0.095 0.133 + (dataframe['bb_width'] > self.buy_bb_width.value) + ) + & + (dataframe['closedelta'] > dataframe['close'] * self.buy_closedelta.value / 1000 ) & # from BinH + (dataframe['close'] < dataframe['bb_lowerband3'] * self.buy_bb_factor.value) & + (is_crash_1) + ) + + is_local_uptrend = ( # from NFI next gen + + (dataframe['ema_26'] > dataframe['ema_12']) & + (dataframe['ema_26'] - dataframe['ema_12'] > dataframe['open'] * self.buy_ema_diff.value) & + (dataframe['ema_26'].shift() - dataframe['ema_12'].shift() > dataframe['open'] / 100) & + (dataframe['close'] < dataframe['bb_lowerband2'] * self.buy_bb_factor.value) & + (dataframe['closedelta'] > dataframe['close'] * self.buy_closedelta.value / 1000 ) & + (dataframe['EWO'] < 4) & + (dataframe['EWO'] > -2.5) + ) + + is_ewo = ( # from SMA offset + (dataframe['rsi_fast'] < self.buy_rsi_fast.value) & + (dataframe['close'] < dataframe['ema_8'] * self.buy_ema_low.value) & + (dataframe['EWO'] > self.buy_ewo.value) & + (dataframe['close'] < dataframe['ema_16'] * self.buy_ema_high.value) & + (dataframe['rsi'] < self.buy_rsi.value) + ) + + is_ewo_2 = ( + (dataframe['rsi_fast'] < self.buy_rsi_fast.value) & + (dataframe['close'] < dataframe['ema_8'] * self.buy_ema_low_2.value) & + (dataframe['EWO'] > self.buy_ewo_high.value) & + (dataframe['close'] < dataframe['ema_16'] * self.buy_ema_high_2.value) & + (dataframe['rsi'] < self.buy_rsi.value) & + (rsi_check) + ) + + is_vwap = ( + (dataframe['close'] < dataframe['vwap_lowerband']) & + (dataframe['vwap_width'] > self.buy_vwap_width.value) & + (dataframe['closedelta'] > dataframe['close'] * self.buy_vwap_closedelta.value / 1000 ) & + (dataframe['cti'] < self.buy_vwap_cti.value) & + (dataframe['EWO'] > 8) & + (rsi_check) & + (pump_protection_strict) + ) + + is_vwap_2 = ( + (dataframe['close'] < dataframe['vwap_lowerband']) & + (dataframe['vwap_width'] > self.buy_vwap_width_2.value) & + (dataframe['closedelta'] > dataframe['close'] * self.buy_vwap_closedelta_2.value / 1000 ) & + (dataframe['cti'] < self.buy_vwap_cti_2.value) & + (dataframe['EWO'] > 4) & + (dataframe['EWO'] < 8) & + (rsi_check) & + (pump_protection_strict) + ) + + is_vwap_3 = ( + (dataframe['close'] < dataframe['vwap_lowerband']) & + (dataframe['vwap_width'] > self.buy_vwap_width_3.value) & + (dataframe['closedelta'] > dataframe['close'] * self.buy_vwap_closedelta_3.value / 1000 ) & + (dataframe['cti'] < self.buy_vwap_cti_3.value) & + (dataframe['EWO'] < 4) & + (dataframe['EWO'] > -2.5) & + (dataframe['rsi_28_1h'] < 46) & + (rsi_check) + & + (pump_protection_loose) + ) + + is_VWAP = ( + (dataframe['close'] < dataframe['vwap_lowerband']) & + (dataframe['tpct_change_1'] > 0.04) & + (dataframe['cti'] < -0.8) & + (dataframe['rsi'] < 35) & + (rsi_check) + ) + + is_no_trend_4 = ( + (dataframe['ema_26'] > dataframe['ema_12']) & + (dataframe['ema_26'] - dataframe['ema_12'] > dataframe['open'] * self.buy_no_trend_factor_4.value) & + (dataframe['ema_26'].shift() - dataframe['ema_12'].shift() > dataframe['open'] / 100) & + (dataframe['cti'] < self.buy_no_trend_cti_4.value) & + (dataframe['r_14'] < self.buy_no_trend_r14_4.value) & + (dataframe['EWO'] < -4) & + (min_EWO_check) & + (rsi_check) + ) + + is_V_5 = ( + (dataframe['bb_width'] > self.buy_V_bb_width_5.value) & + (dataframe['cti'] < self.buy_V_cti_5.value) & + (dataframe['r_14'] < self.buy_V_r14_5.value) & + (dataframe['mfi'] < self.buy_V_mfi_5.value) & + # Really Bear, don't engage until dump over + (dataframe['ema_vwap_diff_50'] > 0.215) & + (dataframe['EWO'] < -10) & + (rsi_check) + ) + + is_insta = ( + (dataframe['bb_width_1h'] > 0.13) & + (dataframe['r_14'] < -50) & + (dataframe['r_84_1h'] < -69) & + (dataframe['cti'] < -0.84) & + (dataframe['cti_40_1h'] < -0.73) + & + ( (dataframe['close'].rolling(48).max() >= (dataframe['close'] * 1.1 )) ) + ) + + # NFI quick mode + + is_nfi_32 = ( + (dataframe['rsi_slow'] < dataframe['rsi_slow'].shift(1)) & + (dataframe['rsi_fast'] < 46) & + (dataframe['rsi'] > 19) & + (dataframe['close'] < dataframe['sma_15'] * 0.942) & + (dataframe['cti'] < -0.86) + ) + + is_nfi_33 = ( + (dataframe['close'] < (dataframe['ema_13'] * 0.978)) & + (dataframe['EWO'] > 8) & + (dataframe['cti'] < -0.88) & + (dataframe['rsi'] < 32) & + (dataframe['r_14'] < -98.0) & + (dataframe['volume'] < (dataframe['volume_mean_4'] * 2.5)) + ) + + is_nfix_39 = ( + (dataframe['ema_200'] > (dataframe['ema_200'].shift(12) * 1.01)) & + (dataframe['ema_200'] > (dataframe['ema_200'].shift(48) * 1.07)) & + (dataframe['bb_lowerband2_40'].shift().gt(0)) & + (dataframe['bb_delta_cluc'].gt(dataframe['close'] * 0.056)) & + (dataframe['closedelta'].gt(dataframe['close'] * 0.01)) & + (dataframe['tail'].lt(dataframe['bb_delta_cluc'] * 0.5)) & + (dataframe['close'].lt(dataframe['bb_lowerband2_40'].shift())) & + (dataframe['close'].le(dataframe['close'].shift())) & + (dataframe['close'] > dataframe['ema_50'] * 0.912) + ) + + is_nfix_201 = ( + (dataframe['rsi_slow'] < dataframe['rsi_slow'].shift()) & + (dataframe['rsi_fast'] < 30.0) & + (dataframe['ema_20_1h'] > dataframe['ema_26_1h']) & + (dataframe['close'] < dataframe['sma_15'] * 0.953) & + (dataframe['cti'] < -0.82) & + (dataframe['cci'] < -210.0) + & + (is_pump_1) & + (rsi_check) + ) + + is_nfi7_33 = ( + (dataframe['moderi_96']) & + (dataframe['cti'] < -0.88) & + (dataframe['close'] < (dataframe['ema_13'] * 0.988)) & + (dataframe['EWO'] > 6.4) & + (dataframe['rsi'] < 32.0) & + (dataframe['volume'] < (dataframe['volume_mean_4'] * 2.0)) + & + (pump_protection_loose) & + (rsi_check) + ) + + is_nfi_sma_3 = ( + (dataframe['bb_lowerband2_40'].shift() > 0) & + (dataframe['bb_delta_cluc'] > dataframe['close'] * 0.059) & + (dataframe['ha_closedelta'] > dataframe['close'] * 0.023) & + (dataframe['tail'] < dataframe['bb_delta_cluc'] * 0.418) & + (dataframe['close'] < dataframe['bb_lowerband2_40'].shift()) & + (dataframe['close'] < dataframe['close'].shift()) + ) + + is_BB_checked = is_dip & is_break + + ## condition append + conditions.append(is_BB_checked) # P + dataframe.loc[is_BB_checked, 'buy_tag'] += 'bb ' + + conditions.append(is_local_uptrend) + dataframe.loc[is_local_uptrend, 'buy_tag'] += 'local_uptrend ' + + conditions.append(is_ewo) + dataframe.loc[is_ewo, 'buy_tag'] += 'ewo ' + + conditions.append(is_ewo_2) + dataframe.loc[is_ewo_2, 'buy_tag'] += 'ewo2 ' + + conditions.append(is_no_trend_4) + dataframe.loc[is_no_trend_4, 'buy_tag'] += 'no_trend_4 ' + + conditions.append(is_vwap) + dataframe.loc[is_vwap, 'buy_tag'] += 'vwap ' + + conditions.append(is_vwap_2) + dataframe.loc[is_vwap_2, 'buy_tag'] += 'vwap_2 ' + + conditions.append(is_vwap_3) + dataframe.loc[is_vwap_3, 'buy_tag'] += 'vwap_3 ' + + conditions.append(is_VWAP) + dataframe.loc[is_VWAP, 'buy_tag'] += 'VWAP ' + + conditions.append(is_insta) + dataframe.loc[is_insta, 'buy_tag'] += 'insta ' + + # NFI + conditions.append(is_nfi_32) + dataframe.loc[is_nfi_32, 'buy_tag'] += 'nfi_32 ' + + conditions.append(is_nfi_33) + dataframe.loc[is_nfi_33, 'buy_tag'] += 'nfi_33 ' + + conditions.append(is_nfix_39) + dataframe.loc[is_nfix_39, 'buy_tag'] += 'x_39 ' + + conditions.append(is_nfix_201) + dataframe.loc[is_nfix_201, 'buy_tag'] += 'x_201 ' + + conditions.append(is_nfi7_33) + dataframe.loc[is_nfi7_33, 'buy_tag'] += '7_33 ' + + conditions.append(is_nfi_sma_3) + dataframe.loc[is_nfi_sma_3, 'buy_tag'] += 'sma_3 ' + + # Very Bear + conditions.append(is_V_5) + dataframe.loc[is_V_5, 'buy_tag'] += 'V_5 ' + + 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: + + dataframe.loc[ (dataframe['volume'] > 0), 'sell' ] = 0 + + return dataframe + +# Chaikin Money Flow +def chaikin_money_flow(dataframe, n=20, fillna=False) -> Series: + """Chaikin Money Flow (CMF) + It measures the amount of Money Flow Volume over a specific period. + http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:chaikin_money_flow_cmf + Args: + dataframe(pandas.Dataframe): dataframe containing ohlcv + n(int): n period. + fillna(bool): if fill nan values. + Returns: + pandas.Series: New feature generated. + """ + mfv = ((dataframe['close'] - dataframe['low']) - (dataframe['high'] - dataframe['close'])) / (dataframe['high'] - dataframe['low']) + mfv = mfv.fillna(0.0) # float division by zero + mfv *= dataframe['volume'] + cmf = (mfv.rolling(n, min_periods=0).sum() + / dataframe['volume'].rolling(n, min_periods=0).sum()) + if fillna: + cmf = cmf.replace([np.inf, -np.inf], np.nan).fillna(0) + return Series(cmf, name='cmf') + +# Mom DIV +def momdiv(dataframe: DataFrame, mom_length: int = 10, bb_length: int = 20, bb_dev: float = 2.0, lookback: int = 30) -> DataFrame: + mom: Series = ta.MOM(dataframe, timeperiod=mom_length) + upperband, middleband, lowerband = ta.BBANDS(mom, timeperiod=bb_length, nbdevup=bb_dev, nbdevdn=bb_dev, matype=0) + buy = qtpylib.crossed_below(mom, lowerband) + sell = qtpylib.crossed_above(mom, upperband) + hh = dataframe['high'].rolling(lookback).max() + ll = dataframe['low'].rolling(lookback).min() + coh = dataframe['high'] >= hh + col = dataframe['low'] <= ll + df = DataFrame({ + "momdiv_mom": mom, + "momdiv_upperb": upperband, + "momdiv_lowerb": lowerband, + "momdiv_buy": buy, + "momdiv_sell": sell, + "momdiv_coh": coh, + "momdiv_col": col, + }, index=dataframe['close'].index) + return df + +class BB_RTR_dca (BB_RTR): + + # DCA options + position_adjustment_enable = True + + initial_safety_order_trigger = -0.08 + max_safety_orders = 2 + safety_order_step_scale = 0.5 #SS + safety_order_volume_scale = 1.6 #OS + + # Auto compound calculation + max_dca_multiplier = (1 + max_safety_orders) + if (max_safety_orders > 0): + if (safety_order_volume_scale > 1): + max_dca_multiplier = (2 + (safety_order_volume_scale * (math.pow(safety_order_volume_scale, (max_safety_orders - 1)) - 1) / (safety_order_volume_scale - 1))) + elif (safety_order_volume_scale < 1): + max_dca_multiplier = (2 + (safety_order_volume_scale * (1 - math.pow(safety_order_volume_scale, (max_safety_orders - 1))) / (1 - safety_order_volume_scale))) + + # Let unlimited stakes leave funds open for DCA orders + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + if self.config['stake_amount'] == 'unlimited': + return proposed_stake / self.max_dca_multiplier + + return proposed_stake + + # DCA + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + + if current_profit > self.initial_safety_order_trigger: + return None + + count_of_buys = trade.nr_of_successful_buys + + if 1 <= count_of_buys <= self.max_safety_orders: + safety_order_trigger = (abs(self.initial_safety_order_trigger) * count_of_buys) + if (self.safety_order_step_scale > 1): + safety_order_trigger = abs(self.initial_safety_order_trigger) + (abs(self.initial_safety_order_trigger) * self.safety_order_step_scale * (math.pow(self.safety_order_step_scale,(count_of_buys - 1)) - 1) / (self.safety_order_step_scale - 1)) + elif (self.safety_order_step_scale < 1): + safety_order_trigger = abs(self.initial_safety_order_trigger) + (abs(self.initial_safety_order_trigger) * self.safety_order_step_scale * (1 - math.pow(self.safety_order_step_scale,(count_of_buys - 1))) / (1 - self.safety_order_step_scale)) + + if current_profit <= (-1 * abs(safety_order_trigger)): + try: + stake_amount = self.wallets.get_trade_stake_amount(trade.pair, None) + # This calculates base order size + stake_amount = stake_amount / self.max_dca_multiplier + # This then calculates current safety order size + stake_amount = stake_amount * math.pow(self.safety_order_volume_scale, (count_of_buys - 1)) + amount = stake_amount / current_rate + logger.info(f"Initiating safety order buy #{count_of_buys} for {trade.pair} with stake amount of {stake_amount} which equals {amount}") + return stake_amount + except Exception as exception: + logger.info(f'Error occured while trying to get stake amount for {trade.pair}: {str(exception)}') + return None + + return None diff --git a/BinHV45.py b/BinHV45.py new file mode 100644 index 0000000..c007a7c --- /dev/null +++ b/BinHV45.py @@ -0,0 +1,71 @@ +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy +from freqtrade.strategy import IntParameter +from pandas import DataFrame +import numpy as np +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +def bollinger_bands(stock_price, window_size, num_of_std): + rolling_mean = stock_price.rolling(window=window_size).mean() + rolling_std = stock_price.rolling(window=window_size).std() + lower_band = rolling_mean - (rolling_std * num_of_std) + + return rolling_mean, lower_band + + +class BinHV45(IStrategy): + INTERFACE_VERSION = 2 + + minimal_roi = { + "0": 0.0125 + } + + stoploss = -0.05 + timeframe = '1m' + + buy_bbdelta = IntParameter(low=1, high=15, default=30, space='buy', optimize=True) + buy_closedelta = IntParameter(low=15, high=20, default=30, space='buy', optimize=True) + buy_tail = IntParameter(low=20, high=30, default=30, space='buy', optimize=True) + + # Hyperopt parameters + buy_params = { + "buy_bbdelta": 7, + "buy_closedelta": 17, + "buy_tail": 25, + } + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + bollinger = qtpylib.bollinger_bands(dataframe['close'], window=40, stds=2) + + dataframe['upper'] = bollinger['upper'] + dataframe['mid'] = bollinger['mid'] + dataframe['lower'] = bollinger['lower'] + dataframe['bbdelta'] = (dataframe['mid'] - dataframe['lower']).abs() + dataframe['pricedelta'] = (dataframe['open'] - dataframe['close']).abs() + dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs() + dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs() + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + dataframe['lower'].shift().gt(0) & + dataframe['bbdelta'].gt(dataframe['close'] * self.buy_bbdelta.value / 1000) & + dataframe['closedelta'].gt(dataframe['close'] * self.buy_closedelta.value / 1000) & + dataframe['tail'].lt(dataframe['bbdelta'] * self.buy_tail.value / 1000) & + dataframe['close'].lt(dataframe['lower'].shift()) & + dataframe['close'].le(dataframe['close'].shift()) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + no sell signal + """ + dataframe.loc[:, 'sell'] = 0 + return dataframe diff --git a/BreakEven.py b/BreakEven.py new file mode 100644 index 0000000..b405890 --- /dev/null +++ b/BreakEven.py @@ -0,0 +1,67 @@ +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + + +class BreakEven(IStrategy): + """ + author@: lenik + + Sometimes I want to close the bot ASAP, but not have the positions floating around. + + I can "/stopbuy" and wait for the positions to get closed by the bot rules, which is + waiting for some profit, etc -- this usually takes too long... + + What I would prefer is to close everything that is over 0% profit to avoid the losses. + + Here's a simple strategy with empty buy/sell signals and "minimal_roi = { 0 : 0 }" that + sells everything already at profit and wait until the positions at loss will come to break + even point (or the small profit you provide in ROI table). + + You may restart the bot with the new strategy as a command-line parameter. + + Another way would be to specify the original strategy in the config file, then change to + this one and simply "/reload_config" from the Telegram bot. + + """ + + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "0": 0.01, # at least 1% at first + "10": 0 # after 10min, everything goes + } + + # This is more radical version that sells everything above the profit level +# minimal_roi = { +# "0": 0 +# } + + # And this is basically "/forcesell all", that sells no matter what profit +# minimal_roi = { +# "0": -1 +# } + + # Optimal stoploss designed for the strategy + stoploss = -0.05 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # don't generate any buy or sell signals, everything is handled by ROI and stop_loss + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + ), + 'buy'] = 0 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + ), + 'sell'] = 0 + return dataframe diff --git a/DevilStra.json b/DevilStra.json new file mode 100644 index 0000000..774499a --- /dev/null +++ b/DevilStra.json @@ -0,0 +1,29 @@ +{ + "strategy_name": "DevilStra", + "params": { + "roi": { + "0": 0.574, + "1757": 0.158, + "3804": 0.089, + "6585": 0 + }, + "stoploss": { + "stoploss": -0.28 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_spell": "Gu,Ra,Si,Gu,Pa,De,Si,La,Si,De,Cu,Lu,Pa,Si,De,La,Gu,La,Cu,Cu,Zi,Si,Gu,Lu,Pa,Lu,Ra,La,Si,Si,Ra,Lu,Pa,Ra,De,Zi,Ra,Si,De,La,La,Lu,Gu,Lu,Cu,Ra,Cu,Cu,La,Lu,De,Gu,Si,Cu,Cu,La,Si,Ra,Cu,Zi,La,Gu,De,Zi,De,Gu,Pa,Si,Cu,Lu,Gu,Si,Gu,Lu,Ra,De,Lu,Pa,Pa,Si,Zi,Pa,Cu,Ra,Gu,Ra,De,Cu,Lu,De,Pa,Lu,De,Lu,Pa,Gu,Cu,De,La,Ra,Pa,Gu,Lu,Zi,La,Ra,Cu,Si,De,Ra,La,Zi,Lu,Gu,De,Si,Ra,Pa,Si,De,De,La,La,Lu,Cu,La,Lu,Pa,Pa,Pa,De,Lu,La,Zi,Si,Pa,Pa,La,Si,Cu,Ra,Ra,Gu,Zi,Si,Si,La,La,Lu,La,La,Lu,Pa,Lu,Pa,Cu,Lu,Lu,Si,Zi,Lu,Si,Gu,La,La,La,Pa,Ra,Ra,Cu,De,De,Si,De,De,Ra,Pa,Lu,Zi,Cu,Zi,Gu,Zi,Pa,Si,Gu,Zi,La,Ra,La,Zi,Si,Zi,Si,La,La,Zi,Pa,La,Pa,La,Lu,Pa,Si,Zi,Gu,Zi,De,Zi,Ra,Pa,Cu,De,Cu,Ra,Gu,Gu,Zi,Gu,Zi,Cu,Lu,Gu,Zi,Cu,Pa,Gu,Si,Zi,La,Ra,Lu,Pa,Gu,Si,Zi,La,Ra,Pa,Ra,Cu,Cu,Zi,Cu,Gu,De,Lu,De,De,Ra,Cu,Gu,De,Ra,Si,Pa,La,Si,La,Zi,Lu,Zi,Cu,Zi,La,De,Lu,Cu,Zi" + }, + "sell": { + "sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa" + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-04 11:36:44.627014+00:00" +} \ No newline at end of file diff --git a/DevilStra.py b/DevilStra.py new file mode 100644 index 0000000..c96782a --- /dev/null +++ b/DevilStra.py @@ -0,0 +1,721 @@ +# DevilStra Strategy +# 𝔇𝔢𝔳𝔦𝔩 𝔦𝔰 𝔞𝔩𝔴𝔞𝔶𝔰 𝔰𝔱𝔯𝔬𝔫𝔤𝔢𝔯 𝔱𝔥𝔞𝔫 𝔊𝔬𝔡. +# 𝔅𝔲𝔱 𝔱𝔥𝔢 𝔬𝔫𝔩𝔶 𝔬𝔫𝔢 𝔴𝔥𝔬 𝔥𝔞𝔰 𝔱𝔥𝔢 𝔞𝔟𝔦𝔩𝔦𝔱𝔶 +# 𝔗𝔬 𝔠𝔯𝔢𝔞𝔱𝔢 𝔫𝔢𝔴 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 𝔦𝔰 𝔊𝔬𝔡. +# 𝔄𝔫𝔡 𝔱𝔥𝔢 𝔇𝔢𝔳𝔦𝔩 𝔪𝔞𝔨𝔢𝔰 𝔭𝔬𝔴𝔢𝔯𝔣𝔲𝔩 𝔰𝔭𝔢𝔩𝔩𝔰 +# 𝔉𝔯𝔬𝔪 𝔱𝔥𝔦𝔰 𝔰𝔪𝔞𝔩𝔩 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 (𝔩𝔦𝔨𝔢 𝔣𝔯𝔬𝔤𝔰, 𝔢𝔱𝔠.) +# 𝔚𝔦𝔱𝔥 𝔣𝔯𝔞𝔤𝔪𝔢𝔫𝔱𝔞𝔱𝔦𝔬𝔫 𝔞𝔫𝔡 𝔪𝔦𝔵𝔦𝔫𝔤 𝔱𝔥𝔢𝔪. +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# * IMPORTANT: You Need An "STATIC" Pairlist On Your Config.json ! +# * IMPORTANT: First set PAIR_LIST_LENGHT={pair_whitelist size} +# * And re-hyperopt the Sell strategy And paste result in exact +# * place(lines 535~564) + +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell -s 𝕯𝖊𝖛𝖎𝖑𝕾𝖙𝖗𝖆 + +# --- Do not remove these libs --- +import numpy as np +from functools import reduce +import freqtrade.vendor.qtpylib.indicators as qtpylib +import talib.abstract as ta +import random +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# ########################## SETTINGS ############################## +# pairlist lenght(use exact count of pairs you used in whitelist size+1): +PAIR_LIST_LENGHT = 269 +# you can find exact value of this inside GodStraNew +TREND_CHECK_CANDLES = 4 +# Set the pain range of devil(2~9999) +PAIN_RANGE = 1000 +# Add "GodStraNew" Generated Results As spells inside SPELLS. +# Set them unic phonemes like 'Zi' 'Gu' or 'Lu'! +# * Use below replacement on GodStraNew results to +# * Change God Generated Creatures to Spells: +# +-----------------------------+----------------------+ +# | GodStraNew Hyperopt Results | DevilStra Spells | +# +-----------------------------+----------------------+ +# | | "phonem" : { | +# | buy_params = { | "buy_params" : { | +# | ... | ... | +# | } | }, | +# | sell_params = { | "sell_params" : { | +# | ... | ... | +# | } | } | +# | | }, | +# +-----------------------------+----------------------+ +SPELLS = { + "Zi": { + "buy_params": { + "buy_crossed_indicator0": "BOP-4", + "buy_crossed_indicator1": "MACD-0-50", + "buy_crossed_indicator2": "DEMA-52", + "buy_indicator0": "MINUS_DI-50", + "buy_indicator1": "HT_TRENDMODE-50", + "buy_indicator2": "CORREL-128", + "buy_operator0": "/>R", + "buy_operator1": "CA", + "buy_operator2": "CDT", + "buy_real_num0": 0.1763, + "buy_real_num1": 0.6891, + "buy_real_num2": 0.0509, + }, + "sell_params": { + "sell_crossed_indicator0": "WCLPRICE-52", + "sell_crossed_indicator1": "AROONOSC-15", + "sell_crossed_indicator2": "CDLRISEFALL3METHODS-52", + "sell_indicator0": "COS-50", + "sell_indicator1": "CDLCLOSINGMARUBOZU-30", + "sell_indicator2": "CDL2CROWS-130", + "sell_operator0": "DT", + "sell_operator1": ">R", + "sell_operator2": "/>R", + "sell_real_num0": 0.0678, + "sell_real_num1": 0.8698, + "sell_real_num2": 0.3917, + } + }, + "Gu": { + "buy_params": { + "buy_crossed_indicator0": "SMA-20", + "buy_crossed_indicator1": "CDLLADDERBOTTOM-20", + "buy_crossed_indicator2": "OBV-50", + "buy_indicator0": "MAMA-1-50", + "buy_indicator1": "SUM-40", + "buy_indicator2": "VAR-30", + "buy_operator0": "R", + "sell_operator2": "CUT", + "sell_real_num0": 0.2707, + "sell_real_num1": 0.7987, + "sell_real_num2": 0.6891, + } + }, + "Lu": { + "buy_params": { + "buy_crossed_indicator0": "HT_SINE-0-28", + "buy_crossed_indicator1": "ADD-130", + "buy_crossed_indicator2": "ADD-12", + "buy_indicator0": "ADD-28", + "buy_indicator1": "AVGPRICE-15", + "buy_indicator2": "AVGPRICE-12", + "buy_operator0": "DT", + "buy_operator1": "D", + "buy_operator2": "C", + "buy_real_num0": 0.3676, + "buy_real_num1": 0.4284, + "buy_real_num2": 0.372, + }, + "sell_params": { + "sell_crossed_indicator0": "HT_SINE-0-5", + "sell_crossed_indicator1": "HT_SINE-0-4", + "sell_crossed_indicator2": "HT_SINE-0-28", + "sell_indicator0": "ADD-30", + "sell_indicator1": "AVGPRICE-28", + "sell_indicator2": "ADD-50", + "sell_operator0": "CUT", + "sell_operator1": "DT", + "sell_operator2": "=R", + "sell_real_num0": 0.3205, + "sell_real_num1": 0.2055, + "sell_real_num2": 0.8467, + } + }, + "La": { + "buy_params": { + "buy_crossed_indicator0": "WMA-14", + "buy_crossed_indicator1": "MAMA-1-14", + "buy_crossed_indicator2": "CDLHIKKAKE-14", + "buy_indicator0": "T3-14", + "buy_indicator1": "BETA-14", + "buy_indicator2": "HT_PHASOR-1-14", + "buy_operator0": "/>R", + "buy_operator1": ">", + "buy_operator2": ">R", + "buy_real_num0": 0.0551, + "buy_real_num1": 0.3469, + "buy_real_num2": 0.3871, + }, + "sell_params": { + "sell_crossed_indicator0": "HT_TRENDLINE-14", + "sell_crossed_indicator1": "LINEARREG-14", + "sell_crossed_indicator2": "STOCHRSI-1-14", + "sell_indicator0": "CDLDARKCLOUDCOVER-14", + "sell_indicator1": "AD-14", + "sell_indicator2": "CDLSTALLEDPATTERN-14", + "sell_operator0": "/=R", + "sell_operator1": "COT", + "sell_operator2": "OT", + "sell_real_num0": 0.3992, + "sell_real_num1": 0.7747, + "sell_real_num2": 0.7415, + } + }, + "Si": { + "buy_params": { + "buy_crossed_indicator0": "MACDEXT-2-14", + "buy_crossed_indicator1": "CORREL-14", + "buy_crossed_indicator2": "CMO-14", + "buy_indicator0": "MA-14", + "buy_indicator1": "ADXR-14", + "buy_indicator2": "CDLMARUBOZU-14", + "buy_operator0": "<", + "buy_operator1": "/", + "buy_operator2": "CA", + "buy_real_num0": 0.2208, + "buy_real_num1": 0.1371, + "buy_real_num2": 0.6389, + }, + "sell_params": { + "sell_crossed_indicator0": "MACDEXT-0-15", + "sell_crossed_indicator1": "BBANDS-2-15", + "sell_crossed_indicator2": "DEMA-15", + "sell_indicator0": "ULTOSC-15", + "sell_indicator1": "MIDPOINT-12", + "sell_indicator2": "PLUS_DI-12", + "sell_operator0": "<", + "sell_operator1": "DT", + "sell_operator2": "COT", + "sell_real_num0": 0.278, + "sell_real_num1": 0.0643, + "sell_real_num2": 0.7065, + } + }, + "De": { + "buy_params": { + "buy_crossed_indicator0": "HT_DCPERIOD-12", + "buy_crossed_indicator1": "HT_PHASOR-0-12", + "buy_crossed_indicator2": "MACDFIX-1-15", + "buy_indicator0": "CMO-12", + "buy_indicator1": "TRIMA-12", + "buy_indicator2": "MACDEXT-0-15", + "buy_operator0": "<", + "buy_operator1": "D", + "buy_operator2": "<", + "buy_real_num0": 0.3924, + "buy_real_num1": 0.5546, + "buy_real_num2": 0.7648, + }, + "sell_params": { + "sell_crossed_indicator0": "MACDFIX-1-15", + "sell_crossed_indicator1": "MACD-1-15", + "sell_crossed_indicator2": "WMA-15", + "sell_indicator0": "ROC-15", + "sell_indicator1": "MACD-2-15", + "sell_indicator2": "CCI-60", + "sell_operator0": "CA", + "sell_operator1": " 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class DevilStra(IStrategy): + # #################### RESULT PASTE PLACE #################### + # 16/16: 108 trades. 75/18/15 Wins/Draws/Losses. Avg profit 7.77%. Median profit 8.89%. Total profit 0.08404983 BTC ( 84.05Σ%). Avg duration 3 days, 6:49:00 min. Objective: -11.22849 + + # Buy hyperspace params: + buy_params = { + "buy_spell": "Zi,Lu,Ra,Ra,La,Si,Pa,Si,Cu,La,De,Lu,De,La,Zi,Zi,Zi,Zi,Zi,Lu,Lu,Lu,Si,La,Ra,Pa,La,Zi,Zi,Gu,Ra,De,Gu,Zi,Ra,Ra,Ra,Cu,Pa,De,De,La,Lu,Lu,Lu,La,Zi,Cu,Ra,Gu,Pa,La,Zi,Zi,Si,Lu,Ra,Cu,Cu,Pa,Si,Gu,De,De,Lu,Gu,Zi,Pa,Lu,Pa,Ra,Gu,Cu,La,Pa,Lu,Zi,La,Zi,Gu,Zi,De,Cu,Ra,Lu,Ra,Gu,Si,Ra,La,La,Lu,Gu,Zi,Si,La,Pa,Pa,Cu,Cu,Zi,Gu,Pa,Zi,Pa,Cu,Lu,Pa,Si,De,Gu,Lu,Lu,Cu,Ra,Si,Pa,Gu,Si,Cu,Pa,Zi,Pa,Zi,Gu,Lu,Ra,Pa,Ra,De,Ra,Pa,Zi,La,Pa,De,Pa,Cu,Gu,De,Lu,La,Ra,Zi,Si,Zi,Zi,Cu,Cu,De,Pa,Pa,Zi,De,Ra,La,Lu,De,Lu,Gu,Cu,Cu,La,De,Gu,Lu,Ra,Pa,Lu,Cu,Pa,Pa,De,Si,Zi,Cu,De,De,De,Lu,Si,Zi,Gu,Si,Si,Ra,Pa,Si,La,La,Lu,Lu,De,Gu,Gu,Zi,Ra,La,Lu,Lu,La,Si,Zi,Si,Zi,Si,Lu,Cu,Zi,Lu,De,La,Ra,Ra,Lu,De,Pa,Zi,Gu,Cu,Zi,Pa,De,Si,Lu,De,Cu,De,Zi,Ra,Gu,De,Si,Lu,Lu,Ra,De,Gu,Cu,Gu,La,De,Lu,Lu,Si,Cu,Lu,Zi,Lu,Cu,Gu,Lu,Lu,Ra,Si,Ra,Pa,Lu,De,Ra,Zi,Gu,Gu,Zi,Lu,Cu,Cu,Cu,Lu", + } + + # Sell hyperspace params: + sell_params = { + "sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa", + } + + # ROI table: + minimal_roi = { + "0": 0.574, + "1757": 0.158, + "3804": 0.089, + "6585": 0 + } + + # Stoploss: + stoploss = -0.28 + # #################### END OF RESULT PLACE #################### + + # 𝖂𝖔𝖗𝖘𝖙, 𝖀𝖓𝖎𝖉𝖊𝖆𝖑, 𝕾𝖚𝖇𝖔𝖕𝖙𝖎𝖒𝖆𝖑, 𝕸𝖆𝖑𝖆𝖕𝖗𝖔𝖕𝖔𝖘 𝕬𝖓𝖉 𝕯𝖎𝖘𝖒𝖆𝖑 𝖙𝖎𝖒𝖊𝖋𝖗𝖆𝖒𝖊 𝖋𝖔𝖗 𝖙𝖍𝖎𝖘 𝖘𝖙𝖗𝖆𝖙𝖊𝖌𝖞: + timeframe = '4h' + + spell_pot = [ + ",".join( + tuple( + random.choices( + list(SPELLS.keys()), + # TODO: k will be change to len(pairlist) + k=PAIR_LIST_LENGHT + ) + ) + )for i in range(PAIN_RANGE) + ] + + buy_spell = CategoricalParameter( + spell_pot, default=spell_pot[0], space='buy') + sell_spell = CategoricalParameter( + spell_pot, default=spell_pot[0], space='sell') + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + pairs = self.dp.current_whitelist() + pairs_len = len(pairs) + pair_index = pairs.index(metadata['pair']) + + buy_spells = self.buy_spell.value.split(",") + buy_spells_len = len(buy_spells) + + if pairs_len > buy_spells_len: + print( + f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the") + print("Buy strategy And paste result in exact place(lines 535~564)") + print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!") + exit() + + buy_params_index = buy_spells[pair_index] + + params = spell_finder(buy_params_index, 'buy') + conditions = list() + # TODO: Its not dry code! + buy_indicator = params['buy_indicator0'] + buy_crossed_indicator = params['buy_crossed_indicator0'] + buy_operator = params['buy_operator0'] + buy_real_num = params['buy_real_num0'] + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = params['buy_indicator1'] + buy_crossed_indicator = params['buy_crossed_indicator1'] + buy_operator = params['buy_operator1'] + buy_real_num = params['buy_real_num1'] + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = params['buy_indicator2'] + buy_crossed_indicator = params['buy_crossed_indicator2'] + buy_operator = params['buy_operator2'] + buy_real_num = params['buy_real_num2'] + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + pairs = self.dp.current_whitelist() + pairs_len = len(pairs) + pair_index = pairs.index(metadata['pair']) + + sell_spells = self.sell_spell.value.split(",") + sell_spells_len = len(sell_spells) + + if pairs_len > sell_spells_len: + print( + f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the") + print("Sell strategy And paste result in exact place(lines 535~564)") + print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!") + exit() + + sell_params_index = sell_spells[pair_index] + + params = spell_finder(sell_params_index, 'sell') + + conditions = list() + # TODO: Its not dry code! + sell_indicator = params['sell_indicator0'] + sell_crossed_indicator = params['sell_crossed_indicator0'] + sell_operator = params['sell_operator0'] + sell_real_num = params['sell_real_num0'] + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = params['sell_indicator1'] + sell_crossed_indicator = params['sell_crossed_indicator1'] + sell_operator = params['sell_operator1'] + sell_real_num = params['sell_real_num1'] + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = params['sell_indicator2'] + sell_crossed_indicator = params['sell_crossed_indicator2'] + sell_operator = params['sell_operator2'] + sell_real_num = params['sell_real_num2'] + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'sell']=1 + return dataframe diff --git a/DevilStra.txt b/DevilStra.txt new file mode 100644 index 0000000..a05b101 --- /dev/null +++ b/DevilStra.txt @@ -0,0 +1,76 @@ +Result for strategy DevilStra +============================================================ BACKTESTING REPORT =========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------| +| SAND/USDT | 8 | 231.37 | 1850.99 | 1852.839 | 185.28 | 39 days, 21:07:00 | 6 1 1 75.0 | +| SOL/USDT | 135 | 4.65 | 628.37 | 628.998 | 62.90 | 2 days, 6:16:00 | 83 7 45 61.5 | +| AVAX/USDT | 84 | 5.75 | 483.08 | 483.565 | 48.36 | 3 days, 15:04:00 | 63 6 15 75.0 | +| GALA/USDT | 13 | 14.36 | 186.68 | 186.864 | 18.69 | 4 days, 22:32:00 | 9 0 4 69.2 | +| ETH/USDT | 43 | 3.56 | 153.26 | 153.409 | 15.34 | 4 days, 11:59:00 | 32 6 5 74.4 | +| BNB/USDT | 31 | 4.56 | 141.48 | 141.626 | 14.16 | 4 days, 15:44:00 | 18 10 3 58.1 | +| ROSE/USDT | 48 | 2.89 | 138.94 | 139.075 | 13.91 | 3 days, 22:48:00 | 25 15 8 52.1 | +| XRP/USDT | 50 | 1.64 | 82.23 | 82.309 | 8.23 | 3 days, 16:22:00 | 27 8 15 54.0 | +| EGLD/USDT | 44 | 0.08 | 3.35 | 3.355 | 0.34 | 4 days, 7:08:00 | 27 6 11 61.4 | +| ZEC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| ADA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| IOTX/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| CELR/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| TRX/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| BTC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| TOTAL | 456 | 8.04 | 3668.37 | 3672.038 | 367.20 | 4 days, 3:40:00 | 290 59 107 63.6 | +=========================================================== BUY TAG STATS =========================================================== +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------| +| TOTAL | 456 | 8.04 | 3668.37 | 3672.038 | 367.20 | 4 days, 3:40:00 | 290 59 107 63.6 | +===================================================== SELL REASON STATS ===================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 316 | 257 59 0 100 | 16.93 | 5351.22 | 5356.57 | 356.75 | +| sell_signal | 81 | 32 0 49 39.5 | -1.14 | -92.04 | -92.136 | -6.14 | +| stop_loss | 56 | 0 0 56 0 | -28.14 | -1576.06 | -1577.63 | -105.07 | +| force_sell | 3 | 1 0 2 33.3 | -4.92 | -14.75 | -14.763 | -0.98 | +========================================================= LEFT OPEN TRADES REPORT ========================================================= +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------| +| EGLD/USDT | 1 | 8.35 | 8.35 | 8.353 | 0.84 | 1 day, 12:00:00 | 1 0 0 100 | +| SOL/USDT | 1 | -10.94 | -10.94 | -10.952 | -1.10 | 8 days, 12:30:00 | 0 0 1 0 | +| XRP/USDT | 1 | -12.15 | -12.15 | -12.165 | -1.22 | 10 days, 12:20:00 | 0 0 1 0 | +| TOTAL | 3 | -4.92 | -14.75 | -14.763 | -1.48 | 6 days, 20:17:00 | 1 0 2 33.3 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 456 / 1.41 | +| Starting balance | 1000.000 USDT | +| Final balance | 4672.038 USDT | +| Absolute profit | 3672.038 USDT | +| Total profit % | 367.20% | +| Trades per day | 1.41 | +| Avg. daily profit % | 1.14% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 45600.000 USDT | +| | | +| Best Pair | SAND/USDT 1850.99% | +| Worst Pair | ZEC/USDT 0.00% | +| Best trade | SAND/USDT 1576.03% | +| Worst trade | ETH/USDT -28.14% | +| Best day | 1577.608 USDT | +| Worst day | -197.204 USDT | +| Days win/draw/lose | 170 / 98 / 55 | +| Avg. Duration Winners | 3 days, 15:35:00 | +| Avg. Duration Loser | 3 days, 18:33:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 1015.800 USDT | +| Max balance | 4686.801 USDT | +| Drawdown | 362.40% | +| Drawdown | 362.761 USDT | +| Drawdown high | 1116.607 USDT | +| Drawdown low | 753.846 USDT | +| Drawdown Start | 2021-05-12 21:55:00 | +| Drawdown End | 2021-06-22 12:45:00 | +| Market change | 2716.79% | +================================================ diff --git a/DevilStra2.json b/DevilStra2.json new file mode 100644 index 0000000..cf4dad0 --- /dev/null +++ b/DevilStra2.json @@ -0,0 +1,29 @@ +{ + "strategy_name": "DevilStra2", + "params": { + "roi": { + "0": 0.574, + "1757": 0.158, + "3804": 0.089, + "6585": 0 + }, + "stoploss": { + "stoploss": -0.28 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_spell": "De,De,Si,Zi,Si,Ra,Lu,Gu,Ra,Pa,Ra,La,La,Ra,Ra,Zi,La,Gu,De,Ra,Zi,Cu,Cu,La,Lu,Si,Pa,Zi,Zi,Ra,Cu,De,Zi,Zi,Si,Gu,La,Zi,Zi,Gu,Zi,La,Pa,Pa,Gu,Gu,Pa,De,Pa,Lu,La,La,Gu,Ra,Lu,Zi,Pa,Lu,Gu,De,Si,Cu,Gu,La,Zi,Gu,Cu,Si,Pa,La,La,Lu,Cu,Gu,Si,Lu,Ra,De,Si,Lu,Si,La,Si,Cu,De,Lu,Pa,Gu,Pa,Si,Gu,Lu,Lu,Cu,Lu,De,Cu,Pa,De,Pa,Si,Si,Lu,Pa,La,Gu,Pa,Si,Cu,Gu,Zi,La,Lu,Lu,Zi,De,La,La,Zi,La,Gu,Pa,Cu,Pa,Gu,Pa,Gu,Gu,Ra,Lu,Lu,Zi,De,Ra,Lu,La,Lu,De,Si,Lu,Ra,Si,Si,La,Pa,Lu,Zi,Zi,Cu,Cu,Ra,Si,De,Ra,Ra,Lu,La,Zi,De,Pa,Pa,Si,Zi,Gu,De,Gu,Ra,Cu,Pa,Lu,De,Pa,La,Lu,Cu,Ra,Pa,Cu,Cu,Ra,Gu,Zi,La,Si,Zi,La,Si,De,Cu,Ra,Si,Gu,Si,De,Si,Ra,Pa,Gu,Gu,Pa,Si,Zi,Si,Cu,La,Si,De,Cu,Lu,De,Zi,Si,Pa,Gu,Cu,Si,Pa,Gu,De,La,Ra,Pa,Ra,La,Ra,Ra,La,Pa,Ra,La,Cu,De,Lu,Ra,Si,Ra,Cu,Pa,Si,Zi,Gu,De,Cu,De,Lu,Pa,Zi,La,La,La,La,Lu,La,Lu,Cu,Zi,Zi,Zi,La,Si,Ra,De,Lu,Ra,Si,Ra,De,Pa,Lu" + }, + "sell": { + "sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa" + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-04 13:36:54.394335+00:00" +} \ No newline at end of file diff --git a/DevilStra2.py b/DevilStra2.py new file mode 100644 index 0000000..81e2714 --- /dev/null +++ b/DevilStra2.py @@ -0,0 +1,658 @@ +# DevilStra Strategy +# 𝔇𝔢𝔳𝔦𝔩 𝔦𝔰 𝔞𝔩𝔴𝔞𝔶𝔰 𝔰𝔱𝔯𝔬𝔫𝔤𝔢𝔯 𝔱𝔥𝔞𝔫 𝔊𝔬𝔡. +# 𝔅𝔲𝔱 𝔱𝔥𝔢 𝔬𝔫𝔩𝔶 𝔬𝔫𝔢 𝔴𝔥𝔬 𝔥𝔞𝔰 𝔱𝔥𝔢 𝔞𝔟𝔦𝔩𝔦𝔱𝔶 +# 𝔗𝔬 𝔠𝔯𝔢𝔞𝔱𝔢 𝔫𝔢𝔴 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 𝔦𝔰 𝔊𝔬𝔡. +# 𝔄𝔫𝔡 𝔱𝔥𝔢 𝔇𝔢𝔳𝔦𝔩 𝔪𝔞𝔨𝔢𝔰 𝔭𝔬𝔴𝔢𝔯𝔣𝔲𝔩 𝔰𝔭𝔢𝔩𝔩𝔰 +# 𝔉𝔯𝔬𝔪 𝔱𝔥𝔦𝔰 𝔰𝔪𝔞𝔩𝔩 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 (𝔩𝔦𝔨𝔢 𝔣𝔯𝔬𝔤𝔰, 𝔢𝔱𝔠.) +# 𝔚𝔦𝔱𝔥 𝔣𝔯𝔞𝔤𝔪𝔢𝔫𝔱𝔞𝔱𝔦𝔬𝔫 𝔞𝔫𝔡 𝔪𝔦𝔵𝔦𝔫𝔤 𝔱𝔥𝔢𝔪. +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# * IMPORTANT: You Need An "STATIC" Pairlist On Your Config.json ! +# * IMPORTANT: First set PAIR_LIST_LENGHT={pair_whitelist size} +# * And re-hyperopt the Sell strategy And paste result in exact +# * place(lines 535~564) + +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell -s 𝕯𝖊𝖛𝖎𝖑𝕾𝖙𝖗𝖆 + +# --- Do not remove these libs --- +import numpy as np +from functools import reduce +import freqtrade.vendor.qtpylib.indicators as qtpylib +import talib.abstract as ta +import random +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# ########################## SETTINGS ############################## +# pairlist lenght(use exact count of pairs you used in whitelist size+1): +PAIR_LIST_LENGHT = 269 +# you can find exact value of this inside GodStraNew +TREND_CHECK_CANDLES = 4 +# Set the pain range of devil(2~9999) +PAIN_RANGE = 1000 +# Add "GodStraNew" Generated Results As spells inside SPELLS. +# Set them unic phonemes like 'Zi' 'Gu' or 'Lu'! +# * Use below replacement on GodStraNew results to +# * Change God Generated Creatures to Spells: +# +-----------------------------+----------------------+ +# | GodStraNew Hyperopt Results | DevilStra Spells | +# +-----------------------------+----------------------+ +# | | "phonem" : { | +# | buy_params = { | "buy_params" : { | +# | ... | ... | +# | } | }, | +# | sell_params = { | "sell_params" : { | +# | ... | ... | +# | } | } | +# | | }, | +# +-----------------------------+----------------------+ +SPELLS = { + "Zi": { + "buy_params": { + "buy_crossed_indicator0": "BOP-4", + "buy_crossed_indicator1": "MACD-0-50", + "buy_crossed_indicator2": "DEMA-52", + "buy_indicator0": "MINUS_DI-50", + "buy_indicator1": "HT_TRENDMODE-50", + "buy_indicator2": "CORREL-128", + "buy_operator0": "/>R", + "buy_operator1": "CA", + "buy_operator2": "CDT", + "buy_real_num0": 0.1763, + "buy_real_num1": 0.6891, + "buy_real_num2": 0.0509, + }, + "sell_params": { + "sell_crossed_indicator0": "WCLPRICE-52", + "sell_crossed_indicator1": "AROONOSC-15", + "sell_crossed_indicator2": "CDLRISEFALL3METHODS-52", + "sell_indicator0": "COS-50", + "sell_indicator1": "CDLCLOSINGMARUBOZU-30", + "sell_indicator2": "CDL2CROWS-130", + "sell_operator0": "DT", + "sell_operator1": ">R", + "sell_operator2": "/>R", + "sell_real_num0": 0.0678, + "sell_real_num1": 0.8698, + "sell_real_num2": 0.3917, + } + }, + "Gu": { + "buy_params": { + "buy_crossed_indicator0": "SMA-20", + "buy_crossed_indicator1": "CDLLADDERBOTTOM-20", + "buy_crossed_indicator2": "OBV-50", + "buy_indicator0": "MAMA-1-50", + "buy_indicator1": "SUM-40", + "buy_indicator2": "VAR-30", + "buy_operator0": "R", + "sell_operator2": "CUT", + "sell_real_num0": 0.2707, + "sell_real_num1": 0.7987, + "sell_real_num2": 0.6891, + } + }, + "Lu": { + "buy_params": { + "buy_crossed_indicator0": "HT_SINE-0-28", + "buy_crossed_indicator1": "ADD-130", + "buy_crossed_indicator2": "ADD-12", + "buy_indicator0": "ADD-28", + "buy_indicator1": "AVGPRICE-15", + "buy_indicator2": "AVGPRICE-12", + "buy_operator0": "DT", + "buy_operator1": "D", + "buy_operator2": "C", + "buy_real_num0": 0.3676, + "buy_real_num1": 0.4284, + "buy_real_num2": 0.372, + }, + "sell_params": { + "sell_crossed_indicator0": "HT_SINE-0-5", + "sell_crossed_indicator1": "HT_SINE-0-4", + "sell_crossed_indicator2": "HT_SINE-0-28", + "sell_indicator0": "ADD-30", + "sell_indicator1": "AVGPRICE-28", + "sell_indicator2": "ADD-50", + "sell_operator0": "CUT", + "sell_operator1": "DT", + "sell_operator2": "=R", + "sell_real_num0": 0.3205, + "sell_real_num1": 0.2055, + "sell_real_num2": 0.8467, + } + }, + "La": { + "buy_params": { + "buy_crossed_indicator0": "WMA-14", + "buy_crossed_indicator1": "MAMA-1-14", + "buy_crossed_indicator2": "CDLHIKKAKE-14", + "buy_indicator0": "T3-14", + "buy_indicator1": "BETA-14", + "buy_indicator2": "HT_PHASOR-1-14", + "buy_operator0": "/>R", + "buy_operator1": ">", + "buy_operator2": ">R", + "buy_real_num0": 0.0551, + "buy_real_num1": 0.3469, + "buy_real_num2": 0.3871, + }, + "sell_params": { + "sell_crossed_indicator0": "HT_TRENDLINE-14", + "sell_crossed_indicator1": "LINEARREG-14", + "sell_crossed_indicator2": "STOCHRSI-1-14", + "sell_indicator0": "CDLDARKCLOUDCOVER-14", + "sell_indicator1": "AD-14", + "sell_indicator2": "CDLSTALLEDPATTERN-14", + "sell_operator0": "/=R", + "sell_operator1": "COT", + "sell_operator2": "OT", + "sell_real_num0": 0.3992, + "sell_real_num1": 0.7747, + "sell_real_num2": 0.7415, + } + }, + "Si": { + "buy_params": { + "buy_crossed_indicator0": "MACDEXT-2-14", + "buy_crossed_indicator1": "CORREL-14", + "buy_crossed_indicator2": "CMO-14", + "buy_indicator0": "MA-14", + "buy_indicator1": "ADXR-14", + "buy_indicator2": "CDLMARUBOZU-14", + "buy_operator0": "<", + "buy_operator1": "/", + "buy_operator2": "CA", + "buy_real_num0": 0.2208, + "buy_real_num1": 0.1371, + "buy_real_num2": 0.6389, + }, + "sell_params": { + "sell_crossed_indicator0": "MACDEXT-0-15", + "sell_crossed_indicator1": "BBANDS-2-15", + "sell_crossed_indicator2": "DEMA-15", + "sell_indicator0": "ULTOSC-15", + "sell_indicator1": "MIDPOINT-12", + "sell_indicator2": "PLUS_DI-12", + "sell_operator0": "<", + "sell_operator1": "DT", + "sell_operator2": "COT", + "sell_real_num0": 0.278, + "sell_real_num1": 0.0643, + "sell_real_num2": 0.7065, + } + }, + "De": { + "buy_params": { + "buy_crossed_indicator0": "HT_DCPERIOD-12", + "buy_crossed_indicator1": "HT_PHASOR-0-12", + "buy_crossed_indicator2": "MACDFIX-1-15", + "buy_indicator0": "CMO-12", + "buy_indicator1": "TRIMA-12", + "buy_indicator2": "MACDEXT-0-15", + "buy_operator0": "<", + "buy_operator1": "D", + "buy_operator2": "<", + "buy_real_num0": 0.3924, + "buy_real_num1": 0.5546, + "buy_real_num2": 0.7648, + }, + "sell_params": { + "sell_crossed_indicator0": "MACDFIX-1-15", + "sell_crossed_indicator1": "MACD-1-15", + "sell_crossed_indicator2": "WMA-15", + "sell_indicator0": "ROC-15", + "sell_indicator1": "MACD-2-15", + "sell_indicator2": "CCI-60", + "sell_operator0": "CA", + "sell_operator1": " 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class DevilStra2(IStrategy): + # #################### RESULT PASTE PLACE #################### + # 16/16: 108 trades. 75/18/15 Wins/Draws/Losses. Avg profit 7.77%. Median profit 8.89%. Total profit 0.08404983 BTC ( 84.05Σ%). Avg duration 3 days, 6:49:00 min. Objective: -11.22849 + + # Buy hyperspace params: + buy_params = { + "buy_spell": "Zi,Lu,Ra,Ra,La,Si,Pa,Si,Cu,La,De,Lu,De,La,Zi,Zi,Zi,Zi,Zi,Lu,Lu,Lu,Si,La,Ra,Pa,La,Zi,Zi,Gu,Ra,De,Gu,Zi,Ra,Ra,Ra,Cu,Pa,De,De,La,Lu,Lu,Lu,La,Zi,Cu,Ra,Gu,Pa,La,Zi,Zi,Si,Lu,Ra,Cu,Cu,Pa,Si,Gu,De,De,Lu,Gu,Zi,Pa,Lu,Pa,Ra,Gu,Cu,La,Pa,Lu,Zi,La,Zi,Gu,Zi,De,Cu,Ra,Lu,Ra,Gu,Si,Ra,La,La,Lu,Gu,Zi,Si,La,Pa,Pa,Cu,Cu,Zi,Gu,Pa,Zi,Pa,Cu,Lu,Pa,Si,De,Gu,Lu,Lu,Cu,Ra,Si,Pa,Gu,Si,Cu,Pa,Zi,Pa,Zi,Gu,Lu,Ra,Pa,Ra,De,Ra,Pa,Zi,La,Pa,De,Pa,Cu,Gu,De,Lu,La,Ra,Zi,Si,Zi,Zi,Cu,Cu,De,Pa,Pa,Zi,De,Ra,La,Lu,De,Lu,Gu,Cu,Cu,La,De,Gu,Lu,Ra,Pa,Lu,Cu,Pa,Pa,De,Si,Zi,Cu,De,De,De,Lu,Si,Zi,Gu,Si,Si,Ra,Pa,Si,La,La,Lu,Lu,De,Gu,Gu,Zi,Ra,La,Lu,Lu,La,Si,Zi,Si,Zi,Si,Lu,Cu,Zi,Lu,De,La,Ra,Ra,Lu,De,Pa,Zi,Gu,Cu,Zi,Pa,De,Si,Lu,De,Cu,De,Zi,Ra,Gu,De,Si,Lu,Lu,Ra,De,Gu,Cu,Gu,La,De,Lu,Lu,Si,Cu,Lu,Zi,Lu,Cu,Gu,Lu,Lu,Ra,Si,Ra,Pa,Lu,De,Ra,Zi,Gu,Gu,Zi,Lu,Cu,Cu,Cu,Lu", + } + + # Sell hyperspace params: + sell_params = { + "sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa", + } + + # ROI table: + minimal_roi = { + "0": 0.574, + "1757": 0.158, + "3804": 0.089, + "6585": 0 + } + + # Stoploss: + stoploss = -0.28 + # #################### END OF RESULT PLACE #################### + + # 𝖂𝖔𝖗𝖘𝖙, 𝖀𝖓𝖎𝖉𝖊𝖆𝖑, 𝕾𝖚𝖇𝖔𝖕𝖙𝖎𝖒𝖆𝖑, 𝕸𝖆𝖑𝖆𝖕𝖗𝖔𝖕𝖔𝖘 𝕬𝖓𝖉 𝕯𝖎𝖘𝖒𝖆𝖑 𝖙𝖎𝖒𝖊𝖋𝖗𝖆𝖒𝖊 𝖋𝖔𝖗 𝖙𝖍𝖎𝖘 𝖘𝖙𝖗𝖆𝖙𝖊𝖌𝖞: + timeframe = '4h' + + spell_pot = [ + ",".join( + tuple( + random.choices( + list(SPELLS.keys()), + # TODO: k will be change to len(pairlist) + k=PAIR_LIST_LENGHT + ) + ) + )for i in range(PAIN_RANGE) + ] + + buy_spell = CategoricalParameter( + spell_pot, default=spell_pot[0], space='buy') + sell_spell = CategoricalParameter( + spell_pot, default=spell_pot[0], space='sell') + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + pairs = self.dp.current_whitelist() + pairs_len = len(pairs) + pair_index = pairs.index(metadata['pair']) + + buy_spells = self.buy_spell.value.split(",") + buy_spells_len = len(buy_spells) + + if pairs_len > buy_spells_len: + print( + f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the") + print("Buy strategy And paste result in exact place(lines 535~564)") + print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!") + exit() + + buy_params_index = buy_spells[pair_index] + + params = spell_finder(buy_params_index, 'buy') + conditions = list() + # TODO: Its not dry code! + buy_indicator = params['buy_indicator0'] + buy_crossed_indicator = params['buy_crossed_indicator0'] + buy_operator = params['buy_operator0'] + buy_real_num = params['buy_real_num0'] + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = params['buy_indicator1'] + buy_crossed_indicator = params['buy_crossed_indicator1'] + buy_operator = params['buy_operator1'] + buy_real_num = params['buy_real_num1'] + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = params['buy_indicator2'] + buy_crossed_indicator = params['buy_crossed_indicator2'] + buy_operator = params['buy_operator2'] + buy_real_num = params['buy_real_num2'] + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Diamond.py b/Diamond.py new file mode 100644 index 0000000..fddff21 --- /dev/null +++ b/Diamond.py @@ -0,0 +1,155 @@ +# 𝐼𝓉 𝒾𝓈 𝒟𝒾𝒶𝓂𝑜𝓃𝒹 𝒮𝓉𝓇𝒶𝓉𝑒𝑔𝓎. +# 𝒯𝒽𝒶𝓉 𝓉𝒶𝓀𝑒𝓈 𝒽𝑒𝓇 𝑜𝓌𝓃 𝓇𝒾𝑔𝒽𝓉𝓈 𝓁𝒾𝓀𝑒 𝒜𝒻𝑔𝒽𝒶𝓃𝒾𝓈𝓉𝒶𝓃 𝓌𝑜𝓂𝑒𝓃 +# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓈𝓉𝒾𝓁𝓁 𝓅𝓇𝑜𝓊𝒹 𝒶𝓃𝒹 𝒽𝑜𝓅𝑒𝒻𝓊𝓁. +# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓉𝒽𝑒 𝓂𝑜𝓈𝓉 𝒷𝑒𝒶𝓊𝓉𝒾𝒻𝓊𝓁 𝒸𝓇𝑒𝒶𝓉𝓊𝓇𝑒𝓈 𝒾𝓃 𝓉𝒽𝑒 𝒹𝑒𝓅𝓉𝒽𝓈 𝑜𝒻 𝓉𝒽𝑒 𝒹𝒶𝓇𝓀𝑒𝓈𝓉. +# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓈𝒽𝒾𝓃𝑒 𝓁𝒾𝓀𝑒 𝒹𝒾𝒶𝓂𝑜𝓃𝒹𝓈 𝒷𝓊𝓇𝒾𝑒𝒹 𝒾𝓃 𝓉𝒽𝑒 𝒽𝑒𝒶𝓇𝓉 𝑜𝒻 𝓉𝒽𝑒 𝒹𝑒𝓈𝑒𝓇𝓉 ... +# 𝒲𝒽𝓎 𝓃𝑜𝓉 𝒽𝑒𝓁𝓅 𝓌𝒽𝑒𝓃 𝓌𝑒 𝒸𝒶𝓃? +# 𝐼𝒻 𝓌𝑒 𝒷𝑒𝓁𝒾𝑒𝓋𝑒 𝓉𝒽𝑒𝓇𝑒 𝒾𝓈 𝓃𝑜 𝓂𝒶𝓃 𝓁𝑒𝒻𝓉 𝓌𝒾𝓉𝒽 𝓉𝒽𝑒𝓂 +# (𝒲𝒽𝒾𝒸𝒽 𝒾𝓈 𝓅𝓇𝑜𝒷𝒶𝒷𝓁𝓎 𝓉𝒽𝑒 𝓅𝓇𝑜𝒹𝓊𝒸𝓉 𝑜𝒻 𝓉𝒽𝑒 𝓉𝒽𝑜𝓊𝑔𝒽𝓉 𝑜𝒻 𝓅𝒶𝒾𝓃𝓁𝑒𝓈𝓈 𝒸𝑜𝓇𝓅𝓈𝑒𝓈) +# 𝒲𝒽𝑒𝓇𝑒 𝒽𝒶𝓈 𝑜𝓊𝓇 𝒽𝓊𝓂𝒶𝓃𝒾𝓉𝓎 𝑔𝑜𝓃𝑒? +# 𝒲𝒽𝑒𝓇𝑒 𝒽𝒶𝓈 𝒽𝓊𝓂𝒶𝓃𝒾𝓉𝓎 𝑔𝑜𝓃𝑒? +# 𝒲𝒽𝓎 𝓃𝑜𝓉 𝒽𝑒𝓁𝓅 𝓌𝒽𝑒𝓃 𝓌𝑒 𝒸𝒶𝓃? +# 𝓁𝑒𝓉𝓈 𝓅𝒾𝓅 𝓊𝓃𝒾𝓃𝓈𝓉𝒶𝓁𝓁 𝓉𝒶-𝓁𝒾𝒷 𝑜𝓃 𝒜𝒻𝑔𝒽𝒶𝓃𝒾𝓈𝓉𝒶𝓃 + +# IMPORTANT: Diamond strategy is designed to be pure and +# cuz of that it have not any indicator population. idea is that +# It is just use the pure dataframe ohlcv data for calculation +# of buy/sell signals, But you can add your indicators and add +# your key names inside catagorical hyperoptable params and +# than you be able to hyperopt them as well. +# thanks to: @Kroissan, @drakes00 And @xmatthias for his patience and helps +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# * freqtrade backtesting --strategy Diamond + +# freqtrade hyperopt --hyperopt-loss ShortTradeDurHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 3/10: 76 trades. 51/18/7 Wins/Draws/Losses. Avg profit 1.92%. Median profit 2.40%. Total profit 0.04808472 BTC ( 48.08%). Avg duration 5:06:00 min. Objective: 1.75299 +# freqtrade hyperopt --hyperopt-loss OnlyProfitHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 10/10: 76 trades. 39/34/3 Wins/Draws/Losses. Avg profit 0.61%. Median profit 0.05%. Total profit 0.01528359 BTC ( 15.28%). Avg duration 17:32:00 min. Objective: -0.01528 +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 4/10: 15 trades. 10/2/3 Wins/Draws/Losses. Avg profit 1.52%. Median profit 7.99%. Total profit 0.00754274 BTC ( 7.54%). Avg duration 1 day, 0:04:00 min. Objective: -0.90653 +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 7/10: 130 trades. 68/54/8 Wins/Draws/Losses. Avg profit 0.71%. Median profit 0.06%. Total profit 0.03050369 BTC ( 30.50%). Avg duration 10:07:00 min. Objective: -11.08185 +# freqtrade hyperopt --hyperopt-loss SortinoHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 2/10: 10 trades. 7/0/3 Wins/Draws/Losses. Avg profit 5.50%. Median profit 7.05%. Total profit 0.01817970 BTC ( 18.18%). Avg duration 0:27:00 min. Objective: -11.72450 +# freqtrade hyperopt --hyperopt-loss SortinoHyperOptLossDaily --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# | * Best | 3/10 | 165 | 98 63 4 | 1.00% | 0.05453885 BTC (54.54%) | 0 days 08:02:00 | 0.00442974 BTC (13.41%) | -41.371 | +# | * Best | 7/10 | 101 | 56 42 3 | 0.73% | 0.02444518 BTC (24.45%) | 0 days 13:08:00 | 0.00107122 BTC (3.24%) | -66.7687 | +# * 7/10: 101 trades. 56/42/3 Wins/Draws/Losses. Avg profit 0.73%. Median profit 0.13%. Total profit 0.02444518 BTC ( 24.45%). Avg duration 13:08:00 min. Objective: -66.76866 +# freqtrade hyperopt --hyperopt-loss OnlyProfitHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10 +# * 7/10: 117 trades. 74/41/2 Wins/Draws/Losses. Avg profit 1.91%. Median profit 1.50%. Total profit 0.07370921 BTC ( 73.71%). Avg duration 9:26:00 min. Objective: -0.07371 + +# --- Do not remove these libs --- +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +# Add your lib to import here +import talib.abstract as ta +from functools import reduce +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +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 diff --git a/Diamond.txt b/Diamond.txt new file mode 100644 index 0000000..6084e4e --- /dev/null +++ b/Diamond.txt @@ -0,0 +1,77 @@ +Result for strategy Diamond +========================================================== BACKTESTING REPORT ========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------| +| CELR/USDT | 40 | 1.20 | 47.95 | 47.999 | 4.80 | 6:14:00 | 25 15 0 100 | +| ETH/USDT | 432 | 0.09 | 39.39 | 39.431 | 3.94 | 14:42:00 | 197 226 9 45.6 | +| ROSE/USDT | 60 | 0.64 | 38.12 | 38.154 | 3.82 | 7:32:00 | 29 31 0 100 | +| SAND/USDT | 14 | 1.41 | 19.70 | 19.717 | 1.97 | 3:29:00 | 11 3 0 100 | +| ADA/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 9:27:00 | 3 4 0 100 | +| AVAX/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 3:30:00 | 3 4 0 100 | +| XRP/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 2:55:00 | 3 4 0 100 | +| SOL/USDT | 4 | 0.86 | 3.43 | 3.435 | 0.34 | 3:36:00 | 2 2 0 100 | +| IOTX/USDT | 78 | 0.03 | 2.58 | 2.582 | 0.26 | 8:35:00 | 37 39 2 47.4 | +| BNB/USDT | 7 | 0.32 | 2.26 | 2.262 | 0.23 | 6:11:00 | 2 5 0 100 | +| GALA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| TRX/USDT | 2 | 0.00 | 0.00 | 0.000 | 0.00 | 12:42:00 | 0 2 0 0 | +| BTC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +| EGLD/USDT | 300 | -0.13 | -39.93 | -39.973 | -4.00 | 14:28:00 | 134 156 10 44.7 | +| ZEC/USDT | 277 | -0.25 | -69.80 | -69.865 | -6.99 | 15:57:00 | 137 130 10 49.5 | +| TOTAL | 1235 | 0.05 | 61.68 | 61.742 | 6.17 | 13:32:00 | 583 621 31 47.2 | +========================================================== BUY TAG STATS =========================================================== +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------| +| TOTAL | 1235 | 0.05 | 61.68 | 61.742 | 6.17 | 13:32:00 | 583 621 31 47.2 | +======================================================= SELL REASON STATS ======================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 1202 | 581 621 0 100 | 0.63 | 759.35 | 760.111 | 50.62 | +| trailing_stop_loss | 24 | 2 0 22 8.3 | -23.86 | -572.56 | -573.132 | -38.17 | +| sell_signal | 4 | 0 0 4 0 | -14.02 | -56.06 | -56.117 | -3.74 | +| force_sell | 3 | 0 0 3 0 | -4.85 | -14.56 | -14.574 | -0.97 | +| stop_loss | 2 | 0 0 2 0 | -27.25 | -54.49 | -54.546 | -3.63 | +======================================================== LEFT OPEN TRADES REPORT ========================================================= +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| ZEC/USDT | 1 | -1.32 | -1.32 | -1.320 | -0.13 | 2:40:00 | 0 0 1 0 | +| EGLD/USDT | 1 | -3.25 | -3.25 | -3.251 | -0.33 | 1:20:00 | 0 0 1 0 | +| ETH/USDT | 1 | -9.99 | -9.99 | -10.003 | -1.00 | 4 days, 10:50:00 | 0 0 1 0 | +| TOTAL | 3 | -4.85 | -14.56 | -14.574 | -1.46 | 1 day, 12:57:00 | 0 0 3 0 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 1235 / 3.82 | +| Starting balance | 1000.000 USDT | +| Final balance | 1061.742 USDT | +| Absolute profit | 61.742 USDT | +| Total profit % | 6.17% | +| Trades per day | 3.82 | +| Avg. daily profit % | 0.02% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 123500.000 USDT | +| | | +| Best Pair | CELR/USDT 47.95% | +| Worst Pair | ZEC/USDT -69.80% | +| Best trade | EGLD/USDT 9.32% | +| Worst trade | IOTX/USDT -27.25% | +| Best day | 18.000 USDT | +| Worst day | -55.225 USDT | +| Days win/draw/lose | 201 / 100 / 23 | +| Avg. Duration Winners | 2:30:00 | +| Avg. Duration Loser | 4 days, 7:03:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 940.516 USDT | +| Max balance | 1218.619 USDT | +| Drawdown | 277.83% | +| Drawdown | 278.103 USDT | +| Drawdown high | 218.619 USDT | +| Drawdown low | -59.484 USDT | +| Drawdown Start | 2021-05-12 06:00:00 | +| Drawdown End | 2021-07-20 03:05:00 | +| Market change | 2716.79% | +================================================ diff --git a/Empty.py b/Empty.py new file mode 100644 index 0000000..7153a92 --- /dev/null +++ b/Empty.py @@ -0,0 +1,123 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class Empty(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + # ( + # (dataframe['close'] < dataframe['bb_lowerband']) + # & (dataframe['bb_width'] >= 0.065) + # #& (dataframe['rsi'] < 45) + # & (dataframe['volume'] > 0) + # ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + 'sell'] = 1 + return dataframe + diff --git a/EnCirculation.txt b/EnCirculation.txt new file mode 100644 index 0000000..a70ce89 --- /dev/null +++ b/EnCirculation.txt @@ -0,0 +1,20 @@ +132,670,764,300 DOGE +19,215,937 BTC +71,683,856 LTC +138,063,286 ETC +18,204,913 XMR +19,238,231 BCH +15,772,013 ZEC +50,298,735,565 XRP +34,424,965,305 ADA +8,734,317,475 MATIC +1,139,368,061 DOT +362,910,497 SOL +549,063,278,876,302 SHIB +92,159,192,741 TRX +300,677,692 AVAX +18,204,913 XMR +1,344,947,069 STX +13,572,466,120 ZIL + +https://coinmarketcap.com/ diff --git a/FractalAtr.py b/FractalAtr.py new file mode 100644 index 0000000..5d84461 --- /dev/null +++ b/FractalAtr.py @@ -0,0 +1,328 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 +# isort: skip_file +# --- Do not remove these libs --- +import logging +import numpy as np +import pandas as pd +from pandas import DataFrame +from datetime import datetime, timedelta +from typing import Optional, Union, Tuple +from freqtrade.exchange import timeframe_to_prev_date +from freqtrade.persistence import Trade +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, stoploss_from_open, + IntParameter, IStrategy, merge_informative_pair, informative, stoploss_from_absolute) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import pandas_ta as pta +from technical import qtpylib + +class FractalAtr(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 3 + + # Optimal timeframe for the strategy. + timeframe = '1m' + + # Can this strategy go short? + can_short: bool = False + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + "0": 0.5 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -1 + + position_adjustment_enable = True + use_custom_stoploss = True + + # Trailing stoploss + trailing_stop = False + + # Run "populate_indicators()" only for new candle. + process_only_new_candles = True + + # These values can be overridden in the config. + use_exit_signal = True + exit_profit_only = False + ignore_roi_if_entry_signal = False + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 30 + + # Strategy parameters + buy_rsi = IntParameter(10, 40, default=30, space="buy") + sell_rsi = IntParameter(60, 90, default=70, space="sell") + + # trailing stoploss hyperopt parameters + # hard stoploss profit + + pHSL = DecimalParameter(-0.200, -0.040, default=-0.99, decimals=3, space='sell', optimize=False, load=True) + # profit threshold 1, trigger point, SL_1 is used + pPF_1 = DecimalParameter(0.008, 0.020, default=0.022, decimals=3, space='sell', optimize=True, load=True) + pSL_1 = DecimalParameter(0.008, 0.020, default=0.021, decimals=3, space='sell', optimize=True, load=True) + + # profit threshold 2, SL_2 is used + pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) + pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) + + # Optional order type mapping. + order_types = { + 'entry': 'limit', + 'exit': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + # Optional order time in force. + order_time_in_force = { + 'entry': 'GTC', + 'exit': 'GTC' + } + locked_pairs = {} + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if True | (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + + condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h']) + + # self.protection_nb_buy_lost.value + if (0 < count_of_buys <= 2) & (current_profit < - 0.1) & (condition): + try: + stake_amount = self.config['stake_amount'] + print("Adjust " + trade.pair + " " + str(current_time) + " " + str(current_profit) + " " + str(count_of_buys) + " " + + str(stake_amount)) + return stake_amount + except Exception as exception: + print(exception) + return None + return None + + def calculateScore(self, last_candle): + score = 1 #- (last_candle['percent10'] / 0.01 + return score + + @informative('1h') + def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + self.will_frac(dataframe) + dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0) + dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill") + dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0) + dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill") + dataframe['max72'] = ta.MAX(dataframe['close'], timeperiod=72) + dataframe['min72'] = ta.MIN(dataframe['close'], timeperiod=72) + dataframe['mid72'] = (dataframe['min72'] + (dataframe['max72'] - dataframe['min72']) / 2) + dataframe['width_72'] = (dataframe['max72'] - dataframe['min72']) / dataframe['max72'] + + dataframe['percent'] = dataframe['close'].pct_change() + dataframe['percent5'] = dataframe['close'].pct_change(5) + return dataframe + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + self.will_frac(dataframe) + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['atr'] = ta.ATR(dataframe) + dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0) + dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill") + dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0) + dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill") + dataframe["percent"] = dataframe["close"].pct_change() + dataframe["percent3"] = dataframe["close"].pct_change(3) + dataframe["percent10"] = dataframe["close"].pct_change(10) + + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['atr_relatif'] = ta.ATR(dataframe) / dataframe["min200"] + dataframe["close50"] = dataframe["close"].rolling(50).mean() + dataframe["close3"] = dataframe["close"].rolling(3).mean() + dataframe['rsi_mean'] = dataframe['rsi'].rolling(3).mean() + dataframe['atr_relatif_mean'] = dataframe['atr_relatif'].rolling(3).mean() + dataframe['width_200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['max200'] + dataframe['width_close'] = (dataframe['close'] - dataframe['min200']) / dataframe['close'] + dataframe['200_close'] = dataframe['width_close'] / dataframe['width_200'] * 100 + dataframe['72h_close'] = (dataframe['close'] - dataframe['min72_1h']) / dataframe['min72_1h'] * 100 + + return dataframe + + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['close'], dataframe['bull']) | + qtpylib.crossed_above(dataframe['close'].shift(1), dataframe['bull'].shift(1)) | + qtpylib.crossed_above(dataframe['close'].shift(2), dataframe['bull'].shift(2)) + ) & + ((dataframe['rsi'] < 20) | (dataframe['atr_relatif'] > 0.008)) & + # ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) & + (dataframe['close3'] < dataframe['close50']) & # Make sure Volume is not 0 + (dataframe['volume'] > 0) # Make sure Volume is not 0 + + ), ['buy', 'enter_tag']] = (1, 'buy_fractal') + + return dataframe + + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # #(dataframe['volume'] > 0) # Make sure Volume is not 0 + # ), + # 'exit_long'] = 1 + return dataframe + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + last_candle_12 = dataframe.iloc[-13].squeeze() + + allow_to_buy = True #(not self.stop_all) #& (not self.all_down) + + if pair in self.locked_pairs: + trade = self.locked_pairs[pair] + if (last_candle['close3'] >= last_candle['mid72_1h']): + print(pair + ' is locked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str( + trade.open_rate) + ' close3=' + str(last_candle['close3']) + ' mid72=' + str(last_candle['mid72_1h']) + + str(trade)) + allow_to_buy = False + # else: + # print(pair + ' unlocked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str( + # self.locked_pairs[pair])) + # del self.locked_pairs[pair] + + if allow_to_buy: + print('Buy ' + entry_tag + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( + round(self.wallets.get_available_stake_amount())) + " score=" + str(self.calculateScore(last_candle))) + return allow_to_buy + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, + time_in_force: str, + exit_reason: str, current_time, **kwargs, ) -> bool: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + + string = "" + buy_signal = self.getTradeCandle(dataframe, trade) + if not buy_signal.empty: + buy_signal_candle = buy_signal.iloc[-1] + string = str(buy_signal_candle['date']) + ' open=' + str(buy_signal_candle['open']) \ + + " score=" + str(self.calculateScore(last_candle)) + + print('Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( + round(self.wallets.get_available_stake_amount())) #"+ str(amount) + ' ' + str(rate) + + " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit" + str(trade.calc_profit(rate, amount)) + + " " + string) + + return True + + def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, + current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]': + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002): + return None + + days = (current_time - trade.open_date_utc).days + hours = (current_time - trade.open_date_utc).seconds / 3600 + minutes = (current_time - trade.open_date_utc).seconds / 60 + + # if (days >= 1) & (current_profit < -0.02): + # return 'too_old' + + self.testLockedTrade(trade, current_profit, current_rate, current_time, pair) + # if pair in self.locked_pairs: + # print(pair + " stoploss") + # return "force_stoploss" + factor = 10 + exit_atr = (trade.open_rate + (last_candle['atr'] * factor)) + if (current_rate > exit_atr): + return "exit_atr" + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002): + return -1 + + # print(pair + " " + str(current_time) + " rate=" + str(current_profit)) + self.testLockedTrade(trade, current_profit, current_rate, current_time, pair) + + # hard stoploss profit + HSL = self.pHSL.value + PF_1 = self.pPF_1.value + SL_1 = self.pSL_1.value + PF_2 = self.pPF_2.value + SL_2 = self.pSL_2.value + + # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + + if current_profit > PF_2: + sl_profit = SL_2 + (current_profit - PF_2) + elif (current_profit > PF_1): + sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + else: + sl_profit = HSL + + return stoploss_from_open(sl_profit, current_profit) + + # def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + # current_rate: float, current_profit: float, **kwargs) -> float: + # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # candle = dataframe.iloc[-1].squeeze() + # factor = 10 + # return stoploss_from_absolute(current_rate - (candle['atr'] * factor), current_rate, is_short=trade.is_short) + def getTradeCandle(self, dataframe, trade: 'Trade'): + trade_open_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc) + buy_signal = dataframe.loc[dataframe['date'] <= trade_open_date] + return buy_signal + + def testLockedTrade(self, trade: 'Trade', current_profit, current_rate, current_time, pair): + if current_profit <= -0.1: + if pair in self.locked_pairs: + trade = self.locked_pairs[pair] + if current_rate > trade.open_rate: + print(pair + ' unlocked ' + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str( + trade.open_rate) + ' profit=' + str(current_profit)) + del self.locked_pairs[pair] + # else: + # self.locked_pairs[pair] = current_rate + else: + self.locked_pairs[pair] = trade + # self.lock_pair(pair, until=current_time + timedelta(hours=24)) + + print(pair + " locked at " + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str( + trade.open_rate) + ' profit=' + str(current_profit)) + + def will_frac(self, df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]: + """ + Indicate bearish and bullish fractal patterns using shifted Series. + :param df: OHLC data + :param period: number of lower (or higher) points on each side of a high (or low) + :return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern + """ + periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2] + highs = [df['high'] > df['high'].shift(p) for p in periods] + bears = pd.Series(np.logical_and.reduce(highs), index=df.index) + lows = [df['low'] < df['low'].shift(p) for p in periods] + bulls = pd.Series(np.logical_and.reduce(lows), index=df.index) + df['fractal_sup'] = bears + df['fractal_inf'] = bulls + return df \ No newline at end of file diff --git a/FractalAtr2.py b/FractalAtr2.py new file mode 100644 index 0000000..eafbde1 --- /dev/null +++ b/FractalAtr2.py @@ -0,0 +1,433 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 +# isort: skip_file +# --- Do not remove these libs --- +import logging +import numpy as np +import pandas as pd +from pandas import DataFrame +from datetime import datetime, timedelta +from typing import Optional, Union, Tuple +from freqtrade.exchange import timeframe_to_prev_date +from freqtrade.persistence import Trade +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, stoploss_from_open, + IntParameter, IStrategy, merge_informative_pair, informative, stoploss_from_absolute) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import pandas_ta as pta +from technical import qtpylib + +class FractalAtr2(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 3 + + # Optimal timeframe for the strategy. + timeframe = '1m' + + # Can this strategy go short? + can_short: bool = False + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + "0": 0.5 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -1 + + position_adjustment_enable = True + use_custom_stoploss = True + + # Trailing stoploss + trailing_stop = False + + # Run "populate_indicators()" only for new candle. + process_only_new_candles = True + + # These values can be overridden in the config. + use_exit_signal = True + exit_profit_only = False + ignore_roi_if_entry_signal = False + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 30 + + # Strategy parameters + buy_rsi = IntParameter(10, 40, default=30, space="buy") + sell_rsi = IntParameter(60, 90, default=70, space="sell") + + # trailing stoploss hyperopt parameters + # hard stoploss profit + + pHSL = DecimalParameter(-0.200, -0.040, default=-0.99, decimals=3, space='sell', optimize=False, load=True) + # profit threshold 1, trigger point, SL_1 is used + pPF_1 = DecimalParameter(0.008, 0.020, default=0.022, decimals=3, space='sell', optimize=True, load=True) + pSL_1 = DecimalParameter(0.008, 0.020, default=0.021, decimals=3, space='sell', optimize=True, load=True) + + # profit threshold 2, SL_2 is used + pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) + pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) + + # Optional order type mapping. + order_types = { + 'entry': 'limit', + 'exit': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + # Optional order time in force. + order_time_in_force = { + 'entry': 'GTC', + 'exit': 'GTC' + } + locked_pairs = {} + max_profit_pairs = {} + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if True | (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + + condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h']) + + # self.protection_nb_buy_lost.value + if (0 < count_of_buys <= 2) & (current_profit < - 0.1) & (condition): + try: + stake_amount = self.config['stake_amount'] + print("Adjust " + trade.pair + " " + str(current_time) + " " + str(current_profit) + " " + str(count_of_buys) + " " + + str(stake_amount)) + return stake_amount + except Exception as exception: + print(exception) + return None + return None + + def calculateScore(self, last_candle): + score = 1 #- (last_candle['percent10'] / 0.01 + return score + + @informative('1d') + def populate_indicators_1d(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['atr'] = ta.ATR(dataframe) + dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # Bollinger Bands + + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"])) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + return dataframe + + @informative('1h') + def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + self.will_frac(dataframe) + dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0) + dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill") + dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0) + dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill") + dataframe['max72'] = ta.MAX(dataframe['close'], timeperiod=72) + dataframe['min72'] = ta.MIN(dataframe['close'], timeperiod=72) + dataframe['mid72'] = (dataframe['min72'] + (dataframe['max72'] - dataframe['min72']) / 2) + dataframe['width_72'] = (dataframe['max72'] - dataframe['min72']) / dataframe['max72'] + + dataframe['percent'] = dataframe['close'].pct_change() + dataframe['percent5'] = dataframe['close'].pct_change(5) + return dataframe + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + self.will_frac(dataframe) + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['atr'] = ta.ATR(dataframe) + dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0) + dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill") + dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0) + dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill") + dataframe["percent"] = dataframe["close"].pct_change() + dataframe["percent3"] = dataframe["close"].pct_change(3) + dataframe["percent10"] = dataframe["close"].pct_change(10) + dataframe["diff_close1"] = dataframe["close"] - dataframe["close"].shift(1) + dataframe["diff_close3"] = dataframe["close"] - dataframe["close"].shift(3) + dataframe["diff_close5"] = dataframe["close"] - dataframe["close"].shift(5) + dataframe["diff_close10"] = dataframe["close"] - dataframe["close"].shift(10) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_3'] = dataframe['min200'].rolling(3).mean() + + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['atr_relatif'] = ta.ATR(dataframe) / dataframe["min200"] + dataframe["close50"] = dataframe["close"].rolling(50).mean() + dataframe["close3"] = dataframe["close"].rolling(3).mean() + dataframe['rsi_mean'] = dataframe['rsi'].rolling(3).mean() + dataframe['atr_relatif_mean'] = dataframe['atr_relatif'].rolling(3).mean() + dataframe['width_200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['max200'] + dataframe['width_close'] = (dataframe['close'] - dataframe['min200']) / dataframe['close'] + dataframe['200_close'] = dataframe['width_close'] / dataframe['width_200'] * 100 + dataframe['72h_close'] = (dataframe['close'] - dataframe['min72_1h']) / dataframe['min72_1h'] * 100 + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"])) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + return dataframe + + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['close'], dataframe['bull']) | + qtpylib.crossed_above(dataframe['close'].shift(1), dataframe['bull'].shift(1)) | + qtpylib.crossed_above(dataframe['close'].shift(2), dataframe['bull'].shift(2)) | + (dataframe['low'] <= dataframe['min200']) | + (dataframe['low'] <= dataframe['bb_lowerband_1d']) + ) & + # ((dataframe['rsi'] < 60) | (dataframe['atr_relatif'] > 0.008)) & + # ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) & + (dataframe['open'] < dataframe['bb_upperband_1d']) & + (dataframe['bb_width'] >= 0.015) & + (dataframe['width_close'] <= 0.015) & + (dataframe['open'] < dataframe['close3']) & + (dataframe['open'] < dataframe['close50']) & + (dataframe['fractal_inf_1h'] == 1) & + #((dataframe['fractal_inf_1h'] == 1) | (dataframe['low'] <= dataframe['bb_lowerband_1d'])) & + # (dataframe['percent10'] < -0.005) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + + ), ['buy', 'enter_tag']] = (1, 'buy_fractal') + + # dataframe.loc[ + # ( + # # ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) & + # # (dataframe['close3'] <= dataframe['width_200']) & + # (dataframe['min200'].shift(5) == dataframe['min200']) & + # (dataframe['min72_1h'] > dataframe['min200']) & + # (dataframe['width_200'] > 0.035) & + # (dataframe['width_close'] == 0) & + # (dataframe['volume'] > 0) # Make sure Volume is not 0 + # + # ), ['buy', 'enter_tag']] = (1, 'buy_min72') + + return dataframe + + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + ((dataframe['200_close'].shift(3) > 95) | (dataframe['200_close'].shift(2) > 95) + | (dataframe['200_close'].shift(1) > 95) | (dataframe['200_close'] > 95) + | (dataframe['percent'] < -0.005) + # | (dataframe['high'] >= dataframe['max50']) + # | ((dataframe['percent3'] < 0) & (dataframe['close3'].shift(1) >= dataframe['close3'])) + ) + & + (dataframe['percent'] < 0) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'exit_long'] = 1 + return dataframe + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + last_candle_12 = dataframe.iloc[-13].squeeze() + + allow_to_buy = True #(not self.stop_all) #& (not self.all_down) + + if pair in self.locked_pairs: + trade = self.locked_pairs[pair] + if (last_candle['close3'] >= last_candle['mid72_1h']): + print(pair + ' is locked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str( + trade.open_rate) + ' close3=' + str(last_candle['close3']) + ' mid72=' + str(last_candle['mid72_1h']) + + str(trade)) + allow_to_buy = False + # else: + # print(pair + ' unlocked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str( + # self.locked_pairs[pair])) + # del self.locked_pairs[pair] + + if allow_to_buy: + print('Buy ' + entry_tag + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( + round(self.wallets.get_available_stake_amount())) + " score=" + str(self.calculateScore(last_candle))) + return allow_to_buy + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, + time_in_force: str, + exit_reason: str, current_time, **kwargs, ) -> bool: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + + days = (current_time - trade.open_date_utc).days + hours = (current_time - trade.open_date_utc).seconds / 3600 + minutes = (current_time - trade.open_date_utc).seconds / 60 + + allow_to_sell = False #(minutes > 30) + profit = trade.calc_profit(rate, amount) + if not (pair in self.max_profit_pairs): + self.max_profit_pairs[pair] = profit + self.max_profit_pairs[pair] = max(self.max_profit_pairs[pair], profit) + + if (self.max_profit_pairs[pair] > 0.5): + allow_decrease = 0.2 * self.max_profit_pairs[pair] + print("Max profit=" + str(self.max_profit_pairs[pair]) + ' ' + str(profit) + ' ' + str(allow_decrease)) + if self.max_profit_pairs[pair] - profit < allow_decrease: + allow_to_sell = False + else: + allow_to_sell = True + # if last_candle['percent'] <= + + if (profit < - 1.5): + print("Stop loss profit=" + str(self.max_profit_pairs[pair]) + ' ' + str(profit)) + allow_to_sell = True + + string = "" + buy_signal = self.getTradeCandle(dataframe, trade) + if not buy_signal.empty: + buy_signal_candle = buy_signal.iloc[-1] + string = str(buy_signal_candle['date']) + ' open=' + str(buy_signal_candle['open']) \ + + " score=" + str(self.calculateScore(last_candle)) + + if allow_to_sell: + print('Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( + round(self.wallets.get_available_stake_amount())) #"+ str(amount) + ' ' + str(rate) + + " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit=" + str(trade.calc_profit(rate, amount)) + + " " + string) + del self.max_profit_pairs[pair] + else: + print('Cancel Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair) + return allow_to_sell + + def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, + current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]': + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002): + return None + + days = (current_time - trade.open_date_utc).days + hours = (current_time - trade.open_date_utc).seconds / 3600 + minutes = (current_time - trade.open_date_utc).seconds / 60 + + if not (pair in self.max_profit_pairs): + self.max_profit_pairs[pair] = current_profit + self.max_profit_pairs[pair] = max(self.max_profit_pairs[pair], current_profit) + + if (hours >= 2) & (self.max_profit_pairs[pair] < 0.002) & (self.max_profit_pairs[pair] > - 0.002): + return "no_change" + + # if (days >= 1) & (current_profit < -0.02): + # return 'too_old' + + self.testLockedTrade(trade, current_profit, current_rate, current_time, pair) + # if pair in self.locked_pairs: + # print(pair + " stoploss") + # return "force_stoploss" + factor = 10 + exit_atr = (trade.open_rate + (last_candle['atr'] * factor)) + if (current_rate > exit_atr): + return "exit_atr" + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002): + return -1 + + # print(pair + " " + str(current_time) + " rate=" + str(current_profit)) + self.testLockedTrade(trade, current_profit, current_rate, current_time, pair) + + # hard stoploss profit + HSL = self.pHSL.value + PF_1 = self.pPF_1.value + SL_1 = self.pSL_1.value + PF_2 = self.pPF_2.value + SL_2 = self.pSL_2.value + + # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + + if current_profit > PF_2: + sl_profit = SL_2 + (current_profit - PF_2) + elif (current_profit > PF_1): + sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + else: + sl_profit = HSL + + return stoploss_from_open(sl_profit, current_profit) + + # def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + # current_rate: float, current_profit: float, **kwargs) -> float: + # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # candle = dataframe.iloc[-1].squeeze() + # factor = 10 + # return stoploss_from_absolute(current_rate - (candle['atr'] * factor), current_rate, is_short=trade.is_short) + def getTradeCandle(self, dataframe, trade: 'Trade'): + trade_open_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc) + buy_signal = dataframe.loc[dataframe['date'] <= trade_open_date] + return buy_signal + + def testLockedTrade(self, trade: 'Trade', current_profit, current_rate, current_time, pair): + return "" + if current_profit <= -0.1: + if pair in self.locked_pairs: + trade = self.locked_pairs[pair] + if current_rate > trade.open_rate: + print(pair + ' unlocked ' + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str( + trade.open_rate) + ' profit=' + str(current_profit)) + del self.locked_pairs[pair] + # else: + # self.locked_pairs[pair] = current_rate + else: + self.locked_pairs[pair] = trade + # self.lock_pair(pair, until=current_time + timedelta(hours=24)) + + print(pair + " locked at " + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str( + trade.open_rate) + ' profit=' + str(current_profit)) + + def will_frac(self, df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]: + """ + Indicate bearish and bullish fractal patterns using shifted Series. + :param df: OHLC data + :param period: number of lower (or higher) points on each side of a high (or low) + :return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern + """ + periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2] + highs = [df['high'] > df['high'].shift(p) for p in periods] + bears = pd.Series(np.logical_and.reduce(highs), index=df.index) + lows = [df['low'] < df['low'].shift(p) for p in periods] + bulls = pd.Series(np.logical_and.reduce(lows), index=df.index) + df['fractal_sup'] = bears + df['fractal_inf'] = bulls + return df diff --git a/Genetic.py b/Genetic.py new file mode 100644 index 0000000..b71fd1c --- /dev/null +++ b/Genetic.py @@ -0,0 +1,362 @@ +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy as np # noqa + + +def activate(x): + return np.tanh(x) # tanh + +params = { + '0-0-0-w': -0.53814, + '0-0-bias': -0.96407, + '1-0-0-w': -0.49249, + '10-0-0-w': 0.08845, + '11-0-0-w': -0.14317, + '12-0-0-w': 0.00923, + '13-0-0-w': 0.30464, + '14-0-0-w': -0.35835, + '15-0-0-w': -0.49712, + '16-0-0-w': 0.76135, + '17-0-0-w': -0.75257, + '18-0-0-w': -0.04622, + '19-0-0-w': 0.10012, + '2-0-0-w': -0.23534, + '20-0-0-w': -0.04553, + '21-0-0-w': -0.35334, + '22-0-0-w': 0.17952, + '23-0-0-w': 0.44446, + '24-0-0-w': -0.15875, + '25-0-0-w': 0.97565, + '26-0-0-w': -0.89948, + '27-0-0-w': 0.61777, + '28-0-0-w': -0.60204, + '29-0-0-w': -0.85229, + '3-0-0-w': 0.47262, + '30-0-0-w': -0.52791, + '31-0-0-w': 0.98494, + '4-0-0-w': -0.54942, + '5-0-0-w': 0.40523, + '6-0-0-w': 0.4723, + '7-0-0-w': 0.63297, + '8-0-0-w': 0.07159, + '9-0-0-w': -0.86791, + 'adx-bias': -0.48719, + 'ao-bias': -0.87518, + 'aroonosc-bias': -0.56096, + 'bb_percent-bias': -0.98703, + 'bb_width-bias': -0.73742, + 'cci-bias': 0.47039, + 'end-0-w': -0.81658, + 'end-bias': 0.74656, + 'fastd-bias': -0.2793, + 'fisher_rsi_norm-bias': -0.36065, + 'kc_percent-bias': 0.76707, + 'kc_width-bias': 0.5489, + 'macd-bias': 0.55448, + 'macdhist-bias': -0.83133, + 'macdsignal-bias': 0.30828, + 'mfi-bias': -0.13097, + 'roc-bias': -0.78885, + 'rsi-bias': 0.9856, + 'sar-bias': 0.43812, + 'sma10-bias': -0.39019, + 'sma100-bias': 0.03558, + 'sma21-bias': 0.07457, + 'sma3-bias': 0.93633, + 'sma5-bias': -0.93329, + 'sma50-bias': -0.60637, + 'tema10-bias': -0.45946, + 'tema100-bias': 0.1662, + 'tema21-bias': 0.68466, + 'tema3-bias': 0.25368, + 'tema5-bias': -0.88818, + 'tema50-bias': 0.3019, + 'uo-bias': 0.71019, + 'wbb_percent-bias': -0.55964, + 'wbb_width-bias': 0.23523, + + 's-0-0-0-w': 0.85409, + 's-0-0-bias': -0.04613, + 's-1-0-0-w': -0.14997, + 's-10-0-0-w': -0.67008, + 's-11-0-0-w': -0.40221, + 's-12-0-0-w': 0.64553, + 's-13-0-0-w': 0.22838, + 's-14-0-0-w': 0.99977, + 's-15-0-0-w': 0.89363, + 's-16-0-0-w': -0.88212, + 's-17-0-0-w': -0.71813, + 's-18-0-0-w': 0.41602, + 's-19-0-0-w': -0.48389, + 's-2-0-0-w': 0.09649, + 's-20-0-0-w': 0.64273, + 's-21-0-0-w': -0.31671, + 's-22-0-0-w': 0.9663, + 's-23-0-0-w': 0.00229, + 's-24-0-0-w': 0.96244, + 's-25-0-0-w': -0.24513, + 's-26-0-0-w': 0.52312, + 's-27-0-0-w': 0.44742, + 's-28-0-0-w': -0.03916, + 's-29-0-0-w': 0.88882, + 's-3-0-0-w': -0.32112, + 's-30-0-0-w': -0.70886, + 's-31-0-0-w': -0.42672, + 's-4-0-0-w': -0.55265, + 's-5-0-0-w': 0.56105, + 's-6-0-0-w': 0.47436, + 's-7-0-0-w': 0.58136, + 's-8-0-0-w': -0.48308, + 's-9-0-0-w': -0.16024, + 's-adx-bias': -0.4091, + 's-ao-bias': 0.76889, + 's-aroonosc-bias': 0.16228, + 's-bb_percent-bias': 0.19407, + 's-bb_width-bias': 0.11795, + 's-cci-bias': 0.8379, + 's-end-0-w': -0.14648, + 's-end-bias': -0.85697, + 's-fastd-bias': -0.00581, + 's-fisher_rsi_norm-bias': -0.05253, + 's-kc_percent-bias': -0.3562, + 's-kc_width-bias': 0.67451, + 's-macd-bias': -0.17742, + 's-macdhist-bias': -0.58328, + 's-macdsignal-bias': -0.79847, + 's-mfi-bias': -0.48236, + 's-roc-bias': -0.5914, + 's-rsi-bias': -0.9618, + 's-sar-bias': 0.57033, + 's-sma10-bias': 0.14349, + 's-sma100-bias': 0.02401, + 's-sma21-bias': 0.78191, + 's-sma3-bias': 0.72279, + 's-sma5-bias': -0.19383, + 's-sma50-bias': 0.63697, + 's-tema10-bias': 0.96837, + 's-tema100-bias': 0.77171, + 's-tema21-bias': 0.67279, + 's-tema3-bias': -0.24583, + 's-tema5-bias': -0.08997, + 's-tema50-bias': 0.65532, + 's-uo-bias': 0.67701, + 's-wbb_percent-bias': -0.658, + 's-wbb_width-bias': -0.71056 +} + +network_shape = [1] + +class Genetic(IStrategy): + # ROI table: + minimal_roi = { + "0": 0.21029, + "11": 0.05876, + "57": 0.02191, + "281": 0 + } + + # Stoploss: + stoploss = -0.07693 + + # Optimal ticker interval for the strategy + ticker_interval = '2h' + + # Trailing stop: + trailing_only_offset_is_reached = False + trailing_stop = True + trailing_stop_positive = 0.01019 + trailing_stop_positive_offset = 0.01164 + + # run "populate_indicators" only for new candle + process_only_new_candles = True + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = True + + startup_candle_count = 100 + + 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. + """ + + # Momentum Indicators + # ------------------------------------ + + # ADX + dataframe['adx'] = ta.ADX(dataframe) / 100 + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # # Minus Directional Indicator / Movement + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) / 100 + + # # Awesome Oscillator + dataframe['ao'] = ((qtpylib.awesome_oscillator(dataframe) > 0).astype(int) - 0.5) * 2 + + # # Keltner Channel + keltner = qtpylib.keltner_channel(dataframe) + dataframe["kc_upperband"] = keltner["upper"] + dataframe["kc_lowerband"] = keltner["lower"] + dataframe["kc_middleband"] = keltner["mid"] + dataframe["kc_percent"] = ( + (dataframe["close"] - dataframe["kc_lowerband"]) / + (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + ) + dataframe["kc_width"] = ( + (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + ) + + # # Ultimate Oscillator + dataframe['uo'] = ta.ULTOSC(dataframe) / 100 + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + dataframe['cci'] = ta.CCI(dataframe) / 200 + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) / 100 + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] * 100 - 50) + fisher_rsi = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + dataframe['fisher_rsi_norm'] = 50 * (fisher_rsi + 1) / 100 + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] / 100 + + # # Stochastic RSI + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) / 100 + + # # ROC + dataframe['roc'] = ta.ROC(dataframe) / 100 + + # Overlap Studies + # ------------------------------------ + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # SMA - Simple Moving Average + dataframe['sma3'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=3) - 1 + dataframe['sma5'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=5) - 1 + dataframe['sma10'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=10) - 1 + dataframe['sma21'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=21) - 1 + dataframe['sma50'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=50) - 1 + dataframe['sma100'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=100) - 1 + + # Parabolic SAR + dataframe['sar'] = dataframe['close'] / ta.SAR(dataframe) - 1 + + # TEMA - Triple Exponential Moving Average + dataframe['tema3'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=3) - 1 + dataframe['tema5'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=5) - 1 + dataframe['tema10'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=10) - 1 + dataframe['tema21'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=21) - 1 + dataframe['tema50'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=50) - 1 + dataframe['tema100'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=100) - 1 + + 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 + """ + indicators = ['aroonosc', 'ao', 'uo', 'cci', 'rsi', 'fisher_rsi_norm', 'sar', + 'sma3', 'sma5', 'sma10', 'sma21', 'sma50', 'sma100', + 'tema3', 'tema5', 'tema10', 'tema21', 'tema50', 'tema100', + 'fastd', 'adx', 'bb_percent', 'bb_width', 'macd', 'macdsignal', 'macdhist', 'mfi', + 'wbb_percent', 'wbb_width', 'roc', 'kc_percent', 'kc_width'] + inputs = [] + for indicator in indicators: + inputs.append(dataframe[indicator] + params[indicator + '-bias']) + + for index, layer_size in enumerate(network_shape): + outputs = [] + for n in range(layer_size): + weight = 0 + for i, input in enumerate(inputs): + weight += params['{}-{}-{}-w'.format(i, index, n)] * input + weight += params['{}-{}-bias'.format(index, n)] + outputs.append(activate(weight)) + inputs = outputs + + weight = 0 + for i, input in enumerate(inputs): + weight += params['end-{}-w'.format(i)] * input + weight += params['end-bias'] + + dataframe.loc[activate(weight) > 0, 'buy'] = 1 + + # Check that the candle had volume + dataframe.loc[dataframe['volume'] <= 0, 'buy'] = 0 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe \ No newline at end of file diff --git a/GodStra.py b/GodStra.py new file mode 100644 index 0000000..ec4717b --- /dev/null +++ b/GodStra.py @@ -0,0 +1,171 @@ +# GodStra Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT:Add to your pairlists inside config.json (Under StaticPairList): +# { +# "method": "AgeFilter", +# "min_days_listed": 30 +# }, +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# IMPORTANT: Use Smallest "max_open_trades" for getting best results inside config.json + +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +# Add your lib to import here +# import talib.abstract as ta +from ta import add_all_ta_features +from ta.utils import dropna +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np + + +class GodStra(IStrategy): + # 5/66: 9 trades. 8/0/1 Wins/Draws/Losses. Avg profit 21.83%. Median profit 35.52%. Total profit 1060.11476586 USDT ( 196.50Σ%). Avg duration 3440.0 min. Objective: -7.06960 + # +--------+---------+----------+------------------+--------------+-------------------------------+----------------+-------------+ + # | Best | Epoch | Trades | Win Draw Loss | Avg profit | Profit | Avg duration | Objective | + # |--------+---------+----------+------------------+--------------+-------------------------------+----------------+-------------| + # | * Best | 1/500 | 11 | 2 1 8 | 5.22% | 280.74230393 USDT (57.40%) | 2,421.8 m | -2.85206 | + # | * Best | 2/500 | 10 | 7 0 3 | 18.76% | 983.46414442 USDT (187.58%) | 360.0 m | -4.32665 | + # | * Best | 5/500 | 9 | 8 0 1 | 21.83% | 1,060.11476586 USDT (196.50%) | 3,440.0 m | -7.0696 | + + # Buy hyperspace params: + buy_params = { + 'buy-cross-0': 'volatility_kcc', + 'buy-indicator-0': 'trend_ichimoku_base', + 'buy-int-0': 42, + 'buy-oper-0': ' DataFrame: + # Add all ta features + dataframe = dropna(dataframe) + dataframe = add_all_ta_features( + dataframe, open="open", high="high", low="low", close="close", volume="volume", + fillna=True) + # dataframe.to_csv("df.csv", index=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = list() + # /5: Cuz We have 5 Group of variables inside buy_param + for i in range(self.dna_size(self.buy_params)): + + OPR = self.buy_params[f'buy-oper-{i}'] + IND = self.buy_params[f'buy-indicator-{i}'] + CRS = self.buy_params[f'buy-cross-{i}'] + INT = self.buy_params[f'buy-int-{i}'] + REAL = self.buy_params[f'buy-real-{i}'] + DFIND = dataframe[IND] + DFCRS = dataframe[CRS] + + if OPR == ">": + conditions.append(DFIND > DFCRS) + elif OPR == "=": + conditions.append(np.isclose(DFIND, DFCRS)) + elif OPR == "<": + conditions.append(DFIND < DFCRS) + elif OPR == "CA": + conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) + elif OPR == "CB": + conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) + elif OPR == ">I": + conditions.append(DFIND > INT) + elif OPR == "=I": + conditions.append(DFIND == INT) + elif OPR == "R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " DataFrame: + conditions = list() + for i in range(self.dna_size(self.sell_params)): + OPR = self.sell_params[f'sell-oper-{i}'] + IND = self.sell_params[f'sell-indicator-{i}'] + CRS = self.sell_params[f'sell-cross-{i}'] + INT = self.sell_params[f'sell-int-{i}'] + REAL = self.sell_params[f'sell-real-{i}'] + DFIND = dataframe[IND] + DFCRS = dataframe[CRS] + + if OPR == ">": + conditions.append(DFIND > DFCRS) + elif OPR == "=": + conditions.append(np.isclose(DFIND, DFCRS)) + elif OPR == "<": + conditions.append(DFIND < DFCRS) + elif OPR == "CA": + conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) + elif OPR == "CB": + conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) + elif OPR == ">I": + conditions.append(DFIND > INT) + elif OPR == "=I": + conditions.append(DFIND == INT) + elif OPR == "R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " List[Dimension]: + """ + Define your Hyperopt space for searching buy strategy parameters. + """ + gene = list() + + for i in range(DNA_SIZE): + gene.append(Categorical(GodGenes, name=f'buy-indicator-{i}')) + gene.append(Categorical(GodGenes, name=f'buy-cross-{i}')) + gene.append(Integer(-1, 101, name=f'buy-int-{i}')) + gene.append(Real(-1.1, 1.1, name=f'buy-real-{i}')) + # Operations + # CA: Crossed Above, CB: Crossed Below, + # I: Integer, R: Real, D: Disabled + gene.append(Categorical(["D", ">", "<", "=", "CA", "CB", + ">I", "=I", "R", "=R", " Callable: + """ + Define the buy strategy parameters to be used by Hyperopt. + """ + def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Buy strategy Hyperopt will build and use. + """ + conditions = [] + # GUARDS AND TRENDS + for i in range(DNA_SIZE): + + OPR = params[f'buy-oper-{i}'] + IND = params[f'buy-indicator-{i}'] + CRS = params[f'buy-cross-{i}'] + INT = params[f'buy-int-{i}'] + REAL = params[f'buy-real-{i}'] + DFIND = dataframe[IND] + DFCRS = dataframe[CRS] + + if OPR == ">": + conditions.append(DFIND > DFCRS) + elif OPR == "=": + conditions.append(np.isclose(DFIND, DFCRS)) + elif OPR == "<": + conditions.append(DFIND < DFCRS) + elif OPR == "CA": + conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) + elif OPR == "CB": + conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) + elif OPR == ">I": + conditions.append(DFIND > INT) + elif OPR == "=I": + conditions.append(DFIND == INT) + elif OPR == "R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " List[Dimension]: + """ + Define your Hyperopt space for searching sell strategy parameters. + """ + gene = list() + + for i in range(DNA_SIZE): + gene.append(Categorical(GodGenes, name=f'sell-indicator-{i}')) + gene.append(Categorical(GodGenes, name=f'sell-cross-{i}')) + gene.append(Integer(-1, 101, name=f'sell-int-{i}')) + gene.append(Real(-0.01, 1.01, name=f'sell-real-{i}')) + # Operations + # CA: Crossed Above, CB: Crossed Below, + # I: Integer, R: Real, D: Disabled + gene.append(Categorical(["D", ">", "<", "=", "CA", "CB", + ">I", "=I", "R", "=R", " Callable: + """ + Define the sell strategy parameters to be used by Hyperopt. + """ + def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Sell strategy Hyperopt will build and use. + """ + conditions = [] + + # GUARDS AND TRENDS + for i in range(DNA_SIZE): + + OPR = params[f'sell-oper-{i}'] + IND = params[f'sell-indicator-{i}'] + CRS = params[f'sell-cross-{i}'] + INT = params[f'sell-int-{i}'] + REAL = params[f'sell-real-{i}'] + DFIND = dataframe[IND] + DFCRS = dataframe[CRS] + + if OPR == ">": + conditions.append(DFIND > DFCRS) + elif OPR == "=": + conditions.append(np.isclose(DFIND, DFCRS)) + elif OPR == "<": + conditions.append(DFIND < DFCRS) + elif OPR == "CA": + conditions.append(qtpylib.crossed_above(DFIND, DFCRS)) + elif OPR == "CB": + conditions.append(qtpylib.crossed_below(DFIND, DFCRS)) + elif OPR == ">I": + conditions.append(DFIND > INT) + elif OPR == "=I": + conditions.append(DFIND == INT) + elif OPR == "R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.15) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'sell']=1 + return dataframe diff --git a/GodStraJD1.py b/GodStraJD1.py new file mode 100644 index 0000000..5bfe5dc --- /dev/null +++ b/GodStraJD1.py @@ -0,0 +1,858 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD1(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' + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.14) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + # ( + # # StrategyHelperLocal.four_red_candles(dataframe) & + # # dataframe['bb_width'] >= 0.025 + # ( + # ((dataframe['open'] - dataframe['close'].shift(4)) / dataframe['open'] > 0.01) | + # ((dataframe['open'] - dataframe['close'].shift(5)) / dataframe['open'] > 0.01) | + # ((dataframe['open'] - dataframe['close'].shift(6)) / dataframe['open'] > 0.01) | + # ((dataframe['open'] - dataframe['close'].shift(7)) / dataframe['open'] > 0.01) + # ) + # ) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD2.py b/GodStraJD2.py new file mode 100644 index 0000000..0e1699f --- /dev/null +++ b/GodStraJD2.py @@ -0,0 +1,848 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD2(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.13) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3.py b/GodStraJD3.py new file mode 100644 index 0000000..caefc0e --- /dev/null +++ b/GodStraJD3.py @@ -0,0 +1,863 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bbwitth': {'color': 'blue'}, + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.12) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3_1.json b/GodStraJD3_1.json new file mode 100644 index 0000000..4a5a28e --- /dev/null +++ b/GodStraJD3_1.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD3_1", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "CDLINNECK-6", + "buy_crossed_indicator1": "DEMA-12", + "buy_crossed_indicator2": "CDLHAMMER-12", + "buy_indicator0": "CDLXSIDEGAP3METHODS-55", + "buy_indicator1": "HT_DCPERIOD-55", + "buy_indicator2": "LINEARREG_INTERCEPT-6", + "buy_operator0": "=R", + "buy_operator1": ">R", + "buy_operator2": ">R", + "buy_real_num0": 0.0, + "buy_real_num1": 0.1, + "buy_real_num2": 0.3 + }, + "sell": { + "sell_crossed_indicator0": "AVGPRICE-100", + "sell_crossed_indicator1": "CDLGAPSIDESIDEWHITE-6", + "sell_crossed_indicator2": "PLUS_DI-15", + "sell_indicator0": "BBANDS-2-50", + "sell_indicator1": "PLUS_DM-6", + "sell_indicator2": "MIDPOINT-100", + "sell_operator0": "/=R", + "sell_operator1": "CUT", + "sell_operator2": "CUT", + "sell_real_num0": 0.1, + "sell_real_num1": 0.2, + "sell_real_num2": 1.0 + }, + "protection": {}, + "roi": { + "0": 0.594, + "1344": 0.201, + "3068": 0.081, + "5986": 0 + }, + "stoploss": { + "stoploss": -0.116 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-03 05:11:14.667810+00:00" +} diff --git a/GodStraJD3_1.py b/GodStraJD3_1.py new file mode 100644 index 0000000..97cde64 --- /dev/null +++ b/GodStraJD3_1.py @@ -0,0 +1,1033 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import datetime + +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + "600": 0.166, + "1200": 0.14, + "2400": 0.1, + "3600": 0.05, + "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '4h' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + # print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.015 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + # print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.12) + & (dataframe['volume'] * dataframe['close'] / 1000 > 100) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3_2.json b/GodStraJD3_2.json new file mode 100644 index 0000000..e2623b4 --- /dev/null +++ b/GodStraJD3_2.json @@ -0,0 +1,84 @@ +{ + "strategy_name": "GodStraJD3_2", + "params": { + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_indicator0": "CDLSHOOTINGSTAR-110", + "buy_crossed_indicator0": "CDLTASUKIGAP-5", + "buy_operator0": ">", + "buy_real_num0": 1.0, + "buy_indicator1": "MACDFIX-2-12", + "buy_crossed_indicator1": "CDLSPINNINGTOP-6", + "buy_operator1": "<", + "buy_real_num1": 0.2, + "buy_indicator2": "DEMA-110", + "buy_crossed_indicator2": "CDL3WHITESOLDIERS-110", + "buy_operator2": "/R", + "sell_real_num0": 0.9, + "sell_real_num1": 0.6, + "sell_real_num2": 0.3 + }, + "protections": [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 5 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 2, + "stop_duration_candles": 100, + "max_allowed_drawdown": 0.1 + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "only_per_pair": false + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 6, + "trade_limit": 2, + "stop_duration_candles": 60, + "required_profit": 0.02 + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "required_profit": 0.01 + } + ], + "roi": { + "0": 0.893, + "1606": 0.31, + "4383": 0.122, + "10010": 0 + }, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-02 04:52:51.009356+00:00" +} diff --git a/GodStraJD3_2.jsonOLD b/GodStraJD3_2.jsonOLD new file mode 100644 index 0000000..5c4bb5f --- /dev/null +++ b/GodStraJD3_2.jsonOLD @@ -0,0 +1,84 @@ +{ + "strategy_name": "GodStraJD3_2", + "params": { + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_indicator0": "CDLSHOOTINGSTAR-110", + "buy_crossed_indicator0": "CDLTASUKIGAP-5", + "buy_operator0": ">", + "buy_real_num0": 1.0, + "buy_indicator1": "MACDFIX-2-12", + "buy_crossed_indicator1": "CDLSPINNINGTOP-6", + "buy_operator1": "<", + "buy_real_num1": 0.2, + "buy_indicator2": "DEMA-110", + "buy_crossed_indicator2": "CDL3WHITESOLDIERS-110", + "buy_operator2": "/R", + "sell_real_num0": 0.9, + "sell_real_num1": 0.6, + "sell_real_num2": 0.3 + }, + "protections": [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 5 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 2, + "stop_duration_candles": 100, + "max_allowed_drawdown": 0.1 + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "only_per_pair": false + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 6, + "trade_limit": 2, + "stop_duration_candles": 60, + "required_profit": 0.02 + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "required_profit": 0.01 + } + ], + "roi": { + "0": 0.893, + "1606": 0.31, + "4383": 0.122, + "10010": 0 + }, + "stoploss": { + "stoploss": -2 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-02 04:52:51.009356+00:00" +} diff --git a/GodStraJD3_2.py b/GodStraJD3_2.py new file mode 100644 index 0000000..2db2341 --- /dev/null +++ b/GodStraJD3_2.py @@ -0,0 +1,1078 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + "600": 0.166, + "1200": 0.14, + "2400": 0.1, + "3600": 0.05, + "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '4h' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind": { + 'CDLTASUKIGAP-5': {'color': 'white'}, + 'CDLSPINNINGTOP-6': {'color': 'blue'}, + 'CDL3WHITESOLDIERS-110': {'color': 'red'} + }, + "Ind2": { + 'CDLSHOOTINGSTAR-110': {'color': 'white'}, + 'MACDFIX-2-12': {'color': 'blue'}, + 'DEMA-110': {'color': 'red'} + }, + + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20'] * 1.001) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + #( + # (dataframe['close'] < dataframe['bb_lowerband']) + # & (dataframe['bb_width'] >= 0.12) + # & (dataframe['volume'] * dataframe['close'] / 1000 > 100) + #) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3_3.py b/GodStraJD3_3.py new file mode 100644 index 0000000..8d361f1 --- /dev/null +++ b/GodStraJD3_3.py @@ -0,0 +1,1111 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy, SellCheckTuple +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_3(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '4h' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind": { + 'CDLTASUKIGAP-5': {'color': 'white'}, + 'CDLSPINNINGTOP-6': {'color': 'blue'}, + 'CDL3WHITESOLDIERS-110': {'color': 'red'} + }, + "Ind2": { + 'CDLSHOOTINGSTAR-110': {'color': 'white'}, + 'MACDFIX-2-12': {'color': 'blue'}, + 'DEMA-110': {'color': 'red'} + }, + + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + count = 0 + for coin, balance in self.wallets.get_all_balances().items(): + count = count + 1 + # print(coin, " ", balance) + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + # ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + if (current_profit > 0) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): #(current_profit / 4))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma10_desc' + + #if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # & (last_candle['percent'] < 0): + # print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_bb_band_sma20_desc' + + if (current_profit > 0) & (last_candle['rsi'] > 88): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + #if 0.015 < current_profit < 0.03: + # if (last_candle['percent3'] < -0.005 ): + # # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'profit_percent3' + # if (current_profit > 0) \ + # & (last_candle['percent'] < -0.02): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_percent_loss' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + # if 0.05 < current_profit < 1: + # if ( + # (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + # (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # # ) | ( + # # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + # ): + # # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + # + # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'profit_3h_sma10_desc' + # + # if (0 < current_profit < 0.1) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + # print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'profit_5h_sma20_desc' + + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + dataframe['ADD-20'] = gene_calculator(dataframe, 'ADD-20') + dataframe['ASIN-6'] = gene_calculator(dataframe, 'ASIN-6') + dataframe['CDLEVENINGSTAR-50'] = gene_calculator(dataframe, 'CDLEVENINGSTAR-50') + + dataframe['SMA-100'] = gene_calculator(dataframe, 'SMA-100') + dataframe['WILLR-50'] = gene_calculator(dataframe, 'WILLR-50') + dataframe['CDLHANGINGMAN-20'] = gene_calculator(dataframe, 'CDLHANGINGMAN-20') + + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.12) + & (dataframe['volume'] * dataframe['close'] / 1000 > 100) + ) | + (reduce(lambda x, y: x & y, conditions)), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + # print("sell pair=", self.wallets.get_all_balances()[metadata['pair']]) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) & + (dataframe['volume'] * dataframe['close'] / 1000 >= 100) + # (dataframe['open'] < dataframe['sma10']) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3_4.json b/GodStraJD3_4.json new file mode 100644 index 0000000..0cf25e5 --- /dev/null +++ b/GodStraJD3_4.json @@ -0,0 +1,41 @@ +{ + "strategy_name": "GodStraJD3_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.145, + "trailing_stop_positive_offset": 0.146, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "T3-10", + "buy_crossed_indicator1": "HT_SINE-1-50", + "buy_crossed_indicator2": "PLUS_DI-20", + "buy_indicator0": "TEMA-50", + "buy_indicator1": "ADXR-50", + "buy_indicator2": "CDLSEPARATINGLINES-50", + "buy_operator0": "/", + "buy_operator2": "/R", + "buy_operator1": "<", + "buy_operator2": "CA", + "buy_real_num0": 0.0, + "buy_real_num1": 0.8, + "buy_real_num2": 0.5 + }, + "sell": { + "sell_crossed_indicator0": "TRANGE-12", + "sell_crossed_indicator1": "CDLEVENINGDOJISTAR-55", + "sell_crossed_indicator2": "HT_PHASOR-0-15", + "sell_indicator0": "HT_PHASOR-0-15", + "sell_indicator1": "AROON-1-110", + "sell_indicator2": "ADX-6", + "sell_operator0": "", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_4(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + # 'min': {'color': 'white'}, + # 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind": { + "PLUS_DM-20": {'color': 'green'}, + "CDLTAKURI-5": {'color': 'blue'} + }, + # "Ind2": { + # 'MINUS_DM-5': {'color': 'green'}, + # 'DX-5': {'color': 'blue'}, + # 'LINEARREG-50': {'color': 'red'} + # }, + # "Profit": { + # 'profit': {'color': 'pink'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.01) & (last_candle['rsi'] < 30): + return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + # if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + # & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + # return "quick_gain_param" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, "4h") for pair in pairs] + #informative_pairs += [(pair, '1d') for pair in pairs] + #informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + dataframe[self.buy_indicator0.value] = gene_calculator(dataframe, self.buy_indicator0.value) + dataframe[self.buy_crossed_indicator0.value] = gene_calculator(dataframe, self.buy_crossed_indicator0.value) + dataframe[self.buy_indicator1.value] = gene_calculator(dataframe, self.buy_indicator1.value) + dataframe[self.buy_crossed_indicator1.value] = gene_calculator(dataframe, self.buy_crossed_indicator1.value) + # dataframe[self.buy_indicator2.value] = gene_calculator(dataframe, self.buy_indicator2.value) + # dataframe[self.buy_crossed_indicator2.value] = gene_calculator(dataframe, self.buy_crossed_indicator2.value) + + # dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5) + # dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50) + # dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20) + # stoch = ta.STOCH(dataframe, timeperiod=10) + # # print(stoch) + # dataframe['STOCH-1-10'] = stoch['slowd'] + # dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5) + + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + # dataframe["sum_percent"] = dataframe["sum_percent"].shift(1) + dataframe["percent"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + # print('informative', metadata['pair'], informative.tail(1)) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + (reduce(lambda x, y: x & y, conditions) + # & (dataframe['percent_4h'] > 0) + & (dataframe['percent3_4h'] <= 0) + ), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_4_1.json b/GodStraJD3_4_1.json new file mode 100644 index 0000000..950f042 --- /dev/null +++ b/GodStraJD3_4_1.json @@ -0,0 +1,54 @@ +{ + "strategy_name": "GodStraJD3_4_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.145, + "trailing_stop_positive_offset": 0.146, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bbwidth_num0": 0.9, + "buy_cond1_num0": 5.74, + "buy_crossed_indicator0": "CDLIDENTICAL3CROWS-100", + "buy_crossed_indicator1": "CDLMORNINGDOJISTAR-20", + "buy_crossed_indicator2": "CDLEVENINGSTAR-10", + "buy_indicator0": "HT_PHASOR-0-100", + "buy_indicator1": "DEMA-10", + "buy_indicator2": "CDLEVENINGSTAR-10", + "buy_operator0": "/", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_4_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if self.profit_quick_lost.value: + if (current_profit >= 0) & (last_candle['percent3'] < -0.01): + return "quick_lost" + + if self.profit_no_change.value: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3.value: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain.value: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10.value: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10.value: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5) + # dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50) + # dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20) + # stoch = ta.STOCH(dataframe, timeperiod=10) + # # print(stoch) + # dataframe['STOCH-1-10'] = stoch['slowd'] + # dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5) + + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + # dataframe["sum_percent"] = dataframe["sum_percent"].shift(1) + dataframe["percent"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[self.buy_indicator0.value] = gene_calculator(dataframe, self.buy_indicator0.value) + dataframe[self.buy_crossed_indicator0.value] = gene_calculator(dataframe, self.buy_crossed_indicator0.value) + dataframe[self.buy_indicator1.value] = gene_calculator(dataframe, self.buy_indicator1.value) + dataframe[self.buy_crossed_indicator1.value] = gene_calculator(dataframe, self.buy_crossed_indicator1.value) + dataframe[self.buy_indicator2.value] = gene_calculator(dataframe, self.buy_indicator2.value) + dataframe[self.buy_crossed_indicator2.value] = gene_calculator(dataframe, self.buy_crossed_indicator2.value) + + dataframe["cond0"] = dataframe[self.buy_indicator0.value].div(dataframe[self.buy_crossed_indicator0.value]) + dataframe["cond1"] = dataframe[self.buy_indicator1.value] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + self.buy_operator0.value, + self.buy_indicator0.value, + self.buy_crossed_indicator0.value, + self.buy_real_num0.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + self.buy_operator1.value, + self.buy_indicator1.value, + self.buy_crossed_indicator1.value, + self.buy_real_num1.value + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + (reduce(lambda x, y: x & y, conditions) + & (dataframe['sma20'].shift(self.buy_shift_bb_lowerband.value) < dataframe['sma20']) + & (dataframe['sma50'].shift(self.buy_shift_bb_lowerband.value) < dataframe['sma50']) + ), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # # TODO: Its not dry code! + # sell_indicator = self.sell_indicator0.value + # sell_crossed_indicator = self.sell_crossed_indicator0.value + # sell_operator = self.sell_operator0.value + # sell_real_num = self.sell_real_num0.value + # condition, dataframe = condition_generator( + # dataframe, + # sell_operator, + # sell_indicator, + # sell_crossed_indicator, + # sell_real_num + # ) + # conditions.append(condition) + # + # sell_indicator = self.sell_indicator1.value + # sell_crossed_indicator = self.sell_crossed_indicator1.value + # sell_operator = self.sell_operator1.value + # sell_real_num = self.sell_real_num1.value + # condition, dataframe = condition_generator( + # dataframe, + # sell_operator, + # sell_indicator, + # sell_crossed_indicator, + # sell_real_num + # ) + # conditions.append(condition) + # + # sell_indicator = self.sell_indicator2.value + # sell_crossed_indicator = self.sell_crossed_indicator2.value + # sell_operator = self.sell_operator2.value + # sell_real_num = self.sell_real_num2.value + # condition, dataframe = condition_generator( + # dataframe, + # sell_operator, + # sell_indicator, + # sell_crossed_indicator, + # sell_real_num + # ) + # conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + # print("sell pair=", self.wallets.get_all_balances()[metadata['pair']]) + + # if conditions: + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) & + # (dataframe['volume'] * dataframe['close'] / 1000 >= 100) + # # (dataframe['open'] < dataframe['sma10']) + # ), + # 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD3_5.json b/GodStraJD3_5.json new file mode 100644 index 0000000..8debc36 --- /dev/null +++ b/GodStraJD3_5.json @@ -0,0 +1,26 @@ +{ + "strategy_name": "GodStraJD3_5", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 0.7, + "buy_real_num1": 0.48, + "buy_real_num2": 0.67 + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-14 20:24:56.873912+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_5.py b/GodStraJD3_5.py new file mode 100644 index 0000000..665c2d0 --- /dev/null +++ b/GodStraJD3_5.py @@ -0,0 +1,618 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + return condition, dataframe + + +class GodStraJD3_5(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + # 'min': {'color': 'white'}, + # 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + # "percent": { + # "percent": {'color': 'green'}, + # "percent3": {'color': 'blue'}, + # "percent5": {'color': 'red'} + # } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + # + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit >= 0) & (last_candle['percent3'] < -0.01): + return "quick_lost" + + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).days >= 3) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'old_sma10' + + if (current_profit > -0.01) \ + & ((current_time - trade.open_date_utc).days >= 6) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'very_old_sma10' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + dataframe["q_0.1"] = dataframe.quantile(.1) + dataframe["q_0.25"] = dataframe.quantile(.25) + dataframe["q_0.33"] = dataframe.quantile(.33) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value + ) + conditions.append(condition1) + # # backup + # condition2, dataframe = condition_generator( + # dataframe, + # buy_operator1, + # buy_indicator1, + # buy_crossed_indicator1, + # self.buy_real_num1.value + # ) + # conditions.append(condition2) + # + # condition3, dataframe = condition_generator( + # dataframe, + # buy_operator2, + # buy_indicator2, + # buy_crossed_indicator2, + # self.buy_real_num2.value + # ) + # conditions.append(condition3) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + & (dataframe['bb_width'] > 0.035) + # ) | ( + # (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent20'] < -0.01) + # & (dataframe['percent3'] > 0) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # + # ) | ( + # (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'].shift(1) < -0.01) + # & (dataframe['percent3'].shift(1) > 0) + # & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1)) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # # & (dataframe['pente5'].shift(1) > 0) + ), 'buy'] = 1 + + pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + pandas.set_option('display.max_columns', 30) + + # print(reduce(lambda x, y: x & y, conditions)) + # print(reduce(lambda x, y: x & y, condition1), " ", + # reduce(lambda x, y: x & y, condition2), " ", + # reduce(lambda x, y: x & y, condition3), " ", + # # (reduce(lambda x, y: x & y, conditions)) + # dataframe['buy'], + # + # ) + + # if conditions: + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + # # & (dataframe['percent5'] < 0.025) + # # (dataframe['percent10'] < 0.04) + # # ) | ( + # # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + # # & (dataframe['percent50'] < -0.06) + # # & (dataframe['percent3'] > 0) + # # # & (dataframe['sma10'].shift(12) > dataframe['sma10'].shift(2)) + # # & (dataframe['sma10'].shift(2) > dataframe['sma10'].shift(1)) + # # & (dataframe['sma10'].shift(1) < dataframe['sma10']) + # # # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # ) + # #(dataframe['percent3'] > 0)) + # ,'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_5_1.json b/GodStraJD3_5_1.json new file mode 100644 index 0000000..33376f1 --- /dev/null +++ b/GodStraJD3_5_1.json @@ -0,0 +1,41 @@ +{ + "strategy_name": "GodStraJD3_5_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1 + }, + "buy": { + "buy_real_num0": 0.46, + "buy_real_num1": 0.48, + "buy_real_num2": 0.67, + "profit_no_change": true, + "profit_old_sma10": true, + "profit_over_rsi": true, + "profit_quick_gain": true, + "profit_quick_gain_3": true, + "profit_short_loss": true, + "profit_sma10": true, + "profit_sma20": true, + "profit_very_old_sma10": true + }, + "sell": {}, + "protection": { + "lookback": 155, + "protection_max_allowed_dd": 0.15, + "protection_stop": 240, + "protection_stoploss_stop": 73, + "trade_limit": 3 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.243, + "trailing_stop_positive_offset": 0.306, + "trailing_only_offset_is_reached": true + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-29 13:25:27.974545+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_5_1.jsonDECREASE b/GodStraJD3_5_1.jsonDECREASE new file mode 100644 index 0000000..b686937 --- /dev/null +++ b/GodStraJD3_5_1.jsonDECREASE @@ -0,0 +1,32 @@ +{ + "strategy_name": "GodStraJD3_5_1", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 1.0, + "buy_real_num1": 0.11, + "buy_real_num2": 0.47 + }, + "sell": {}, + "protection": { + "lookback": 156, + "protection_max_allowed_dd": 0.56, + "protection_stop": 62, + "protection_stoploss_stop": 46, + "trade_limit": 6 + }, + "stoploss": { + "stoploss": -0.288 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-27 20:28:08.774453+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_5_1.py b/GodStraJD3_5_1.py new file mode 100644 index 0000000..aeacf67 --- /dev/null +++ b/GodStraJD3_5_1.py @@ -0,0 +1,577 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_5_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Ind1": { + buy_indicator1: {'color': 'yellow'}, + buy_crossed_indicator1: {'color': 'pink'} + }, + "Ind2": { + buy_indicator2: {'color': 'cyan'}, + buy_crossed_indicator2: {'color': 'blue'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy') + buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(0, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + lookback = IntParameter(0, 200, default=48, space='protection') + trade_limit = IntParameter(0, 10, default=2, space='protection') + + profit_no_change = BooleanParameter(default=True, space="buy") + profit_sma10 = BooleanParameter(default=True, space="buy") + profit_sma20 = BooleanParameter(default=True, space="buy") + profit_quick_gain = BooleanParameter(default=True, space="buy") + profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + profit_old_sma10 = BooleanParameter(default=True, space="buy") + profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + profit_over_rsi = BooleanParameter(default=True, space="buy") + profit_short_loss = BooleanParameter(default=True, space="buy") + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if self.profit_no_change.value: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_old_sma10.value: + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).days >= 3) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'old_sma10' + if self.profit_very_old_sma10.value: + if (current_profit > -0.01) \ + & ((current_time - trade.open_date_utc).days >= 6) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + buy_operator1, + buy_indicator1, + buy_crossed_indicator1, + self.buy_real_num1.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + buy_operator2, + buy_indicator2, + buy_crossed_indicator2, + self.buy_real_num2.value + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + # # & (dataframe['percent5'] < 0.025) + # # (dataframe['percent10'] < 0.04) + # ) | ( + (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + & ((dataframe['percent20'].shift(5) < -0.025) | (dataframe['percent20'].shift(10) < -0.025)) + & ((dataframe['percent5'] > 0.001) | (dataframe['open'] < dataframe['bb_lowerband'])) + & (dataframe['sma10'].shift(1) < dataframe['sma10']) + # & (dataframe['open'].shift(50) > dataframe['open']) + ) + #(dataframe['percent3'] > 0)) + ,'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_5_2.json b/GodStraJD3_5_2.json new file mode 100644 index 0000000..4197794 --- /dev/null +++ b/GodStraJD3_5_2.json @@ -0,0 +1,30 @@ +{ + "strategy_name": "GodStraJD3_5_2", + "params": { + "roi": { + "0": 1 + }, + "stoploss": { + "stoploss": -1 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.344, + "trailing_stop_positive_offset": 0.354, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 0.46, + "buy_real_num1": 0.48, + "buy_real_num2": 0.67 + }, + "sell": { + "sell_real_num0": 0.11, + "sell_real_num1": 0.78, + "sell_real_num2": 0.36 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-20 02:01:29.086955+00:00" +} diff --git a/GodStraJD3_5_2.jsonBest b/GodStraJD3_5_2.jsonBest new file mode 100644 index 0000000..3b58dd3 --- /dev/null +++ b/GodStraJD3_5_2.jsonBest @@ -0,0 +1,30 @@ +{ + "strategy_name": "GodStraJD3_5_2", + "params": { + "roi": { + "0": 1 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.344, + "trailing_stop_positive_offset": 0.354, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 0.46, + "buy_real_num1": 0.48, + "buy_real_num2": 0.67 + }, + "sell": { + "sell_real_num0": 0.11, + "sell_real_num1": 0.78, + "sell_real_num2": 0.36 + }, + "protection": {}, + "stoploss": { + "stoploss": -0.02 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-20 01:13:41.941514+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_5_2.py b/GodStraJD3_5_2.py new file mode 100644 index 0000000..70dfb8e --- /dev/null +++ b/GodStraJD3_5_2.py @@ -0,0 +1,628 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_5_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Ind1": { + buy_indicator1: {'color': 'yellow'}, + buy_crossed_indicator1: {'color': 'pink'} + }, + "Ind2": { + buy_indicator2: {'color': 'cyan'}, + buy_crossed_indicator2: {'color': 'blue'}, + }, + "Sell0": { + sell_crossed_indicator0: {'color': 'green'}, + sell_indicator0: {'color': 'red'} + }, + "Sell1": { + sell_indicator1: {'color': 'yellow'}, + sell_crossed_indicator1: {'color': 'pink'} + }, + "Sell2": { + sell_indicator2: {'color': 'cyan'}, + sell_crossed_indicator2: {'color': 'blue'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy') + buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy') + + sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell') + sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell') + sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell') + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 12 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 2, + "stop_duration_candles": 48, + "max_allowed_drawdown": 0.04, + "only_per_pair": False + }, + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0.015) & (last_candle['percent'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + if (current_profit > 0.01) & (last_candle['rsi'] < 20): + return "small_rsi" + if (current_profit > 0.005) & (last_candle['percent3'] < -0.01): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'quick_lost' + if (current_profit < -0.02) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "stop_loss_1h" + + if (current_profit > 0.005) & (last_candle['percent5'] < -0.015): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'very_quick_lost' + + # if (current_profit > 0.01) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + # | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10' + # + # if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma20'] > last_candle['sma20']) & + # ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma20' + # + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if (current_profit > 0) \ + & (previous_last_candle['rsi'] > 88) \ + & ((last_candle['percent'] < - current_profit / 3) | (last_candle['percent3'] < - current_profit / 3)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + # & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'short_lost' + + #if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe[sell_crossed_indicator0] = gene_calculator(dataframe, sell_crossed_indicator0) + dataframe[sell_crossed_indicator1] = gene_calculator(dataframe, sell_crossed_indicator1) + dataframe[sell_crossed_indicator2] = gene_calculator(dataframe, sell_crossed_indicator2) + + dataframe[sell_indicator0] = gene_calculator(dataframe, sell_indicator0) + dataframe[sell_indicator1] = gene_calculator(dataframe, sell_indicator1) + dataframe[sell_indicator2] = gene_calculator(dataframe, sell_indicator2) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + buy_operator1, + buy_indicator1, + buy_crossed_indicator1, + self.buy_real_num1.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + buy_operator2, + buy_indicator2, + buy_crossed_indicator2, + self.buy_real_num2.value + ) + conditions.append(condition) + + # condition_1 = ( + # reduce(lambda x, y: x & y, conditions) & + # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & + # (dataframe['open'] < dataframe['sma20']) + # ) + # condition_2 = ( + # (dataframe['bb_width'] > 0.11) & + # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & + # (dataframe['rsi'].shift(1) < 20) & + # (dataframe['open'] < dataframe['sma20']) + # ) + # if (condition_1): + # dataframe.loc[condition_1, 'buy'] = 'buy_opt' + # if (condition_2): + # dataframe.loc[condition_2, 'buy'] = 'bb_width' + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) & + (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & + (dataframe['close'] < dataframe['sma20']) & + (dataframe['close'] < dataframe['sma50']) & + (dataframe['close'] * 0.99 < dataframe['bb_lowerband']) + ) | ( + (dataframe['close'] < dataframe['bb_lowerband']) & + (dataframe['bb_width'] > 0.11) & + (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & + (dataframe['rsi'] < 30) & + (dataframe['close'] < dataframe['sma20']) & + (dataframe['sma100'].shift(30) < dataframe['sma100']) + ),'buy']=1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + sell_operator0, + sell_indicator0, + sell_crossed_indicator0, + self.sell_real_num0.value + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + sell_operator1, + sell_indicator1, + sell_crossed_indicator1, + self.sell_real_num1.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + sell_operator2, + sell_indicator2, + sell_crossed_indicator2, + self.sell_real_num2.value + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + diff --git a/GodStraJD3_5_3.json b/GodStraJD3_5_3.json new file mode 100644 index 0000000..dbcf049 --- /dev/null +++ b/GodStraJD3_5_3.json @@ -0,0 +1,29 @@ +{ + "strategy_name": "GodStraJD3_5_3", + "params": { + "roi": { + "0": 1 + }, + "stoploss": { + "stoploss": -0.02 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.344, + "trailing_stop_positive_offset": 0.354, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_sma_max": 0.98, + "buy_sma_min": -1.52 + }, + "sell": { + "sell_real_num0": 0.51, + "sell_real_num1": 0.85, + "sell_real_num2": 0.0 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-20 17:43:05.699962+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_5_3.py b/GodStraJD3_5_3.py new file mode 100644 index 0000000..0aa4442 --- /dev/null +++ b/GodStraJD3_5_3.py @@ -0,0 +1,609 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_5_3(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Ind1": { + buy_indicator1: {'color': 'yellow'}, + buy_crossed_indicator1: {'color': 'pink'} + }, + "Ind2": { + buy_indicator2: {'color': 'cyan'}, + buy_crossed_indicator2: {'color': 'blue'}, + }, + "Sell0": { + sell_crossed_indicator0: {'color': 'green'}, + sell_indicator0: {'color': 'red'} + }, + "Sell1": { + sell_indicator1: {'color': 'yellow'}, + sell_crossed_indicator1: {'color': 'pink'} + }, + "Sell2": { + sell_indicator2: {'color': 'cyan'}, + sell_crossed_indicator2: {'color': 'blue'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + + buy_real_num0 = 0.46 + buy_real_num1 = 0.48 + buy_real_num2 = 0.67 + #buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy') + #buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy') + #buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy') + + sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell') + sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell') + sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell') + + # buy_bb_width = DecimalParameter(0, 0.2, decimals=3, default=0.12, space='buy') + # buy_bb_min = IntParameter(-30, 50, default=50, space='buy') + + buy_sma_min = DecimalParameter(-2, 2, decimals=2, default=0, space='buy') + buy_sma_max = DecimalParameter(-2, 2, decimals=2, default=0.5, space='buy') + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 2, + "stop_duration_candles": 72, + "max_allowed_drawdown": 0.04, + "only_per_pair": False + }, + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + #if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + # return "no_change" + if (current_profit > 0.01) & (last_candle['rsi'] < 20): + return "small_rsi" + # if (current_profit > 0.01) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + # | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10' + # + # if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma20'] > last_candle['sma20']) & + # ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma20' + # + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + # & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'short_lost' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe[sell_crossed_indicator0] = gene_calculator(dataframe, sell_crossed_indicator0) + dataframe[sell_crossed_indicator1] = gene_calculator(dataframe, sell_crossed_indicator1) + dataframe[sell_crossed_indicator2] = gene_calculator(dataframe, sell_crossed_indicator2) + + dataframe[sell_indicator0] = gene_calculator(dataframe, sell_indicator0) + dataframe[sell_indicator1] = gene_calculator(dataframe, sell_indicator1) + dataframe[sell_indicator2] = gene_calculator(dataframe, sell_indicator2) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + #self.buy_real_num0.value + self.buy_real_num0 + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + buy_operator1, + buy_indicator1, + buy_crossed_indicator1, + #self.buy_real_num1.value + self.buy_real_num1 + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + buy_operator2, + buy_indicator2, + buy_crossed_indicator2, + #self.buy_real_num2.value + self.buy_real_num2 + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) & + (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) & + # ((100 * ((dataframe['sma100'] - dataframe['sma100'].shift(10)) / dataframe['sma100'])) >= self.buy_sma_min.value) & + # ((100 * ((dataframe['sma100'] - dataframe['sma100'].shift(10)) / dataframe['sma100'])) <= self.buy_sma_max.value) & + (dataframe['close'] < dataframe['sma20']) + ),'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + sell_operator0, + sell_indicator0, + sell_crossed_indicator0, + self.sell_real_num0.value + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + sell_operator1, + sell_indicator1, + sell_crossed_indicator1, + self.sell_real_num1.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + sell_operator2, + sell_indicator2, + sell_crossed_indicator2, + self.sell_real_num2.value + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) # (dataframe['open'] < dataframe['sma10']) + ), + 'sell']=1 + return dataframe + diff --git a/GodStraJD3_6.json b/GodStraJD3_6.json new file mode 100644 index 0000000..2cb855e --- /dev/null +++ b/GodStraJD3_6.json @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_6", + "params": { + "roi": { + "0": 1 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "CDLTHRUSTING-20", + "buy_crossed_indicator1": "MACDEXT-0-20", + "buy_crossed_indicator2": "CDLXSIDEGAP3METHODS-50", + "buy_indicator0": "MIDPOINT-5", + "buy_indicator1": "RSI-20", + "buy_indicator2": "CDLSHORTLINE-5", + "buy_operator0": "/>R", + "buy_operator1": "", + "sell_operator2": "CB", + "sell_real_num0": 0.4, + "sell_real_num1": 0.7, + "sell_real_num2": 0.8 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-15 13:33:08.407372+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_6.py b/GodStraJD3_6.py new file mode 100644 index 0000000..b9a1277 --- /dev/null +++ b/GodStraJD3_6.py @@ -0,0 +1,956 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +timeperiods = [5, 10, 20, 50, 100] + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_6(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind": { + 'MA-20': {'color': 'green'}, + 'STOCH-1-10': {'color': 'blue'}, + 'CDLDRAGONFLYDOJI-5': {'color': 'red'} + }, + "Ind2": { + 'MINUS_DM-5': {'color': 'green'}, + 'DX-5': {'color': 'blue'}, + 'LINEARREG-50': {'color': 'red'} + }, + "Profit": { + 'profit': {'color': 'pink'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.065: + # # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.045: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + # def custom_sell(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() + # previous_last_candle = dataframe.iloc[-2].squeeze() + # previous_5_candle = dataframe.iloc[-5].squeeze() + # #print("last_candle", last_candle) + # #print("previous_last_candle", previous_last_candle) + # + # #dataframe.iloc[-1]['profit'] = current_profit + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # # print("count=", count) + # + # # (last_candle['percent5'] < -0.005) \ + # # if (0 < current_profit < 0.005) \ + # # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # # last_candle['percent5']) + # # return 'too_small_gain' + # + # # if (current_profit < -0.05) \ + # # & ((current_time - trade.open_date_utc).days >= 3): + # # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'stop_loss_profit' + # + # # if (current_profit > 0.02) \ + # # & (last_candle['percent'] < 0.01) \ + # # & ((current_time - trade.open_date_utc).seconds >= 3600): + # # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'lost_half_profit' + # + # # ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + # if (current_profit > 0) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) | (last_candle['percent3'] < -0.01)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_bb_band_sma10_desc' + # + # # if (current_profit > 0) \ + # # & (last_candle['percent'] < -0.02): + # # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'stop_percent_loss' + # + # #if (current_profit > 0) \ + # # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + # # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # # & (last_candle['percent'] < 0): + # # print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'over_bb_band_sma20_desc' + # + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi' + # + # # description trade + # # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # # print(last_candle) + # #if 0.015 < current_profit < 0.03: + # # if (last_candle['percent3'] < -0.005 ): + # # # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + # # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'profit_percent3' + # + # # + # # if (0 < current_profit < 0.1) \ + # # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # # & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + # # print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # # return 'profit_5h_sma20_desc' + # + # # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # # "count=", count, "max=", self.config['max_open_trades']) + # # return 'stop_short_loss' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + dataframe['MINUS_DM-5'] = gene_calculator(dataframe, 'MINUS_DM-5') + dataframe['LINEARREG-50'] = gene_calculator(dataframe, 'LINEARREG-50') + dataframe['MA-20'] = gene_calculator(dataframe, 'MA-20') + + dataframe['STOCH-1-10'] = gene_calculator(dataframe, 'STOCH-1-10') + dataframe['CDLDRAGONFLYDOJI-5'] = gene_calculator(dataframe, 'CDLDRAGONFLYDOJI-5') + dataframe['DX-5'] = gene_calculator(dataframe, 'DX-5') + + # dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5) + # dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50) + # dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20) + # stoch = ta.STOCH(dataframe, timeperiod=10) + # # print(stoch) + # dataframe['STOCH-1-10'] = stoch['slowd'] + # dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5) + + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['bb_lowerband']) + # & (dataframe['bb_width'] >= 0.045) + # & (dataframe['volume'] * dataframe['close'] / 1000 > 100) + # ) | + (reduce(lambda x, y: x & y, conditions)), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + # print("sell pair=", self.wallets.get_all_balances()[metadata['pair']]) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) & + (dataframe['volume'] * dataframe['close'] / 1000 >= 100) + # (dataframe['open'] < dataframe['sma10']) + ), + 'sell']=1 + return dataframe diff --git a/GodStraJD3_6_53.json b/GodStraJD3_6_53.json new file mode 100644 index 0000000..abd47b8 --- /dev/null +++ b/GodStraJD3_6_53.json @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_6_53", + "params": { + "roi": { + "0": 1 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "HT_TRENDLINE-100", + "buy_crossed_indicator1": "MACD-1-100", + "buy_crossed_indicator2": "CCI-20", + "buy_indicator0": "CDLDOJISTAR-10", + "buy_indicator1": "WCLPRICE-10", + "buy_indicator2": "DEMA-50", + "buy_operator0": "/>R", + "buy_operator1": "R", + "sell_operator2": ">", + "sell_real_num0": 0.1, + "sell_real_num1": 0.8, + "sell_real_num2": 1.0 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-01 22:59:30.762086+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_6_53.jsonOLD b/GodStraJD3_6_53.jsonOLD new file mode 100644 index 0000000..8b6205a --- /dev/null +++ b/GodStraJD3_6_53.jsonOLD @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_6_53", + "params": { + "roi": { + "0": 1 + }, + "stoploss": { + "stoploss": -2.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "HT_TRENDLINE-100", + "buy_crossed_indicator1": "MACD-1-100", + "buy_crossed_indicator2": "CCI-20", + "buy_indicator0": "CDLDOJISTAR-10", + "buy_indicator1": "WCLPRICE-10", + "buy_indicator2": "DEMA-50", + "buy_operator0": "/>R", + "buy_operator1": "R", + "sell_real_num0": 0.1, + "sell_real_num1": 0.8, + "sell_real_num2": 0.9 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-15 13:26:31.727849+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_6_53.py b/GodStraJD3_6_53.py new file mode 100644 index 0000000..9334487 --- /dev/null +++ b/GodStraJD3_6_53.py @@ -0,0 +1,973 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy, SellCheckTuple +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +timeperiods = [5, 10, 20, 50, 100] + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_6_53(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + # 'min': {'color': 'white'}, + # 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + # "BB": { + # 'bb_width': {'color': 'white'}, + # 'bb_min': {'color': 'red'}, + # }, + # "Ind": { + # ind_1: {'color': 'green'}, + # ind_2: {'color': 'blue'}, + # ind_3: {'color': 'red'} + # }, + # "Ind2": { + # ind_4: {'color': 'green'}, + # ind_5: {'color': 'blue'}, + # ind_6: {'color': 'red'} + # }, + "Pentes": { + 'pente5': {'color': 'green'}, + 'pente10': {'color': 'pink'}, + 'pente20': {'color': 'green'}, + 'pente50': {'color': 'yellow'} + }, + # "Rsi": { + # 'rsi': {'color': 'pink'}, + # }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "percent10": {'color': 'green'}, + "percent20": {'color': 'red'}, + "percent50": {'color': 'pink'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/= 0) & \ + ( + (last_candle['percent3'] < -0.01) | + ((last_candle['percent'] < -0.01) & (previous_last_candle['rsi'] > 72)) + ): + return "quick_lost" + + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + return "no_change" + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).days >= 3) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'old_sma10' + + if (current_profit > -0.01) \ + & ((current_time - trade.open_date_utc).days >= 6) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'very_old_sma10' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + + dataframe[ind_1] = gene_calculator(dataframe, ind_1) + dataframe[ind_2] = gene_calculator(dataframe, ind_2) + dataframe[ind_3] = gene_calculator(dataframe, ind_3) + + dataframe[ind_4] = gene_calculator(dataframe, ind_4) + dataframe[ind_5] = gene_calculator(dataframe, ind_5) + dataframe[ind_6] = gene_calculator(dataframe, ind_6) + + dataframe[sell_1] = gene_calculator(dataframe, sell_1) + dataframe[sell_2] = gene_calculator(dataframe, sell_2) + dataframe[sell_3] = gene_calculator(dataframe, sell_3) + + dataframe[sell_4] = gene_calculator(dataframe, sell_4) + dataframe[sell_5] = gene_calculator(dataframe, sell_5) + dataframe[sell_6] = gene_calculator(dataframe, sell_6) + + # dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5) + # dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50) + # dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20) + # stoch = ta.STOCH(dataframe, timeperiod=10) + # # print(stoch) + # dataframe['STOCH-1-10'] = stoch['slowd'] + # dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5) + + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + dataframe['pente5'] = (100 * (dataframe["sma5"] - dataframe["sma5"].shift(1)) / dataframe["sma5"]) + dataframe['pente10'] = (100 * (dataframe["sma10"] - dataframe["sma10"].shift(1)) / dataframe["sma10"]) + dataframe['pente20'] = (100 * (dataframe["sma20"] - dataframe["sma20"].shift(1)) / dataframe["sma20"]) + dataframe['pente50'] = (100 * (dataframe["sma50"] - dataframe["sma50"].shift(1)) / dataframe["sma50"]) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition1, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition1) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition2, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition2) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition3, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition3) + + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + ) | ( + (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['percent20'].shift(10) < -0.03) + & (dataframe['pente10'].shift(5) < 0) + & (dataframe['pente10'] > 0) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + # ) | ( + # (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent20'].shift(5) < -0.01) + # & (dataframe['percent3'] > 0) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # # & (dataframe['pente5'] > 0) + # + # ) | ( + # (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'].shift(6) < -0.01) + # & (dataframe['percent3'].shift(1) > 0) + # & (dataframe['open'].shift(1) < dataframe['sma10'].shift(1)) + # & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1)) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # # & (dataframe['pente5'].shift(1) > 0) + ), + 'buy']=1 + # print(len(dataframe.keys())) + + # print( + # reduce(lambda x, y: x & y, condition1), " ", + # reduce(lambda x, y: x & y, condition2), " ", + # reduce(lambda x, y: x & y, condition3), " ", + # # (reduce(lambda x, y: x & y, conditions)) + # dataframe['buy'], + # ) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + # print("sell pair=", self.wallets.get_all_balances()[metadata['pair']]) + + # if conditions: + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) #(dataframe['percent3'] > 0) + # ), + # 'sell']=1 + return dataframe + diff --git a/GodStraJD3_6_53_1.json b/GodStraJD3_6_53_1.json new file mode 100644 index 0000000..f2c9986 --- /dev/null +++ b/GodStraJD3_6_53_1.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD3_6_53_1", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_crossed_indicator0": "HT_TRENDLINE-100", + "buy_crossed_indicator1": "MACD-1-100", + "buy_crossed_indicator2": "CCI-20", + "buy_indicator0": "CDLDOJISTAR-10", + "buy_indicator1": "WCLPRICE-10", + "buy_indicator2": "DEMA-50", + "buy_operator0": "/>R", + "buy_operator1": "R", + "sell_operator2": ">", + "sell_real_num0": 0.1, + "sell_real_num1": 0.8, + "sell_real_num2": 1.0 + }, + "protection": { + "protection_max_allowed_dd": 0.36, + "protection_stop": 25 + }, + "stoploss": { + "stoploss": -0.189 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-23 14:20:28.600763+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_6_53_1.py b/GodStraJD3_6_53_1.py new file mode 100644 index 0000000..4a4a5b2 --- /dev/null +++ b/GodStraJD3_6_53_1.py @@ -0,0 +1,920 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy, SellCheckTuple +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +timeperiods = [5, 10, 20, 50, 100] + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_6_53_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 1, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind": { + ind_1: {'color': 'green'}, + ind_2: {'color': 'blue'}, + ind_3: {'color': 'red'} + }, + "Ind2": { + ind_4: {'color': 'green'}, + ind_5: {'color': 'blue'}, + ind_6: {'color': 'red'} + }, + "Profit": { + 'profit': {'color': 'pink'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'].shift(2) < dataframe['bb_lowerband'].shift(2)) + & (dataframe['bb_width'].shift(2) >= 0.12) + & (dataframe['volume'].shift(2) * dataframe['close'].shift(2) / 1000 > 100) + ) | ( + (reduce(lambda x, y: x & y, conditions)) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + & (dataframe['close'] < dataframe['sma20']) + & (dataframe['close'] < dataframe['sma50']) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # (dataframe['close'] * 0.99 < dataframe['bb_lowerband']) + # (dataframe['rsi'] < 45) + ), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + # count = 0 + # for coin, balance in self.wallets.get_all_balances().items(): + # count = count + 1 + # # print(coin, " ", balance) + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + # print("sell pair=", self.wallets.get_all_balances()[metadata['pair']]) + + # if conditions: + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) #(dataframe['percent3'] > 0) + # # | (dataframe['percent3'] < -0.03) + # ), + # 'sell']=1 + + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + + return dataframe + diff --git a/GodStraJD3_6_53_2.json b/GodStraJD3_6_53_2.json new file mode 100644 index 0000000..b1cb738 --- /dev/null +++ b/GodStraJD3_6_53_2.json @@ -0,0 +1,29 @@ +{ + "strategy_name": "GodStraJD3_6_53_2", + "params": { + "roi": { + "0": 2 + }, + "stoploss": { + "stoploss": -0.02 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 0.87, + "buy_real_num1": 0.33, + "buy_real_num2": 0.89 + }, + "sell": {}, + "protection": { + "protection_max_allowed_dd": 0.04, + "protection_stop": 288 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-01-23 13:16:55.016896+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_6_53_2.py b/GodStraJD3_6_53_2.py new file mode 100644 index 0000000..1f1ce32 --- /dev/null +++ b/GodStraJD3_6_53_2.py @@ -0,0 +1,520 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_6_53_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 2, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Ind1": { + buy_indicator1: {'color': 'yellow'}, + buy_crossed_indicator1: {'color': 'pink'} + }, + "Ind2": { + buy_indicator2: {'color': 'cyan'}, + buy_crossed_indicator2: {'color': 'blue'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy') + buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(0, 100, default=48, space='protection') + + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 2, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if (current_profit > 0.01) \ + & ((previous_5_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < -0.01) | (last_candle['percent20'] < -0.01))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).days >= 3) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.0105)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'old_sma10' + + if (current_profit > -0.01) \ + & ((current_time - trade.open_date_utc).days >= 6) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | ( + last_candle['percent5'] < 0)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'very_old_sma10' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value + ) + conditions.append(condition) + + # backup + condition, dataframe = condition_generator( + dataframe, + buy_operator1, + buy_indicator1, + buy_crossed_indicator1, + self.buy_real_num1.value + ) + conditions.append(condition) + + condition, dataframe = condition_generator( + dataframe, + buy_operator2, + buy_indicator2, + buy_crossed_indicator2, + self.buy_real_num2.value + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) & + (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # (dataframe['rsi'] < 45) + ), + 'buy'] = 1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/GodStraJD3_7.json b/GodStraJD3_7.json new file mode 100644 index 0000000..68b0b51 --- /dev/null +++ b/GodStraJD3_7.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "GodStraJD3_7", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "profit_no_change": false, + "profit_old_sma10": false, + "profit_over_rsi": true, + "profit_quick_gain": false, + "profit_quick_gain_3": false, + "profit_quick_lost": true, + "profit_short_loss": true, + "profit_sma10": false, + "profit_sma20": true, + "profit_very_old_sma10": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-04 20:21:28.189888+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7.py b/GodStraJD3_7.py new file mode 100644 index 0000000..418fed3 --- /dev/null +++ b/GodStraJD3_7.py @@ -0,0 +1,636 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + return condition, dataframe + + +class GodStraJD3_7(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + # 'min': {'color': 'white'}, + # 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + # "percent": { + # "percent": {'color': 'green'}, + # "percent3": {'color': 'blue'}, + # "percent5": {'color': 'red'} + # } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + # buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + profit_no_change = BooleanParameter(default=True, space="buy") + profit_quick_lost = BooleanParameter(default=True, space="buy") + profit_sma10 = BooleanParameter(default=True, space="buy") + profit_sma20 = BooleanParameter(default=True, space="buy") + profit_quick_gain = BooleanParameter(default=True, space="buy") + profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + profit_old_sma10 = BooleanParameter(default=True, space="buy") + profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + profit_over_rsi = BooleanParameter(default=True, space="buy") + profit_short_loss = BooleanParameter(default=True, space="buy") + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + # + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if self.profit_quick_lost.value: + if (current_profit >= 0) & (last_candle['percent3'] < -0.01): + return "quick_lost" + + if self.profit_no_change.value: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3.value: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain.value: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10.value: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10.value: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + 0.7 #self.buy_real_num0.value + ) + conditions.append(condition1) + + # # backup + # condition2, dataframe = condition_generator( + # dataframe, + # buy_operator1, + # buy_indicator1, + # buy_crossed_indicator1, + # self.buy_real_num1.value + # ) + # conditions.append(condition2) + # + # condition3, dataframe = condition_generator( + # dataframe, + # buy_operator2, + # buy_indicator2, + # buy_crossed_indicator2, + # self.buy_real_num2.value + # ) + # conditions.append(condition3) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + # ) | ( + # (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent20'] < -0.01) + # & (dataframe['percent3'] > 0) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # + # ) | ( + # (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'].shift(1) < -0.01) + # & (dataframe['percent3'].shift(1) > 0) + # & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1)) + # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # # & (dataframe['pente5'].shift(1) > 0) + ), 'buy'] = 1 + + pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + pandas.set_option('display.max_columns', 30) + # print(condition1) + + # print(reduce(lambda x, y: x & y, conditions)) + # print(reduce(lambda x, y: x & y, condition1), " ", + # reduce(lambda x, y: x & y, condition2), " ", + # reduce(lambda x, y: x & y, condition3), " ", + # # (reduce(lambda x, y: x & y, conditions)) + # dataframe['buy'], + # + # ) + + # if conditions: + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + # # & (dataframe['percent5'] < 0.025) + # # (dataframe['percent10'] < 0.04) + # # ) | ( + # # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) + # # & (dataframe['percent50'] < -0.06) + # # & (dataframe['percent3'] > 0) + # # # & (dataframe['sma10'].shift(12) > dataframe['sma10'].shift(2)) + # # & (dataframe['sma10'].shift(2) > dataframe['sma10'].shift(1)) + # # & (dataframe['sma10'].shift(1) < dataframe['sma10']) + # # # & (dataframe['sma100'].shift(1) < dataframe['sma100']) + # ) + # #(dataframe['percent3'] > 0)) + # ,'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_1.json b/GodStraJD3_7_1.json new file mode 100644 index 0000000..a6054d0 --- /dev/null +++ b/GodStraJD3_7_1.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "GodStraJD3_7_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_real_num0": 0.5, + "buy_signal_bb_width": 0.029 + }, + "sell": {}, + "protection": { + "lookback": 124, + "protection_max_allowed_dd": 0.85, + "protection_stop": 26, + "protection_stoploss_stop": 91, + "trade_limit": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-18 23:22:31.726399+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_1.py b/GodStraJD3_7_1.py new file mode 100644 index 0000000..5ce7d84 --- /dev/null +++ b/GodStraJD3_7_1.py @@ -0,0 +1,540 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator] > dataframe[crossed_indicator]) + elif operator == "=": + condition = (np.isclose(dataframe[indicator], dataframe[crossed_indicator])) + elif operator == "<": + condition = (dataframe[indicator] < dataframe[crossed_indicator]) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above(dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator], dataframe[crossed_indicator])) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) + elif operator == ">R": + condition = (dataframe[indicator] > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator], real_num)) + elif operator == "R": + condition = (dataframe[indicator].div(dataframe[crossed_indicator]) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].div(dataframe[crossed_indicator]), real_num)) + elif operator == "/ dataframe[indicator_trend_sma]) + elif operator == "DT": + condition = (dataframe[indicator] < dataframe[indicator_trend_sma]) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator], dataframe[indicator_trend_sma]) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator], dataframe[indicator_trend_sma]) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator], dataframe[indicator_trend_sma]) + ) | + ( + qtpylib.crossed_above(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + ) & + ( + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + # 'min': {'color': 'white'}, + # 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + "Ind0": { + buy_crossed_indicator0: {'color': 'green'}, + buy_indicator0: {'color': 'red'} + }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + # "percent": { + # "percent": {'color': 'green'}, + # "percent3": {'color': 'blue'}, + # "percent5": {'color': 'red'} + # } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + # buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = True + profit_short_loss = True + profit_sma10 = False + profit_sma20 = True + profit_very_old_sma10 = False + + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + buy_signal_bb_width = DecimalParameter(0, 0.15, decimals=3, default=0.05, space='buy') + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.01): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value + ) + conditions.append(condition1) + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min50']) + & (dataframe['bb_width'] > self.buy_signal_bb_width.value) + ), 'buy'] = 1 + + pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + pandas.set_option('display.max_columns', 30) + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_2.json b/GodStraJD3_7_2.json new file mode 100644 index 0000000..82321f2 --- /dev/null +++ b/GodStraJD3_7_2.json @@ -0,0 +1,32 @@ +{ + "strategy_name": "GodStraJD3_7_2", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.042, + "trailing_stop_positive_offset": 0.119, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage0": 6, + "buy_real_num0": 0.9, + "buy_signal_bb_width": 0.0 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + }, + "roi": { + "0": 2 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-07 17:59:59.847942+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_2.py b/GodStraJD3_7_2.py new file mode 100644 index 0000000..c7edeae --- /dev/null +++ b/GodStraJD3_7_2.py @@ -0,0 +1,606 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'ecart_20': {'color': 'red'}, + 'ecart_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + # buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = False + profit_sma20 = True + profit_very_old_sma10 = False + + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + buy_signal_bb_width = DecimalParameter(0, 0.15, decimals=2, default=0.05, space='buy') + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_decalage0 = IntParameter(1, 10, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5) \ + & ((current_time - trade.open_date_utc).days < 10) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10) \ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ( + (current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + # if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ( + (current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ( + (current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) \ + & (previous_last_candle['rsi'] > 88) & ( \ + (last_candle['percent'] < - current_profit / 3) | + (last_candle['percent3'] < - current_profit / 3)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + if False & (current_profit > 0) & (last_candle[ + 'rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if False & (current_profit > 0) & (previous_last_candle['rsi'] > 82) & ( + last_candle['percent'] < -0.02): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0) \ + & (( + current_time - trade.open_date_utc).days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=72) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + + if conditions: + for decalage in range(3, self.buy_decalage0.value): + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= -0.01) + # & (dataframe['min20'] == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + #  & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= -0.02) + # & (dataframe['min20'] == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 30) + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/GodStraJD3_7_3.json b/GodStraJD3_7_3.json new file mode 100644 index 0000000..92a69c1 --- /dev/null +++ b/GodStraJD3_7_3.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "GodStraJD3_7_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.15, + "trailing_stop_positive_offset": 0.2, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage0": 6, + "buy_real_num0": 0.9, + "buy_decalage2": 5, + "buy_real_num2": 1.5, + "buy_signal_bb_width": 0.06 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-25 21:24:08.672826+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_3.py b/GodStraJD3_7_3.py new file mode 100644 index 0000000..7ebb5f8 --- /dev/null +++ b/GodStraJD3_7_3.py @@ -0,0 +1,641 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_3(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'ecart_20': {'color': 'red'}, + 'ecart_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + # buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = False + profit_sma20 = True + profit_very_old_sma10 = False + + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_decalage0 = IntParameter(1, 10, default=5, space='buy') + + buy_real_num2 = DecimalParameter(1, 3, decimals=2, default=0.67, space='buy') + buy_decalage2 = IntParameter(1, 10, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=72) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + + conditions2 = list() + + condition2, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num2.value, + self.buy_decalage2.value + ) + conditions2.append(condition2) + + if conditions: + for decalage in range(3, self.buy_decalage0.value): + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= -0.01) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= 0.02) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= -0.02) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= 0.02) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # dataframe.loc[ + # ( + # (dataframe['cond1'].shift(decalage) <= 1.2) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + # & (dataframe['percent20'].shift(decalage) <= -0.065) + # & (dataframe['distance_min'] <= 0.01) + # ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + # if conditions2: + # for decalage in range(1, self.buy_decalage2.value): #self.buy_decalage.value): + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions2) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) < dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['bb_width'].shift(decalage) > self.buy_signal_bb_width.value) + # & (dataframe['percent20'].shift(decalage) <= -0.01) + # # & (dataframe['min20'] == dataframe['min50']) + # ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + + pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + pandas.set_option('display.max_columns', 30) + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_4.json b/GodStraJD3_7_4.json new file mode 100644 index 0000000..f7ad4db --- /dev/null +++ b/GodStraJD3_7_4.json @@ -0,0 +1,45 @@ +{ + "strategy_name": "GodStraJD3_7_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_distance": 0.04, + "buy_0_percent20": 0.02, + "buy_2": true, + "buy_2_distance": 0.02, + "buy_2_percent20": 0.08, + "buy_3": true, + "buy_3_distance": -0.06, + "buy_3_percent20": 0.1, + "buy_decalage0": 8, + "buy_decalage2": 8, + "buy_decalage3": 6, + "buy_decalage_deb_0": 3, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 3, + "buy_min_horizon": 83 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-08 17:38:42.327292+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_4.py b/GodStraJD3_7_4.py new file mode 100644 index 0000000..b68a2bc --- /dev/null +++ b/GodStraJD3_7_4.py @@ -0,0 +1,804 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_4(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'ecart_20': {'color': 'red'}, + 'ecart_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + # "buy_real_num0": 0.46, + # "buy_real_num1": 0.48, + # "buy_real_num2": 0.67 + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy') + # buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy') + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = False + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + # buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_decalage0 = IntParameter(1, 10, default=5, space='buy') + # # + # buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_decalage1 = IntParameter(1, 10, default=5, space='buy') + # + # buy_real_num2 = DecimalParameter(1, 3, decimals=2, default=0.67, space='buy') + # buy_decalage2 = IntParameter(1, 10, default=5, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_2 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy') + + buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + 0.9, #self.buy_real_num0.value, + 6 #self.buy_decalage0.value + ) + conditions.append(condition1) + + conditions2 = list() + + condition2, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + 1.5, #self.buy_real_num2.value, + 5 #self.buy_decalage2.value + ) + conditions2.append(condition2) + + if conditions: + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + if self.buy_0.value: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + # if conditions2: + # for decalage in range(1, self.buy_decalage2.value): #self.buy_decalage.value): + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions2) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) < dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['bb_width'].shift(decalage) > self.buy_signal_bb_width.value) + # & (dataframe['percent20'].shift(decalage) <= -0.01) + # # & (dataframe['min20'] == dataframe['min50']) + # ), ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5.json b/GodStraJD3_7_5.json new file mode 100644 index 0000000..30bf5d4 --- /dev/null +++ b/GodStraJD3_7_5.json @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_7_5", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_distance": 0.06, + "buy_0_percent20": 0.02, + "buy_2": true, + "buy_2_distance": 0.09, + "buy_2_percent20": 0.05, + "buy_3": true, + "buy_3_distance": 0.03, + "buy_3_percent20": 0.06, + "buy_decalage0": 7, + "buy_decalage2": 8, + "buy_decalage3": 6, + "buy_decalage_deb_0": 2, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 3, + "buy_min_horizon": 179, + "buy_real_num0": 0.82, + "buy_real_num1": 0.42, + "buy_real_num2": 0.21 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-09 00:06:48.822740+00:00" +} diff --git a/GodStraJD3_7_5.py b/GodStraJD3_7_5.py new file mode 100644 index 0000000..7c8014e --- /dev/null +++ b/GodStraJD3_7_5.py @@ -0,0 +1,764 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_2 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy') + + buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_1.json b/GodStraJD3_7_5_1.json new file mode 100644 index 0000000..a3fe3ed --- /dev/null +++ b/GodStraJD3_7_5_1.json @@ -0,0 +1,57 @@ +{ + "strategy_name": "GodStraJD3_7_5_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": false, + "buy_0_percent20": 0.07, + "buy_1_decalage": 8, + "buy_1_decalage_deb": 2, + "buy_1_distance": 0.03, + "buy_1_min": 1.09, + "buy_1_normal_var": 4.1, + "buy_1_real_num": 0.13, + "buy_1_volume": 94, + "buy_2": false, + "buy_2_decalage": 8, + "buy_2_decalage_deb": 1, + "buy_2_distance": 0.06, + "buy_2_min": 1.07, + "buy_2_normal_var": 2.1, + "buy_2_percent20": -0.08, + "buy_2_real_num": 0.96, + "buy_2_volume": 19, + "buy_3": true, + "buy_3_decalage": 8, + "buy_3_decalage_deb": 2, + "buy_3_distance": 0.06, + "buy_3_min": 1.01, + "buy_3_normal_var": 0.8, + "buy_3_percent20": 0.01, + "buy_3_real_num": 0.19, + "buy_3_volume": 32, + "buy_min_horizon": 139 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-17 11:40:13.234887+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_1.py b/GodStraJD3_7_5_1.py new file mode 100644 index 0000000..5fbdf5a --- /dev/null +++ b/GodStraJD3_7_5_1.py @@ -0,0 +1,823 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_min = DecimalParameter(1, 1.1, decimals=2, default=1.02, space='buy') + buy_2_min = DecimalParameter(1, 1.1, decimals=2, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.1, decimals=2, default=1.02, space='buy') + + buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_1_real_num.value, + self.buy_1_decalage.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * self.buy_1_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_1_distance.value) + & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_1_real_num.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * self.buy_2_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_10.json b/GodStraJD3_7_5_10.json new file mode 100644 index 0000000..bd065c1 --- /dev/null +++ b/GodStraJD3_7_5_10.json @@ -0,0 +1,72 @@ +{ + "strategy_name": "GodStraJD3_7_5_10", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0_distance": 0.01, + "buy_0_percent20": 0.1, + "buy_1_bb_lower_5": 0.52, + "buy_1_pente_sma10": 0.25, + "buy_1_pente_sma20": 0.38, + "buy_1_percent_5m_num": -0.04, + "buy_2_bb_lower_5": 0.56, + "buy_2_distance": 0.1, + "buy_2_pente_sma10": 0.55, + "buy_2_pente_sma20": 0.25, + "buy_2_percent20": 0.04, + "buy_2_percent_5m_num": -0.07, + "buy_3_bb_lower_5": 0.6, + "buy_3_distance": -0.01, + "buy_3_pente_sma10": 0.32, + "buy_3_pente_sma20": 0.5, + "buy_3_percent20": 0.09, + "buy_3_percent_5m_num": -0.04, + "buy_4_day_week_percent": 0.0, + "buy_4_pente_sma10": 0.56, + "buy_4_pente_sma20": 0.13, + "buy_day_week": "percent3_1d", + "buy_decalage0": 7, + "buy_decalage2": 8, + "buy_decalage3": 8, + "buy_decalage_deb_0": 3, + "buy_decalage_deb_2": 0, + "buy_decalage_deb_3": 0, + "buy_min_horizon": 83, + "buy_real_num0": 1.63, + "buy_real_num1": 0.42, + "buy_real_num2": 0.38 + }, + "sell": { + "sell_RSI": 89, + "sell_RSI2": 78, + "sell_RSI2_percent": 0.001, + "sell_candels": 4, + "sell_percent": 0.02, + "sell_percent3": 0.014, + "sell_profit_no_change": 0.02, + "sell_profit_percent10": 0.0013, + "sell_too_old_day": 7, + "sell_too_old_percent": 0.019 + }, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-29 07:11:59.278799+00:00" +} diff --git a/GodStraJD3_7_5_10.py b/GodStraJD3_7_5_10.py new file mode 100644 index 0000000..daec1d7 --- /dev/null +++ b/GodStraJD3_7_5_10.py @@ -0,0 +1,962 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_10(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma5': {'color': 'pink'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'}, + 'open_1d': {'color': 'white'}, + 'close_1d': {'color': 'white'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_lower_5': {'color': 'yellow'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = True + profit_old_sma10 = False + profit_old_sma5 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = True + profit_short_loss = False + profit_sma5 = True + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_1_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy') + buy_2_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy') + buy_3_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy') + buy_4_day_week_percent = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='buy') + + buy_day_week = CategoricalParameter([ + 'percent_1d', 'percent3_1d', 'percent5_1d', 'percent_1w', 'percent3_1w'], + default="percent_1d", space='buy') + #buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1d_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1w_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + #buy_0 = BooleanParameter(default=True, space="buy") + #buy_2 = BooleanParameter(default=True, space="buy") + #buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy') + + buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + buy_1_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_4_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + buy_1_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_4_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + # buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + + buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_candels = IntParameter(0, 48, default=12, space='sell') + + sell_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_RSI = IntParameter(70, 98, default=88, space='sell') + sell_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # }, + # { + # "method": "EmergencyStop", + # "min_percent": -0.05, + # "candels": 1 + # } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + # if self.profit_quick_gain_3: + # if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain_3" + # if self.profit_quick_gain: + # if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain" + # if (current_profit > 0 & last_candle['bb_width'] < current_profit): + # return "more_bb_width" + + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, "5m") for pair in pairs] + informative_pairs += [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # dataframe['TR'] = ta.TRANGE(dataframe) + # dataframe['ATR'] = ta.SMA(dataframe['TR'], 21) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1w") + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + # logger.info("Strategy informative using %s %s", "BTC/TUSD", "5m") + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1w", ffill=True) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="5m") + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "5m", ffill=True) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # logger.info("Strategy informative using %s %s", "BTC/TUSD", "1h") + + # # Get the informative pair + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # pandas.set_option('display.max_rows', informative.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # # print('informative', metadata['pair'], informative.tail(1)) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative['max_open'] = ta.MAX(informative["open"], timeperiod=2) + # informative['max_close'] = ta.MIN(informative["close"], timeperiod=2) + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # self.protections.global_stop(current_time); + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + & (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe['sma10']) < self.buy_1_pente_sma10.value / 100) + & (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe['sma20']) < self.buy_1_pente_sma20.value / 100) + & (dataframe['percent_5m'].shift(1) >= self.buy_1_percent_5m_num.value) + & (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + & (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe[ + 'sma10']) < self.buy_2_pente_sma10.value / 100) + & (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe[ + 'sma20']) < self.buy_2_pente_sma20.value / 100) + & (dataframe['percent_5m'].shift(1) >= self.buy_2_percent_5m_num.value) + & (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + & (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe[ + 'sma10']) < self.buy_3_pente_sma10.value / 100) + & (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe[ + 'sma20']) < self.buy_3_pente_sma20.value / 100) + & (dataframe['percent_5m'].shift(1) >= self.buy_3_percent_5m_num.value) + & (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # "buy_2_distance": 0.09, + # "buy_2_percent20": 0.05, + decalage = 1 + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 19) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= 0.05) #self.buy_2_percent20.value) + & (dataframe['distance_min'] <= 0.09) #self.buy_2_distance.value) + & (dataframe[self.buy_day_week.value] >= self.buy_4_day_week_percent.value) + ), ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['close_1d']) + # & (dataframe['close'] > dataframe['bb_upperband']) + # ), ['buy', 'buy_tag']] = (1, 'buy_4') + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_2.json b/GodStraJD3_7_5_2.json new file mode 100644 index 0000000..87d992a --- /dev/null +++ b/GodStraJD3_7_5_2.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD3_7_5_2", + "params": { + "roi": { + "0": 2 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.02, + "trailing_stop_positive_offset": 0.03, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_1": false, + "buy_1_bb_diff_lower": 0.0007, + "buy_1_decalage": 6, + "buy_1_decalage_deb": 1, + "buy_1_distance": 0.03, + "buy_1_percent20": 0.06, + "buy_1_real_num": 0.1, + "buy_2": false, + "buy_2_bb_diff_lower": 0.0004, + "buy_2_decalage": 7, + "buy_2_decalage_deb": 3, + "buy_2_distance": 0.06, + "buy_2_percent20": 0.01, + "buy_2_real_num": 1.7, + "buy_3": true, + "buy_3_bb_diff_lower": 0.0, + "buy_3_decalage": 7, + "buy_3_decalage_deb": 2, + "buy_3_distance": 0.09, + "buy_3_percent20": 0.01, + "buy_3_real_num": 0.99, + "buy_min_horizon": 191 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-12 21:14:24.255458+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_2.py b/GodStraJD3_7_5_2.py new file mode 100644 index 0000000..9d7e6b8 --- /dev/null +++ b/GodStraJD3_7_5_2.py @@ -0,0 +1,781 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "bb_diff_lower": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_1 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_1_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, space='buy') + buy_2_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, space='buy') + buy_3_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + days = (current_time - trade.open_date_utc).days + # if (current_profit >= -0.01 * days) & (days >= 5) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']): + # return "too_old_" + days + if (current_profit >= -0.01) & (days >= 5) & (days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & (days >= 10) & (days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & (days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & (days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & (days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + + # if (current_profit > 0) \ + # & (previous_last_candle['rsi'] > 88) \ + # & ( + # (last_candle['percent'] < - current_profit / 3) | (last_candle['percent3'] < - current_profit / 3)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi' + + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['volume_max'] = dataframe['volume10'] * dataframe['close'] / 1000 + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe["bb_diff_lower"] = (dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1)) / dataframe["bb_lowerband"] + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) - 100 + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + if self.buy_1.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_1_real_num.value, + self.buy_1_decalage.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['bb_diff_lower'] >= - self.buy_1_bb_diff_lower.value) + # & (dataframe['distance_min'] <= self.buy_1_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_2_real_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_3_real_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['bb_width'] >= 0.07) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & (dataframe['bb_diff_lower'] >= - self.buy_3_bb_diff_lower.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_3.json b/GodStraJD3_7_5_3.json new file mode 100644 index 0000000..37c68ce --- /dev/null +++ b/GodStraJD3_7_5_3.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD3_7_5_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": false, + "buy_0_percent20": -0.07, + "buy_1_decalage": 6, + "buy_1_decalage_deb": 3, + "buy_1_distance": 0.02, + "buy_1_normal_var": 5.0, + "buy_1_real_num": 0.61, + "buy_2": true, + "buy_2_decalage": 6, + "buy_2_decalage_deb": 1, + "buy_2_distance": 0.1, + "buy_2_normal_var": 0.0, + "buy_2_percent20": 0.02, + "buy_2_real_num": 0.35, + "buy_3": true, + "buy_3_decalage": 6, + "buy_3_decalage_deb": 2, + "buy_3_distance": 0.01, + "buy_3_normal_var": 1.8, + "buy_3_percent20": -0.03, + "buy_3_real_num": 1.18, + "buy_min_horizon": 165 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-13 17:21:19.281512+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_3.json1 b/GodStraJD3_7_5_3.json1 new file mode 100644 index 0000000..a2b3e0b --- /dev/null +++ b/GodStraJD3_7_5_3.json1 @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD3_7_5_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_percent20": 0.09, + "buy_1_decalage": 6, + "buy_1_decalage_deb": 1, + "buy_1_distance": 0.06, + "buy_1_normal_var": 4.7, + "buy_1_real_num": 0.96, + "buy_2": true, + "buy_2_decalage": 6, + "buy_2_decalage_deb": 2, + "buy_2_distance": 0.03, + "buy_2_normal_var": 1.6, + "buy_2_percent20": 0.09, + "buy_2_real_num": 0.08, + "buy_3": false, + "buy_3_decalage": 6, + "buy_3_decalage_deb": 2, + "buy_3_distance": -0.08, + "buy_3_normal_var": 1.9, + "buy_3_percent20": -0.06, + "buy_3_real_num": 0.81, + "buy_min_horizon": 186 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-12 23:10:38.145463+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_3.py b/GodStraJD3_7_5_3.py new file mode 100644 index 0000000..9b32d5f --- /dev/null +++ b/GodStraJD3_7_5_3.py @@ -0,0 +1,808 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_3(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # # if current_candle['bb_width'] > 0.05: + # # print("use more stake", pair, " ", proposed_stake * 2) + # # return min(max_stake, proposed_stake * 2) + # # + # # if current_candle['bb_width'] > 0.035: + # # print("use more stake", pair, " ", proposed_stake * 1.5) + # # return min(max_stake, proposed_stake * 1.5) + # + # # if current_candle['bb_width'] < 0.020: + # # print("use less stake", pair, " ", proposed_stake / 2) + # # return min(max_stake, proposed_stake / 2) + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # # Compound profits during favorable conditions instead of using a static stake. + # # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # + # # Use default stake amount. + # return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008) & (last_candle['percent3'] < 0): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008) & (last_candle['percent3'] < 0): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005) & (last_candle['percent3'] < 0): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_1_real_num.value, + self.buy_1_decalage.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_1_distance.value) + & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_1_real_num.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_4.json b/GodStraJD3_7_5_4.json new file mode 100644 index 0000000..0a723b2 --- /dev/null +++ b/GodStraJD3_7_5_4.json @@ -0,0 +1,57 @@ +{ + "strategy_name": "GodStraJD3_7_5_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": false, + "buy_0_percent20": 0.02, + "buy_1_decalage": 8, + "buy_1_decalage_deb": 3, + "buy_1_distance": 0.07, + "buy_1_min": 1.029, + "buy_1_normal_var": 3.5, + "buy_1_real_num": 0.47, + "buy_1_volume": 71, + "buy_2": true, + "buy_2_decalage": 8, + "buy_2_decalage_deb": 2, + "buy_2_distance": 0.06, + "buy_2_min": 1.029, + "buy_2_normal_var": 0.3, + "buy_2_percent20": 0.06, + "buy_2_real_num": 0.38, + "buy_2_volume": 13, + "buy_3": true, + "buy_3_decalage": 7, + "buy_3_decalage_deb": 2, + "buy_3_distance": 0.03, + "buy_3_min": 1.008, + "buy_3_normal_var": 3.2, + "buy_3_percent20": 0.09, + "buy_3_real_num": 0.73, + "buy_3_volume": 12, + "buy_min_horizon": 141 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-17 23:12:39.259525+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_4.py b/GodStraJD3_7_5_4.py new file mode 100644 index 0000000..6366dec --- /dev/null +++ b/GodStraJD3_7_5_4.py @@ -0,0 +1,827 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from technical.indicators import cmf + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_4(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + + buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cmf20'] = cmf(dataframe, 20) + dataframe['cmf50'] = cmf(dataframe, 50) + dataframe['cmf100'] = cmf(dataframe, 100) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_1_real_num.value, + self.buy_1_decalage.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_1_distance.value) + & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_1_real_num.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['open'] <= dataframe['min200'] * self.buy_2_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_5.json b/GodStraJD3_7_5_5.json new file mode 100644 index 0000000..e8d2263 --- /dev/null +++ b/GodStraJD3_7_5_5.json @@ -0,0 +1,63 @@ +{ + "strategy_name": "GodStraJD3_7_5_5", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_percent20": 0.03, + "buy_1_cmf100_inf": 0.3, + "buy_1_cmf100_sup": 0.6, + "buy_1_decalage": 7, + "buy_1_decalage_deb": 2, + "buy_1_distance": -0.01, + "buy_1_min": 1.002, + "buy_1_normal_var": 2.2, + "buy_1_real_num": 0.53, + "buy_1_volume": 65, + "buy_2": true, + "buy_2_cmf100_inf": 1.0, + "buy_2_cmf100_sup": 0.0, + "buy_2_decalage": 6, + "buy_2_decalage_deb": 2, + "buy_2_distance": 0.08, + "buy_2_min": 1.025, + "buy_2_normal_var": 1.3, + "buy_2_percent20": -0.09, + "buy_2_real_num": 0.32, + "buy_2_volume": 38, + "buy_3": true, + "buy_3_cmf100_inf": -0.4, + "buy_3_cmf100_sup": -0.1, + "buy_3_decalage": 7, + "buy_3_decalage_deb": 1, + "buy_3_distance": 0.1, + "buy_3_min": 1.016, + "buy_3_normal_var": 1.6, + "buy_3_percent20": 0.03, + "buy_3_real_num": 1.94, + "buy_3_volume": 97, + "buy_min_horizon": 98 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-19 16:02:08.220681+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_5.py b/GodStraJD3_7_5_5.py new file mode 100644 index 0000000..d547b6e --- /dev/null +++ b/GodStraJD3_7_5_5.py @@ -0,0 +1,875 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from technical.indicators import cmf +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_5(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_2_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + buy_1_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_2_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + + buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + inf_tf = '1h' + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, self.inf_tf) for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cmf20'] = cmf(dataframe, 20) + dataframe['cmf50'] = cmf(dataframe, 50) + dataframe['cmf100'] = cmf(dataframe, 100) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_tf) + # Get the 14 day rsi + informative['rsi'] = ta.RSI(informative, timeperiod=14) + + # informative['cmf'] = cmf(informative, timeperiod=14) + + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + + pandas.set_option('display.max_rows', informative.shape[0] + 1) + pandas.set_option('display.max_columns', 50) + + print('informative', metadata['pair'], informative.tail(1)) + + # Use the helper function merge_informative_pair to safely merge the pair + # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair + # use ffill to have the 1d value available in every row throughout the day. + # Without this, comparisons between columns of the original and the informative pair would only work once per day. + # Full documentation of this method, see below + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_1_real_num.value, + # self.buy_1_decalage.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['cmf100'] < self.buy_1_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_1_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_2_real_num.value) + & (dataframe['cmf100'] >= self.buy_2_cmf100_sup.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) #self.buy_3_real_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['cmf100'] < self.buy_3_cmf100_sup.value) + # & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_6.json b/GodStraJD3_7_5_6.json new file mode 100644 index 0000000..dc19373 --- /dev/null +++ b/GodStraJD3_7_5_6.json @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_7_5_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_percent20": 0.08, + "buy_1_volume": 0, + "buy_3": true, + "buy_3_cmf100_inf": 0.4, + "buy_3_cmf100_sup": -0.6, + "buy_3_cond_1h_num": 0.56, + "buy_3_cond_num": 0.76, + "buy_3_decalage": 7, + "buy_3_decalage_deb": 3, + "buy_3_distance": 0.08, + "buy_3_min": 1.016, + "buy_3_normal_var": 3.3, + "buy_3_percent20": 0.1, + "buy_3_percent_1d_num": 0.01, + "buy_3_percent_1w_num": -0.04, + "buy_3_real_num": 0.23, + "buy_3_volume": 96, + "buy_min_horizon": 198 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-22 20:30:50.351361+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_6.py b/GodStraJD3_7_5_6.py new file mode 100644 index 0000000..d667cdc --- /dev/null +++ b/GodStraJD3_7_5_6.py @@ -0,0 +1,898 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from technical.indicators import cmf +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_6(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + # buy_1_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_2_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + # buy_1_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_2_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_percent_1d_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + buy_3_percent_1w_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + + # buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + # buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + # buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + # buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + # buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + # buy_1_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + # buy_2_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + # buy_1_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + # buy_2_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + # buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + # buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + + # buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + # buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + # buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + # buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + # buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + # buy_2_decalage = IntParameter(# buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + # buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + inf_tf = '4h' + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, self.inf_tf) for pair in pairs] + informative_pairs += [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = dataframe['bb_lowerband'].rolling(5).var() + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cmf20'] = cmf(dataframe, 20) + dataframe['cmf50'] = cmf(dataframe, 50) + dataframe['cmf100'] = cmf(dataframe, 100) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_tf) + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + pandas.set_option('display.max_rows', informative.shape[0] + 1) + pandas.set_option('display.max_columns', 50) + # print('informative', metadata['pair'], informative.tail(1)) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, ffill=True) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w') + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + informative["percent5"] = informative["percent"].rolling(5).sum() + informative["percent3"] = informative["percent"].rolling(3).sum() + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_1_real_num.value, + # self.buy_1_decalage.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['cmf100'] < self.buy_1_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_1_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + # for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + # if self.buy_2.value: + # dataframe.loc[ + # ( + # (dataframe['cond1'].shift(decalage) <= self.buy_2_cond_num.value) + # & (dataframe['cond1'].shift(decalage) >= self.buy_3_cond_num.value) + # & (dataframe['cond1_1h'] <= self.buy_2_cond_1h_num.value) + # & (dataframe['cmf100'] >= self.buy_2_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + # & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_2_distance.value) + # # & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_3_cond_num.value) + #& (dataframe['percent_1d'] <= self.buy_3_percent_1d_num.value) + #& (dataframe['percent_1w'] <= self.buy_3_percent_1w_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['cmf100'] < self.buy_3_cmf100_sup.value) + # & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + # & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_7.json b/GodStraJD3_7_5_7.json new file mode 100644 index 0000000..644913a --- /dev/null +++ b/GodStraJD3_7_5_7.json @@ -0,0 +1,63 @@ +{ + "strategy_name": "GodStraJD3_7_5_7", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_percent20": 0.05, + "buy_1_cmf100_inf": 0.5, + "buy_1_cmf100_sup": -0.6, + "buy_1_decalage": 6, + "buy_1_decalage_deb": 2, + "buy_1_distance": 0.1, + "buy_1_min": 1.01, + "buy_1_normal_var": 1.0, + "buy_1_real_num": 0.01, + "buy_1_volume": 60, + "buy_2": true, + "buy_2_cmf100_inf": -0.9, + "buy_2_cmf100_sup": -1.0, + "buy_2_decalage": 7, + "buy_2_decalage_deb": 1, + "buy_2_distance": 0.09, + "buy_2_min": 1.025, + "buy_2_normal_var": 4.0, + "buy_2_percent20": 0.06, + "buy_2_real_num": 0.61, + "buy_2_volume": 33, + "buy_3": false, + "buy_3_cmf100_inf": 0.0, + "buy_3_cmf100_sup": 0.7, + "buy_3_decalage": 7, + "buy_3_decalage_deb": 3, + "buy_3_distance": -0.06, + "buy_3_min": 1.006, + "buy_3_normal_var": 4.5, + "buy_3_percent20": 0.1, + "buy_3_real_num": 1.41, + "buy_3_volume": 15, + "buy_min_horizon": 197 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-20 19:38:37.829599+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_7.py b/GodStraJD3_7_5_7.py new file mode 100644 index 0000000..9ed5d0c --- /dev/null +++ b/GodStraJD3_7_5_7.py @@ -0,0 +1,878 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from technical.indicators import cmf +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_7(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_1_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_2_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + buy_1_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_2_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + + buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + buy_2_decalage = IntParameter(buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + inf_tf = '1h' + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent3'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, self.inf_tf) for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cmf20'] = cmf(dataframe, 20) + dataframe['cmf50'] = cmf(dataframe, 50) + dataframe['cmf100'] = cmf(dataframe, 100) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_tf) + + # Get the 14 day rsi + informative['rsi'] = ta.RSI(informative, timeperiod=14) + + # informative['cmf'] = cmf(informative, timeperiod=14) + + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + + pandas.set_option('display.max_rows', informative.shape[0] + 1) + pandas.set_option('display.max_columns', 50) + + # print('informative', metadata['pair'], informative.tail(1)) + + # Use the helper function merge_informative_pair to safely merge the pair + # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair + # use ffill to have the 1d value available in every row throughout the day. + # Without this, comparisons between columns of the original and the informative pair would only work once per day. + # Full documentation of this method, see below + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_1_real_num.value, + # self.buy_1_decalage.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['cmf100'] < self.buy_1_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_1_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_2_real_num.value) + & (dataframe['cond1_1h'] <= self.buy_2_real_num.value) + & (dataframe['cmf100'] >= self.buy_2_cmf100_sup.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) #self.buy_3_real_num.value) + & (dataframe['cond1_1h'] <= self.buy_3_real_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['cmf100'] < self.buy_3_cmf100_sup.value) + # & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_8.json b/GodStraJD3_7_5_8.json new file mode 100644 index 0000000..c9ddc86 --- /dev/null +++ b/GodStraJD3_7_5_8.json @@ -0,0 +1,46 @@ +{ + "strategy_name": "GodStraJD3_7_5_8", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0": true, + "buy_0_percent20": -0.07, + "buy_1_volume": 43, + "buy_3": true, + "buy_3_cmf100_inf": -0.9, + "buy_3_cmf100_sup": 1.0, + "buy_3_cond_1h_num": 0.37, + "buy_3_cond_num": 1.78, + "buy_3_decalage": 8, + "buy_3_decalage_deb": 1, + "buy_3_distance": 0.1, + "buy_3_min": 1.022, + "buy_3_normal_var": 2.1, + "buy_3_percent20": 0.09, + "buy_3_real_num": 0.37, + "buy_3_volume": 60, + "buy_min_horizon": 58 + }, + "sell": {}, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-20 17:59:02.967586+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_8.py b/GodStraJD3_7_5_8.py new file mode 100644 index 0000000..3302a48 --- /dev/null +++ b/GodStraJD3_7_5_8.py @@ -0,0 +1,889 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from technical.indicators import cmf +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_8(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = False + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + # buy_1_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_2_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + # buy_1_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_2_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + # buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_0 = BooleanParameter(default=True, space="buy") + # buy_2 = BooleanParameter(default=True, space="buy") + buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + # buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + # buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + # buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + # buy_1_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + # buy_2_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + # buy_1_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + # buy_2_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + buy_3_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy') + + # buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + # buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy') + + # buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + # buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy') + + # buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy') + # buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy') + buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy') + + # buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy') + # buy_2_decalage = IntParameter(# buy_2_decalage_deb.value + 1, 8, default=5, space='buy') + buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy') + + buy_1_volume = IntParameter(0, 100, default=10, space='buy') + # buy_2_volume = IntParameter(0, 100, default=10, space='buy') + buy_3_volume = IntParameter(0, 100, default=10, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + inf_tf = '1h' + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + # decalage_candle = dataframe.iloc[- decalage].squeeze() + # # if (decalage_candle['normal_var_20'] >= 0.6): + # amount = 10 * (- decalage_candle['percent20'] * 100) + # print("use more stake", pair, " ", amount) + # return min(max_stake, amount) + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + # @property + # def protections(self): + # return [ + # { + # "method": "CooldownPeriod", + # "stop_duration_candles": 10 + # }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # } + # ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.015): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008): + return "no_change_20" + + if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008): + return "no_change_10" + if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005): + return "no_change_5" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, self.inf_tf) for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var() + dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var() + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cmf20'] = cmf(dataframe, 20) + dataframe['cmf50'] = cmf(dataframe, 50) + dataframe['cmf100'] = cmf(dataframe, 100) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_tf) + # Get the 14 day rsi + informative['rsi'] = ta.RSI(informative, timeperiod=14) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + + + informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + + pandas.set_option('display.max_rows', informative.shape[0] + 1) + pandas.set_option('display.max_columns', 50) + + # print('informative', metadata['pair'], informative.tail(1)) + + # Use the helper function merge_informative_pair to safely merge the pair + # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair + # use ffill to have the 1d value available in every row throughout the day. + # Without this, comparisons between columns of the original and the informative pair would only work once per day. + # Full documentation of this method, see below + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_1_real_num.value, + # self.buy_1_decalage.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['cmf100'] < self.buy_1_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_1_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + # for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value): + # if self.buy_2.value: + # dataframe.loc[ + # ( + # (dataframe['cond1'].shift(decalage) <= self.buy_2_cond_num.value) + # & (dataframe['cond1'].shift(decalage) >= self.buy_3_cond_num.value) + # & (dataframe['cond1_1h'] <= self.buy_2_cond_1h_num.value) + # & (dataframe['cmf100'] >= self.buy_2_cmf100_sup.value) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value) + # # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + # & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_2_distance.value) + # # & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value): + if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_3_cond_num.value) + & (dataframe['cond1_1h'] <= self.buy_3_cond_1h_num.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['cmf100'] < self.buy_3_cmf100_sup.value) + & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + # & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + # & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_9.json b/GodStraJD3_7_5_9.json new file mode 100644 index 0000000..1582465 --- /dev/null +++ b/GodStraJD3_7_5_9.json @@ -0,0 +1,52 @@ +{ + "strategy_name": "GodStraJD3_7_5_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0_distance": -0.08, + "buy_0_percent20": 0.01, + "buy_1_bb_lower_5": 0.06, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.1, + "buy_2_percent20": 0.05, + "buy_3_bb_lower_5": 0.47, + "buy_3_distance": 0.05, + "buy_3_percent20": -0.07, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 8, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 2, + "buy_min_horizon": 119, + "buy_real_num0": 0.14, + "buy_real_num1": 0.36, + "buy_real_num2": 1.71 + }, + "sell": { + "sell_candels": 40, + "sell_percent": 0.0, + "sell_percent3": 0.014 + }, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-25 00:29:29.617986+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_9.py b/GodStraJD3_7_5_9.py new file mode 100644 index 0000000..3acd4bc --- /dev/null +++ b/GodStraJD3_7_5_9.py @@ -0,0 +1,861 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_9(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'}, + 'open_1d': {'color': 'white'}, + 'close_1d': {'color': 'white'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_lower_5': {'color': 'yellow'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = False + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = True + profit_short_loss = False + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + #buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1d_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1w_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + #buy_0 = BooleanParameter(default=True, space="buy") + #buy_2 = BooleanParameter(default=True, space="buy") + #buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy') + + buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + # buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + + buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_candels = IntParameter(0, 48, default=12, space='sell') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\ + & ((current_time - trade.open_date_utc).days < 10)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\ + & ((current_time - trade.open_date_utc).days < 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost: + if (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change: + if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + # if self.profit_quick_gain_3: + # if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain_3" + # if self.profit_quick_gain: + # if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + # def informative_pairs(self): + # # get access to all pairs available in whitelist. + # pairs = self.dp.current_whitelist() + # # Assign tf to each pair so they can be downloaded and cached for strategy. + # # informative_pairs = [(pair, "4h") for pair in pairs] + # informative_pairs = [(pair, '1d') for pair in pairs] + # #informative_pairs += [(pair, '1w') for pair in pairs] + # + # # Optionally Add additional "static" pairs + # # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + # + # return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # dataframe['TR'] = ta.TRANGE(dataframe) + # dataframe['ATR'] = ta.SMA(dataframe['TR'], 21) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # # Get the informative pair + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # pandas.set_option('display.max_rows', informative.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # # print('informative', metadata['pair'], informative.tail(1)) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative['max_open'] = ta.MAX(informative["open"], timeperiod=2) + # informative['max_close'] = ta.MIN(informative["close"], timeperiod=2) + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['close_1d']) + # & (dataframe['close'] > dataframe['bb_upperband']) + # ), ['buy', 'buy_tag']] = (1, 'buy_4') + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_9_1.json b/GodStraJD3_7_5_9_1.json new file mode 100644 index 0000000..0dcf549 --- /dev/null +++ b/GodStraJD3_7_5_9_1.json @@ -0,0 +1,67 @@ +{ + "strategy_name": "GodStraJD3_7_5_9_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "sell_RSI": 95, + "sell_RSI2": 81, + "sell_RSI2_percent": 0.008, + "sell_candels": 17, + "sell_percent": 0.016, + "sell_percent3": 0.001, + "sell_profit_no_change": 0.016, + "sell_profit_percent10": 0.0002, + "sell_too_old_day": 7, + "sell_too_old_percent": 0.005 + }, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-29 20:57:57.922162+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_5_9_1.py b/GodStraJD3_7_5_9_1.py new file mode 100644 index 0000000..247dbfe --- /dev/null +++ b/GodStraJD3_7_5_9_1.py @@ -0,0 +1,863 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_9_1(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'}, + 'open_1d': {'color': 'white'}, + 'close_1d': {'color': 'white'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_lower_5': {'color': 'yellow'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + profit_no_change = True + profit_old_sma10 = False + profit_over_rsi = True + profit_quick_gain = True + profit_quick_gain_3 = True + profit_quick_lost = True + profit_short_loss = False + profit_sma5 = True + profit_sma10 = True + profit_sma20 = True + profit_very_old_sma10 = False + + trades = list() + # profit_no_change = BooleanParameter(default=True, space="buy") + # profit_quick_lost = BooleanParameter(default=True, space="buy") + # profit_sma10 = BooleanParameter(default=True, space="buy") + # profit_sma20 = BooleanParameter(default=True, space="buy") + # profit_quick_gain = BooleanParameter(default=True, space="buy") + # profit_quick_gain_3 = BooleanParameter(default=True, space="buy") + # profit_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_very_old_sma10 = BooleanParameter(default=True, space="buy") + # profit_over_rsi = BooleanParameter(default=True, space="buy") + # profit_short_loss = BooleanParameter(default=True, space="buy") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + #buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # buy_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + # buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1d_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + #buy_3_percent_1w_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + #buy_0 = BooleanParameter(default=True, space="buy") + #buy_2 = BooleanParameter(default=True, space="buy") + #buy_3 = BooleanParameter(default=True, space="buy") + + buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + buy_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy') + + buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + buy_1_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_4_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + buy_1_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_4_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + # buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + # buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy') + + buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_candels = IntParameter(0, 48, default=12, space='sell') + + sell_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_RSI = IntParameter(70, 98, default=88, space='sell') + sell_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 24, + # "trade_limit": 4, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # }, + # { + # "method": "EmergencyStop", + # "min_percent": -0.05, + # "candels": 1 + # } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (current_profit > 0.015) & (last_candle['percent'] < -0.005): + # return 'percent_quick' + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + # if self.profit_quick_gain_3: + # if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain_3" + # if self.profit_quick_gain: + # if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + # return "quick_gain" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + # def informative_pairs(self): + # # get access to all pairs available in whitelist. + # pairs = self.dp.current_whitelist() + # # Assign tf to each pair so they can be downloaded and cached for strategy. + # # informative_pairs = [(pair, "4h") for pair in pairs] + # informative_pairs = [(pair, '1d') for pair in pairs] + # #informative_pairs += [(pair, '1w') for pair in pairs] + # + # # Optionally Add additional "static" pairs + # # informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")] + # + # return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + # dataframe['TR'] = ta.TRANGE(dataframe) + # dataframe['ATR'] = ta.SMA(dataframe['TR'], 21) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + # # INFORMATIVE PAIRS + + # # Get the informative pair + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # pandas.set_option('display.max_rows', informative.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # # print('informative', metadata['pair'], informative.tail(1)) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative['max_open'] = ta.MAX(informative["open"], timeperiod=2) + # informative['max_close'] = ta.MIN(informative["close"], timeperiod=2) + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True) + + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w') + # informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0) + # informative[buy_indicator0] = gene_calculator(informative, buy_indicator0) + # informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0]) + # informative["percent"] = (informative["close"] - informative["open"]) / informative["open"] + # informative["percent5"] = informative["percent"].rolling(5).sum() + # informative["percent3"] = informative["percent"].rolling(3).sum() + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_5_9_2.json b/GodStraJD3_7_5_9_2.json new file mode 100644 index 0000000..9e154c3 --- /dev/null +++ b/GodStraJD3_7_5_9_2.json @@ -0,0 +1,97 @@ +{ + "strategy_name": "GodStraJD3_7_5_9_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_0_distance": -0.05, + "buy_0_percent20": 0.04, + "buy_1_bb_lower_5": 0.36, + "buy_1_pente_sma10": 0.22, + "buy_1_pente_sma20": 0.6, + "buy_2_bb_lower_5": 0.23, + "buy_2_distance": 0.09, + "buy_2_pente_sma10": 0.36, + "buy_2_pente_sma20": 0.46, + "buy_2_percent20": 0.02, + "buy_3_bb_lower_5": 0.48, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.53, + "buy_3_pente_sma20": 0.11, + "buy_3_percent20": -0.09, + "buy_4_pente_sma10": 0.48, + "buy_4_pente_sma20": 0.38, + "buy_bb_lowerband": 1.02, + "buy_bb_width": 0.08, + "buy_cat": "", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_5_9_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'}, + 'open_1d': {'color': 'white'}, + 'close_1d': {'color': 'white'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_lower_5': {'color': 'yellow'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'normal_var_20': {'color': 'red'}, + 'normal_var_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + trades = list() + profit_no_change = BooleanParameter(default=True, space="sell") + profit_quick_lost = BooleanParameter(default=True, space="sell") + profit_sma5 = BooleanParameter(default=True, space="sell") + profit_sma10 = BooleanParameter(default=True, space="sell") + profit_sma20 = BooleanParameter(default=True, space="sell") + profit_quick_gain = BooleanParameter(default=True, space="sell") + profit_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_old_sma10 = BooleanParameter(default=True, space="sell") + profit_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_over_rsi = BooleanParameter(default=True, space="sell") + profit_short_loss = BooleanParameter(default=True, space="sell") + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + buy_real = DecimalParameter(0.001, 0.999, decimals=4, default=0.11908, space='buy') + buy_cat = CategoricalParameter([">R", "=R", " expected_profit) & (last_candle['pct_change_1_1d'] < 0): + # return "exp_profit_down" + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if (last_candle['pct_change_1_1d'] > 0): + if self.profit_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change.value and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + else: + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (( + current_time - trade.open_date_utc).days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe['profit'] = 0 + # RSI + dataframe['trend_ichimoku_base'] = ta2.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta2.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = ta.RSI(informative) + informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = ta.SMA(informative, timeperiod=3) + informative['sma5'] = ta.SMA(informative, timeperiod=5) + informative['sma10'] = ta.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + & (dataframe['pct_change_1_1d'] < self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] < self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] < self.buy_pct_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value) + & (dataframe['pct_change_1_1d'] < self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] < self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] < self.buy_pct_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + & (dataframe['pct_change_1_1d'] < self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] < self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] < self.buy_pct_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_real.value + OPR = self.buy_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] > self.buy_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_6.json b/GodStraJD3_7_6.json new file mode 100644 index 0000000..7d1219d --- /dev/null +++ b/GodStraJD3_7_6.json @@ -0,0 +1,63 @@ +{ + "strategy_name": "GodStraJD3_7_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_1_distance": 0.06, + "buy_1_percent20": -0.04, + "buy_3_distance": 0.01, + "buy_3_percent20": 0.08, + "buy_decalage1": 8, + "buy_decalage3": 7, + "buy_decalage_deb_1": 2, + "buy_decalage_deb_3": 3, + "buy_min_horizon": 111, + "buy_real_num1": 0.77, + "buy_real_num3": 0.52 + }, + "sell": { + "profit_no_change": false, + "profit_old_sma10": true, + "profit_over_rsi": false, + "profit_over_rsi2_percent": 0.002, + "profit_over_rsi_max_rsi": 90, + "profit_over_rsi_max_rsi2": 94, + "profit_quick_gain": false, + "profit_quick_gain_3": false, + "profit_quick_lost": true, + "profit_quick_lost_max": 0.0, + "profit_quick_lost_max_profit": 0.013, + "profit_short_loss": true, + "profit_sma10": true, + "profit_sma10_current_profit": 0.027, + "profit_sma10_facteur": 1.0, + "profit_sma20": true, + "profit_sma20_current_profit": 0.021, + "profit_sma20_facteur": 1.006, + "profit_too_old": true, + "profit_too_old_days": 9, + "profit_too_old_max": 0.02, + "profit_very_old_sma10": false + }, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-12 10:23:55.007196+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_6.py b/GodStraJD3_7_6.py new file mode 100644 index 0000000..aa9c5c9 --- /dev/null +++ b/GodStraJD3_7_6.py @@ -0,0 +1,787 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_6(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'ecart_20': {'color': 'red'}, + 'ecart_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # profit_no_change = False + # profit_old_sma10 = False + # profit_over_rsi = True + # profit_quick_gain = True + # profit_quick_gain_3 = True + # profit_quick_lost = False + # profit_short_loss = False + # profit_sma10 = False + # profit_sma20 = True + # profit_very_old_sma10 = False + + trades = list() + profit_too_old = BooleanParameter(default=True, space="sell") + profit_no_change = BooleanParameter(default=True, space="sell") + profit_quick_lost = BooleanParameter(default=True, space="sell") + profit_sma10 = BooleanParameter(default=True, space="sell") + profit_sma20 = BooleanParameter(default=True, space="sell") + profit_quick_gain = BooleanParameter(default=True, space="sell") + profit_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_old_sma10 = BooleanParameter(default=True, space="sell") + profit_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_over_rsi = BooleanParameter(default=True, space="sell") + profit_short_loss = BooleanParameter(default=True, space="sell") + + profit_too_old_max = DecimalParameter(0, 0.05, decimals=2, default=0.01, space='sell') + profit_too_old_days = IntParameter(1, 10, default=5, space='sell') + profit_quick_lost_max = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_quick_lost_max_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma10_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma10_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell') + + profit_sma20_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma20_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell') + + profit_over_rsi_max_rsi = IntParameter(70, 100, default=88, space='sell') + profit_over_rsi_max_rsi2 = IntParameter(70, 100, default=82, space='sell') + + profit_over_rsi2_percent = DecimalParameter(0, 0.05, decimals=3, default=0.02, space='sell') + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + # buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num3 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + # buy_0 = BooleanParameter(default=True, space="buy") + # buy_2 = BooleanParameter(default=True, space="buy") + # buy_3 = BooleanParameter(default=True, space="buy") + + # buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_1_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + # buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + # buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_1 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy') + + # buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage1 = IntParameter(buy_decalage_deb_1.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if self.profit_too_old.value: + if (current_profit >= - self.profit_too_old_max.value) \ + & ((current_time - trade.open_date_utc).days >= self.profit_too_old_days.value)\ + & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 2))\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= - (2 * self.profit_too_old_max.value)) \ + & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 2))\ + & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 3)) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= - (3 * self.profit_too_old_max.value)) \ + & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 3)) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost.value: + if (current_profit >= self.profit_quick_lost_max_profit.value) \ + & (last_candle['percent3'] < - self.profit_quick_lost_max.value): + return "quick_lost" + + if self.profit_no_change.value: + if (current_profit > 0.005) \ + & (last_candle['percent10'] < 0.000) \ + & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3.value: + if (current_profit >= 0.03) \ + & (last_candle['percent3'] < 0) \ + & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain.value: + if (0.01 < current_profit < 0.03) \ + & (last_candle['percent'] < 0) \ + & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > self.profit_sma10_current_profit.value) \ + & ((previous_5_candle['sma10'] > (last_candle['sma10'] * self.profit_sma10_facteur.value)) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > self.profit_sma20_current_profit.value) & (last_candle['percent5'] < 0) \ + & (previous_5_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > (last_candle['sma20'] * self.profit_sma20_facteur.value)) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi'] > self.profit_over_rsi_max_rsi.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.profit_over_rsi_max_rsi2.value) \ + & (last_candle['percent'] < - self.profit_over_rsi2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_real_num0.value, + # self.buy_decalage0.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * 1.02) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_0_distance.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_1.value, self.buy_decalage1.value): + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num1.value) + & (dataframe['bb_width'].shift(decalage) >= 0.07) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['close'] < dataframe['sma10']) + & (dataframe['sma50'].shift(decalage) < dataframe['sma50']) + #& (dataframe['open'] < dataframe['min1.1']) + # & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_1_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + # if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num3.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + #& (dataframe['open'] < dataframe['min1.1']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_7_6_2.json b/GodStraJD3_7_6_2.json new file mode 100644 index 0000000..db4341c --- /dev/null +++ b/GodStraJD3_7_6_2.json @@ -0,0 +1,63 @@ +{ + "strategy_name": "GodStraJD3_7_6_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.026, + "trailing_stop_positive_offset": 0.077, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_1_distance": -0.02, + "buy_1_percent20": 0.03, + "buy_3_distance": 0.05, + "buy_3_percent20": 0.01, + "buy_decalage1": 8, + "buy_decalage3": 8, + "buy_decalage_deb_1": 2, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 195, + "buy_real_num1": 0.55, + "buy_real_num3": 0.55 + }, + "sell": { + "profit_no_change": false, + "profit_old_sma10": true, + "profit_over_rsi": false, + "profit_over_rsi2_percent": 0.002, + "profit_over_rsi_max_rsi": 90, + "profit_over_rsi_max_rsi2": 94, + "profit_quick_gain": false, + "profit_quick_gain_3": false, + "profit_quick_lost": true, + "profit_quick_lost_max": 0.0, + "profit_quick_lost_max_profit": 0.013, + "profit_short_loss": true, + "profit_sma10": true, + "profit_sma10_current_profit": 0.027, + "profit_sma10_facteur": 1.0, + "profit_sma20": true, + "profit_sma20_current_profit": 0.021, + "profit_sma20_facteur": 1.006, + "profit_too_old": true, + "profit_too_old_days": 9, + "profit_too_old_max": 0.02, + "profit_very_old_sma10": false + }, + "protection": { + "lookback": 133, + "protection_max_allowed_dd": 0.71, + "protection_stop": 61, + "protection_stoploss_stop": 50, + "trade_limit": 9 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-12 00:18:04.975397+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_7_6_2.py b/GodStraJD3_7_6_2.py new file mode 100644 index 0000000..064d0f8 --- /dev/null +++ b/GodStraJD3_7_6_2.py @@ -0,0 +1,788 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import calendar +from freqtrade.loggers import setup_logging + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class GodStraJD3_7_6_2(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min20': {'color': '#87e470'}, + 'min50': {'color': '#ac3e2a'}, + "min1.1": {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'} + }, + # "Ind0": { + # buy_crossed_indicator0: {'color': 'green'}, + # buy_indicator0: {'color': 'red'} + # }, + "Cond": { + 'cond1': {'color': 'yellow'}, + }, + # "Ind1": { + # buy_indicator1: {'color': 'yellow'}, + # buy_crossed_indicator1: {'color': 'pink'} + # }, + # "Ind2": { + # buy_indicator2: {'color': 'cyan'}, + # buy_crossed_indicator2: {'color': 'blue'}, + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "Ecart": { + 'ecart_20': {'color': 'red'}, + 'ecart_50': {'color': 'yellow'}, + }, + # "rolling": { + # 'bb_rolling': {'color': '#87e470'}, + # "bb_rolling_min": {'color': '#ac3e2a'} + # }, + "percent": { + "percent": {'color': 'green'}, + "percent3": {'color': 'blue'}, + "percent5": {'color': 'red'}, + "distance_min": {'color': 'white'} + } + } + } + + + # #################### END OF RESULT PLACE #################### + + # profit_no_change = False + # profit_old_sma10 = False + # profit_over_rsi = True + # profit_quick_gain = True + # profit_quick_gain_3 = True + # profit_quick_lost = False + # profit_short_loss = False + # profit_sma10 = False + # profit_sma20 = True + # profit_very_old_sma10 = False + + trades = list() + profit_too_old = BooleanParameter(default=True, space="sell") + profit_no_change = BooleanParameter(default=True, space="sell") + profit_quick_lost = BooleanParameter(default=True, space="sell") + profit_sma10 = BooleanParameter(default=True, space="sell") + profit_sma20 = BooleanParameter(default=True, space="sell") + profit_quick_gain = BooleanParameter(default=True, space="sell") + profit_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_old_sma10 = BooleanParameter(default=True, space="sell") + profit_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_over_rsi = BooleanParameter(default=True, space="sell") + profit_short_loss = BooleanParameter(default=True, space="sell") + + profit_too_old_max = DecimalParameter(0, 0.05, decimals=2, default=0.01, space='sell') + profit_too_old_days = IntParameter(1, 10, default=5, space='sell') + profit_quick_lost_max = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_quick_lost_max_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma10_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma10_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell') + + profit_sma20_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell') + profit_sma20_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell') + + profit_over_rsi_max_rsi = IntParameter(70, 100, default=88, space='sell') + profit_over_rsi_max_rsi2 = IntParameter(70, 100, default=82, space='sell') + + profit_over_rsi2_percent = DecimalParameter(0, 0.05, decimals=3, default=0.02, space='sell') + + # buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy') + + # buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + buy_real_num3 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + # buy_0 = BooleanParameter(default=True, space="buy") + # buy_2 = BooleanParameter(default=True, space="buy") + # buy_3 = BooleanParameter(default=True, space="buy") + + # buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_1_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + + # buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + + # buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_1 = IntParameter(1, 3, default=5, space='buy') + buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy') + + # buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + buy_decalage1 = IntParameter(buy_decalage_deb_1.value + 1, 8, default=5, space='buy') + buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + + protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection') + protection_stop = IntParameter(1, 100, default=48, space='protection') + protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection') + lookback = IntParameter(1, 200, default=48, space='protection') + trade_limit = IntParameter(1, 10, default=2, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + + # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # 'info': + # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + + allow_to_buy = True + max_gain = -100 + sum_gain = 0 + max_time = 0 + + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + if len(self.trades) == 0: + print('search') + self.trades = Trade.get_open_trades() + + if len(self.trades) >= self.config['max_open_trades'] / 2: + for trade in self.trades: + ticker = self.dp.ticker(trade.pair) + last_price = ticker['last'] + gain = (last_price - trade.open_rate) / trade.open_rate + max_gain = max(max_gain, gain) + sum_gain += gain + max_time = max(max_time, datetime.timestamp(trade.open_date)) + print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + now = datetime.now() + diff = (datetime.timestamp(now) - max_time / 3600) + if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + print("allow_to_buy=false") + allow_to_buy = False + print(pair, allow_to_buy, len(self.trades), + "max gain=", max_gain, + "sum_gain=", sum_gain, + "now=", now, + "max=", max_time, + "diff=", datetime.timestamp(now) - max_time) + + if allow_to_buy: + self.trades = list() + + return allow_to_buy + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": self.lookback.value, + "trade_limit": self.trade_limit.value, + "stop_duration_candles": self.protection_stop.value, + "max_allowed_drawdown": self.protection_max_allowed_dd.value, + "only_per_pair": False + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": self.protection_stoploss_stop.value, + "only_per_pair": False + } + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \ + # & (last_candle['percent10'] < 0.001): + # return 'small_profit' + # + # if (current_profit > 0.01) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'sma10_quick' + + if self.profit_too_old.value: + if (current_profit >= - self.profit_too_old_max.value) \ + & ((current_time - trade.open_date_utc).days >= self.profit_too_old_days.value)\ + & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 2))\ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.01" + if (current_profit >= - (2 * self.profit_too_old_max.value)) \ + & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 2))\ + & ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 3)) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.02" + if (current_profit >= - (3 * self.profit_too_old_max.value)) \ + & ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 3)) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return "too_old_0.03" + + if self.profit_quick_lost.value: + if (current_profit >= self.profit_quick_lost_max_profit.value) \ + & (last_candle['percent3'] < - self.profit_quick_lost_max.value): + return "quick_lost" + + if self.profit_no_change.value: + if (current_profit > 0.005) \ + & (last_candle['percent10'] < 0.000) \ + & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3.value: + if (current_profit >= 0.03) \ + & (last_candle['percent3'] < 0) \ + & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain.value: + if (0.01 < current_profit < 0.03) \ + & (last_candle['percent'] < 0) \ + & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > self.profit_sma10_current_profit.value) \ + & ((previous_5_candle['sma10'] > (last_candle['sma10'] * self.profit_sma10_facteur.value)) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > self.profit_sma20_current_profit.value) & (last_candle['percent5'] < 0) \ + & (previous_5_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > (last_candle['sma20'] * self.profit_sma20_facteur.value)) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi'] > self.profit_over_rsi_max_rsi.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.profit_over_rsi_max_rsi2.value) \ + & (last_candle['percent'] < - self.profit_over_rsi2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close'] + dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close'] + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + + # Bollinger Bands - Weighted (EMA based instead of SMA) + # weighted_bollinger = qtpylib.weighted_bollinger_bands( + # qtpylib.typical_price(dataframe), window=20, stds=2 + # ) + # dataframe["wbb_upperband"] = weighted_bollinger["upper"] + # dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + # dataframe["wbb_middleband"] = weighted_bollinger["mid"] + # dataframe["wbb_percent"] = ( + # (dataframe["close"] - dataframe["wbb_lowerband"]) / + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + # ) + # dataframe["wbb_width"] = ( + # (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + # ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50'] + # dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20'] + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 50) + # + # allow_to_buy = True + # max_gain = -100 + # trades = Trade.get_open_trades() + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # pairs = self.dp.current_whitelist() + # pairs_len = len(pairs) + # pair_index = pairs.index(metadata['pair']) + # + # # print(pair_index, " ", metadata['pair']) + # + # # ob = self.dp.orderbook(metadata['pair'], 1) + # # dataframe['best_bid'] = ob['bids'][0][0] + # # dataframe['best_ask'] = ob['asks'][0][0] + # # print(ob) + # + # for trade in trades: + # # if (metadata['pair'] == trade.pair): + # ticker = self.dp.ticker(trade.pair) #metadata['pair']) + # last_price = ticker['last'] + # # dataframe['volume24h'] = ticker['quoteVolume'] + # # dataframe['vwap'] = ticker['vwap'] + # # d = dataframe.tail(1) + # # print(dataframe) + # gain = (last_price - trade.open_rate) / trade.open_rate + # + # # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain) + # max_gain = max(max_gain, gain) + # + # if max_gain > - 0.05: + # allow_to_buy = False + # + # # print(metadata['pair'], max_gain, allow_to_buy, len(trades)) + + # for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + # if self.buy_0.value: + # conditions = list() + # condition1, dataframe = condition_generator( + # dataframe, + # buy_operator0, + # buy_indicator0, + # buy_crossed_indicator0, + # self.buy_real_num0.value, + # self.buy_decalage0.value + # ) + # conditions.append(condition1) + # dataframe.loc[ + # ( + # reduce(lambda x, y: x & y, conditions) + # & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + # & (dataframe['close'] < dataframe['bb_middleband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * 1.02) + # & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # # & (dataframe['min20'] == dataframe['min50']) + # & (dataframe['distance_min'] <= self.buy_0_distance.value) + # ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_1.value, self.buy_decalage1.value): + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num1.value) + & (dataframe['bb_width'].shift(decalage) >= 0.07) + # & (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['sma50'].shift(decalage) < dataframe['sma50']) + #& (dataframe['open'] < dataframe['min1.1']) + # & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_1_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + # if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= self.buy_real_num3.value) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma100']) + & (dataframe['open'] < dataframe['sma10']) + #& (dataframe['open'] < dataframe['min1.1']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # pair = metadata['pair'] + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # # if self.dp: + # # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + + # print(condition1) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + diff --git a/GodStraJD3_8.json b/GodStraJD3_8.json new file mode 100644 index 0000000..b18c0f7 --- /dev/null +++ b/GodStraJD3_8.json @@ -0,0 +1,54 @@ +{ + "strategy_name": "GodStraJD3_8", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.058, + "trailing_stop_positive_offset": 0.079, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bbwidth_num0": 0.05, + "buy_bbwidth_num1": 0.99, + "buy_cond1_num0": 1.29, + "buy_cond1_num1": 1.67, + "profit_no_change": true, + "profit_old_sma10": true, + "profit_over_rsi": true, + "profit_quick_gain": false, + "profit_quick_gain_3": false, + "profit_quick_lost": true, + "profit_short_loss": true, + "profit_sma10": true, + "profit_sma20": true, + "profit_very_old_sma10": false + }, + "sell": { + "sell_crossed_indicator0": "CDLCONCEALBABYSWALL-100", + "sell_indicator0": "BBANDS-2-5", + "sell_operator0": "D", + "sell_percent": 0.01, + "sell_percent3": 0.002, + "sell_percent5": 0.025, + "sell_real_num0": 0.01 + }, + "protection": { + "lookback": 46, + "lookback_stoploss": 144, + "protection_cooldown": 19, + "protection_max_allowed_dd": 0.36, + "protection_stop": 79, + "protection_stoploss_stop": 13, + "trade_limit": 7, + "trade_limit_stoploss": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-14 03:19:36.837525+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_8.py b/GodStraJD3_8.py new file mode 100644 index 0000000..51f28a8 --- /dev/null +++ b/GodStraJD3_8.py @@ -0,0 +1,1043 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +timeperiods = [5, 10, 20, 50, 100] + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_8(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0, space='sell') + sell_percent3 = DecimalParameter(0, 0.03, decimals=3, default=0, space='sell') + sell_percent5 = DecimalParameter(0, 0.04, decimals=3, default=0, space='sell') + + # Sell Hyperoptable Parameters/Spaces. + sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell') + # sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell') + # sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell') + + sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell') + # sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell') + # sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell') + + sell_operator0 = CategoricalParameter(operators, default=" float: + fee = 1.0007 + profit = ((current*fee) - (price*fee)) + + return float(f"{profit:.8f}") + + def calc_percentage_lower(self, price: float, current: float) -> float: + fee = 1.0007 + price = price*fee + current = current*fee + lowerpercent = ((price-current)/(price*fee))*100 + return float(f"{lowerpercent:.8f}") + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": self.protection_cooldown.value + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": self.lookback_stoploss.value, + # "trade_limit": self.trade_limit_stoploss.value, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # }, + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0) & ( + (last_candle['percent5'] <= -0.015) + | (last_candle['percent10'] <= -0.015) + | (last_candle['percent20'] <= -0.015) + ) \ + & ((current_time - trade.open_date_utc).seconds >= 2400): + return "quick_lost" + + if self.profit_quick_lost.value: + if (current_profit >= 0) & (last_candle['percent3'] < -0.01) \ + & ((current_time - trade.open_date_utc).seconds >= 2400): + return "quick_lost_1H" + + if self.profit_no_change.value: + if (current_profit > 0.015) & (last_candle['percent20'] < 0.0) & ((current_time - trade.open_date_utc).seconds >= 2400): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3.value: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain.value: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10.value: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) & (last_candle['sma20_pente'] < -0.015)\ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20'] * 1.005) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10.value: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10.value: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi.value: + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss.value: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max20'] = ta.MAX(dataframe['close'], timeperiod=20) + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe["bb_lower_pente"] = 100 * (dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1)) / dataframe["bb_lowerband"] + dataframe["sma10_pente"] = 100 * (dataframe["sma10"] - dataframe["sma10"].shift(1)) / dataframe["sma10"] + dataframe["sma20_pente"] = 100 * (dataframe["sma20"] - dataframe["sma20"].shift(1)) / dataframe["sma20"] + + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["HT_PHASOR-0-100"] = gene_calculator(dataframe, "HT_PHASOR-0-100") + dataframe["CDLIDENTICAL3CROWS-100"] = gene_calculator(dataframe, "CDLIDENTICAL3CROWS-100") + dataframe["DEMA-10"] = gene_calculator(dataframe, "DEMA-10") + dataframe["CDLMORNINGDOJISTAR-20"] = gene_calculator(dataframe, "CDLMORNINGDOJISTAR-20") + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # dataframe["q_0.1"] = dataframe.rolling(50).quantile(.1)['close'] + # dataframe["q_0.25"] = dataframe.rolling(50).quantile(.25)['close'] + # dataframe["q_0.33"] = dataframe.rolling(50).quantile(.33)['close'] + + dataframe["MACD-2-10"] = gene_calculator(dataframe, "MACD-2-10") + dataframe["CDLIDENTICAL3CROWS-10"] = gene_calculator(dataframe, "CDLIDENTICAL3CROWS-10") + dataframe["PPO-10"] = gene_calculator(dataframe, "PPO-10") + dataframe["MINUS_DM-10"] = gene_calculator(dataframe, "MINUS_DM-10") + dataframe["MOM-10"] = gene_calculator(dataframe, "MOM-10") + dataframe["MACDEXT-0-100"] = gene_calculator(dataframe, "MACDEXT-0-100") + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + percent_lower = False + current_price = dataframe['close'].iloc[-1] + + dataframe['should_sell'] = False + dataframe['should_buy'] = False + + # Get the previous trade + trade = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + if trade: + trade = trade[-1] + lsp = trade.close_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + # Found a bug? When force selling it doesnt close it + else: + lsp = trade.open_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + else: + lsp = 0.00 + + # Get the current Trade + trade = Trade.get_trades_proxy(is_open=True, pair=metadata['pair']) + if trade: + trade = trade[-1] + lbp = trade.open_rate + open_trade = True + profit = self.calc_profit(price=lbp, current=current_price) + profit_percent = (profit/lbp)*100 + else: + lbp = 0.00 + open_trade = False + profit = False + profit_percent = False + # print("------------") + # print("Last Sold For:", lsp) + + # if open_trade: + # print("Bought for: ", lbp) + # print("Current Price: ", current_price) + # if profit: + # print("Current Profit: ", profit, " ", float(f"{profit_percent:.8f}"), "%") + # if percent_lower and not open_trade: + # print("Percent Lower: ", float(f"{percent_lower:.8f}"), "%") + + # Should we Sell? + if profit_percent: + if profit_percent > 1: + dataframe['should_sell'] = True + + # Should we buy? + if not open_trade: + if (lsp == 0.00) & (lbp == 0.00): + dataframe['should_buy'] = True + # Is the percentage of what we sold for and the current price 2% lower + if percent_lower > 2: + dataframe['should_buy'] = True + + dataframe['last_sell_price'] = lsp + dataframe['last_buy_price'] = lbp + dataframe['current_price'] = current_price + dataframe['profit_percent'] = profit_percent + # print("Current Dataframe:") + # print(dataframe.tail(1)) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + conditions2 = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + 0.67 #self.buy_real_num0.value + ) + conditions.append(condition1) + + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + & (dataframe['bb_width'] > 0.05) + ), ['buy', 'buy_tag']] = (1, 'buy_signal_condition') + + #################################################################### + + condition2, dataframe = condition_generator(dataframe, "/=R", "CMO-10", "HT_DCPERIOD-20", 0.37) + conditions2.append(condition2) + + dataframe.loc[ + (reduce(lambda x, y: x & y, conditions2) + # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'].shift(9) < dataframe['bb_lowerband'].shift(9)) + ), ['buy', 'buy_tag']] = (1, 'buy_bb_width_1') + + #################################################################### + conditions = list() + + condition, dataframe = condition_generator(dataframe, "/= 10) + & (dataframe['sma10_pente'] > 0.02) + & (dataframe['sma10'].shift(1) < dataframe['sma10']) + & (dataframe['sma20'].shift(1) < dataframe['sma20']) + & (dataframe['sma50'].shift(1) < dataframe['sma50']) + & (dataframe['close'] < dataframe['bb_upperband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['percent50'] < 0.025) + ), + ['buy', 'buy_tag']] = (1, 'buy_sma') + # print(len(dataframe.keys())) + + + #################################################################### + # conditions3 = list() + # + # condition3, dataframe = condition_generator(dataframe, "D", "MACD-2-10", "CDLIDENTICAL3CROWS-10", 0.88) + # conditions3.append(condition3) + # + # condition3, dataframe = condition_generator(dataframe, "/", "MOM-10", "MACDEXT-0-100", 0.87) + # #conditions3.append(condition3) + # + # if conditions3: + # dataframe.loc[ + # (reduce(lambda x, y: x & y, conditions3) + # # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['close'].shift(7) < dataframe['bb_lowerband'].shift(7)) + # ), + # ['buy', 'buy_tag']] = (1, 'buy_minus_dm') + # print(len(dataframe.keys())) + + # ################################################################### + # + # dataframe.loc[ + # (dataframe['close'] > dataframe['bb_upperband']) + # & (dataframe['percent'] > 0.01) + # & (dataframe['percent20'] < 0.035) + # & (dataframe['cond1'] > 13) + # & (dataframe['bb_width'] > 0.02) + # & (dataframe['cond1'].shift(4) < 8) + # & (dataframe['bb_width'].shift(4) < 0.012) + # , ['buy', 'buy_tag']] = (1, 'buy_cond1') + # + # #################################################################### + # + # dataframe.loc[ + # (dataframe['bb_lower_pente'].shift(4) < -0.50) + # & (dataframe['sma10_pente'] > -0.2) + # & (dataframe['sma10_pente'].shift(4) < -0.4) + # & (dataframe['percent5'] < 0.01) + # , ['buy', 'buy_tag']] = (1, 'buy_lower_pente') + # + # #################################################################### + # + # dataframe.loc[ + # (dataframe['percent50'].shift(4) < -0.05) + # & (dataframe['sma10_pente'].shift(1) < 0) + # & (dataframe['sma10_pente'] >= 0) + # & (dataframe['open'] < dataframe['sma10']) + # , ['buy', 'buy_tag']] = (1, 'buy_sma50') + # + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 30) + # print(condition1) + # print(dataframe["q_0.1"]) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = list() + # + # condition1, dataframe = condition_generator( + # dataframe, + # self.sell_operator0.value, + # self.sell_indicator0.value, + # self.sell_crossed_indicator0.value, + # self.sell_real_num0.value + # ) + # conditions.append(condition1) + # + # # print(self.sell_percent.value, ' ', + # # self.sell_percent.value + self.sell_percent3.value, ' ', + # # self.sell_percent.value + self.sell_percent3.value + self.sell_percent5.value) + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) & + # (dataframe['percent'] < - self.sell_percent.value) & + # (dataframe['percent3'] < - (self.sell_percent3.value + self.sell_percent.value)) & + # (dataframe['percent5'] < - (self.sell_percent5.value + self.sell_percent3.value + self.sell_percent.value)) & + # (dataframe['close'] < dataframe['open']) + # # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe + diff --git a/GodStraJD3_9.json b/GodStraJD3_9.json new file mode 100644 index 0000000..bed9dfb --- /dev/null +++ b/GodStraJD3_9.json @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.058, + "trailing_stop_positive_offset": 0.079, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_signal_bb_width": 1.21, + "buy_signal_condition_high": 1.02, + "buy_signal_minus": 1.22, + "buy_signal_sma10": 1.08, + "buy_signal_sma10_pente": 0.041, + "buy_signal_sma_max": 1.09, + "buy_signal_sma_min": 1.0, + "buy_signal_sma_percent50": 0.061 + }, + "sell": { + "sell_crossed_indicator0": "CDL3INSIDE-50", + "sell_indicator0": "CDLGAPSIDESIDEWHITE-50", + "sell_operator0": "CUT", + "sell_percent": 0.006, + "sell_percent3": 0.0, + "sell_percent5": 0.004, + "sell_real_num0": 0.13 + }, + "protection": { + "lookback": 46, + "lookback_stoploss": 144, + "protection_cooldown": 19, + "protection_max_allowed_dd": 0.36, + "protection_stop": 79, + "protection_stoploss_stop": 13, + "trade_limit": 7, + "trade_limit_stoploss": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-17 19:22:05.539646+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_9.jsonBest b/GodStraJD3_9.jsonBest new file mode 100644 index 0000000..db05efb --- /dev/null +++ b/GodStraJD3_9.jsonBest @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.058, + "trailing_stop_positive_offset": 0.079, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_signal_bb_width": 1.09, + "buy_signal_condition_high": 1.1, + "buy_signal_minus": 1.09, + "buy_signal_sma10": 1.02, + "buy_signal_sma10_pente": 0.001, + "buy_signal_sma_max": 1.03, + "buy_signal_sma_min": 1.08, + "buy_signal_sma_percent50": 0.036 + }, + "sell": { + "sell_crossed_indicator0": "CDLSHORTLINE-50", + "sell_indicator0": "CDLSEPARATINGLINES-20", + "sell_operator0": "=R", + "sell_percent": 0.01, + "sell_percent3": 0.021, + "sell_percent5": 0.006, + "sell_real_num0": 0.84 + }, + "protection": { + "lookback": 46, + "lookback_stoploss": 144, + "protection_cooldown": 19, + "protection_max_allowed_dd": 0.36, + "protection_stop": 79, + "protection_stoploss_stop": 13, + "trade_limit": 7, + "trade_limit_stoploss": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-17 00:06:37.000718+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_9.jsonOld b/GodStraJD3_9.jsonOld new file mode 100644 index 0000000..4b4f77a --- /dev/null +++ b/GodStraJD3_9.jsonOld @@ -0,0 +1,47 @@ +{ + "strategy_name": "GodStraJD3_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.058, + "trailing_stop_positive_offset": 0.079, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_signal_bb_width": 1.1, + "buy_signal_condition_high": 1.07, + "buy_signal_minus": 1.07, + "buy_signal_sma": 1.08, + "buy_signal_sma10": 1.08, + "buy_signal_sma10_pente": 0.041, + "buy_signal_sma_percent50": 0.092 + }, + "sell": { + "sell_crossed_indicator0": "CDLSHORTLINE-50", + "sell_indicator0": "CDLSEPARATINGLINES-20", + "sell_operator0": "=R", + "sell_percent": 0.01, + "sell_percent3": 0.021, + "sell_percent5": 0.006, + "sell_real_num0": 0.84 + }, + "protection": { + "lookback": 46, + "lookback_stoploss": 144, + "protection_cooldown": 19, + "protection_max_allowed_dd": 0.36, + "protection_stop": 79, + "protection_stoploss_stop": 13, + "trade_limit": 7, + "trade_limit_stoploss": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-16 18:51:17.244506+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_9.jsonOld2 b/GodStraJD3_9.jsonOld2 new file mode 100644 index 0000000..423c009 --- /dev/null +++ b/GodStraJD3_9.jsonOld2 @@ -0,0 +1,48 @@ +{ + "strategy_name": "GodStraJD3_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.058, + "trailing_stop_positive_offset": 0.079, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_signal_bb_width": 1.81, + "buy_signal_condition_high": 1.28, + "buy_signal_minus": 1.95, + "buy_signal_sma10": 1.02, + "buy_signal_sma10_pente": 0.055, + "buy_signal_sma_max": 1.02, + "buy_signal_sma_min": 1.03, + "buy_signal_sma_percent50": 0.089 + }, + "sell": { + "sell_crossed_indicator0": "CDLSHORTLINE-50", + "sell_indicator0": "CDLSEPARATINGLINES-20", + "sell_operator0": "=R", + "sell_percent": 0.01, + "sell_percent3": 0.021, + "sell_percent5": 0.006, + "sell_real_num0": 0.84 + }, + "protection": { + "lookback": 46, + "lookback_stoploss": 144, + "protection_cooldown": 19, + "protection_max_allowed_dd": 0.36, + "protection_stop": 79, + "protection_stoploss_stop": 13, + "trade_limit": 7, + "trade_limit_stoploss": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-17 15:42:20.763706+00:00" +} \ No newline at end of file diff --git a/GodStraJD3_9.py b/GodStraJD3_9.py new file mode 100644 index 0000000..18ce8ae --- /dev/null +++ b/GodStraJD3_9.py @@ -0,0 +1,1197 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from datetime import timedelta, datetime + +from freqtrade.strategy.strategy_helper import merge_informative_pair + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle + +# TODO: this gene is removed 'MAVP' cuz or error on periods +import user_data.strategies.custom_indicators as csa + +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +timeperiods = [5, 10, 20, 50, 100] + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD3_9(IStrategy): + # #################### RESULTS PASTE PLACE #################### + # ROI table: + minimal_roi = { + "0": 10, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '5m' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0, space='sell') + sell_percent3 = DecimalParameter(0, 0.03, decimals=3, default=0, space='sell') + sell_percent5 = DecimalParameter(0, 0.04, decimals=3, default=0, space='sell') + + # Sell Hyperoptable Parameters/Spaces. + sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell') + # sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell') + # sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell') + + sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell') + # sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell') + # sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell') + + sell_operator0 = CategoricalParameter(operators, default=" float: + fee = 1.0007 + profit = ((current*fee) - (price*fee)) + + return float(f"{profit:.8f}") + + def calc_percentage_lower(self, price: float, current: float) -> float: + fee = 1.0007 + price = price*fee + current = current*fee + lowerpercent = ((price-current)/(price*fee))*100 + return float(f"{lowerpercent:.8f}") + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": self.protection_cooldown.value + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": self.lookback_stoploss.value, + # "trade_limit": self.trade_limit_stoploss.value, + # "stop_duration_candles": self.protection_stoploss_stop.value, + # "only_per_pair": False + # }, + ] + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0) & ( + (last_candle['percent5'] <= -0.015) + | (last_candle['percent10'] <= -0.015) + | (last_candle['percent20'] <= -0.015) + ) \ + & ((current_time - trade.open_date_utc).seconds >= 2400): + return "quick_lost" + + if self.profit_quick_lost: + if (current_profit >= 0) & (last_candle['percent3'] < -0.01) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 2400): + return "quick_lost_1H" + + if self.profit_no_change: + if (current_profit > 0.015) & (last_candle['percent20'] < 0.0) & \ + (last_candle['sma10'] < 0.0) & ((current_time - trade.open_date_utc).seconds >= 2400): + return "no_change" + + #if (current_profit > 0.01) & (last_candle['rsi'] < 30): + # return "small_rsi" + if self.profit_quick_gain_3: + if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600): + return "quick_gain_3" + if self.profit_quick_gain: + if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600) + return "quick_gain" + + if self.profit_sma10: + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20: + if (current_profit > 0.005) & (last_candle['percent5'] < 0) & (last_candle['sma20_pente'] < -0.015)\ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20'] * 1.005) & + ((last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + # if self.profit_old_sma10: + # if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).days >= 3) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'old_sma10' + # if self.profit_very_old_sma10: + # if (current_profit > -0.01) \ + # & ((current_time - trade.open_date_utc).days >= 6) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'very_old_sma10' + + if self.profit_over_rsi: + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if self.profit_short_loss: + if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + # if (current_profit > 0) \ + # & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_rsi_2' + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['profit'] = 0 + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)): + # dataframe["percent_ok"] = new dataframe() + # else: + # dataframe["percent_ok"] = 0 + + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max20'] = ta.MAX(dataframe['close'], timeperiod=20) + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe["bb_lower_pente"] = 100 * (dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1)) / dataframe["bb_lowerband"] + dataframe["sma10_pente"] = 100 * (dataframe["sma10"] - dataframe["sma10"].shift(1)) / dataframe["sma10"] + dataframe["sma20_pente"] = 100 * (dataframe["sma20"] - dataframe["sma20"].shift(1)) / dataframe["sma20"] + + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["HT_PHASOR-0-100"] = gene_calculator(dataframe, "HT_PHASOR-0-100") + dataframe["CDLIDENTICAL3CROWS-100"] = gene_calculator(dataframe, "CDLIDENTICAL3CROWS-100") + dataframe["DEMA-10"] = gene_calculator(dataframe, "DEMA-10") + dataframe["CDLMORNINGDOJISTAR-20"] = gene_calculator(dataframe, "CDLMORNINGDOJISTAR-20") + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # dataframe["q_0.1"] = dataframe.rolling(50).quantile(.1)['close'] + # dataframe["q_0.25"] = dataframe.rolling(50).quantile(.25)['close'] + # dataframe["q_0.33"] = dataframe.rolling(50).quantile(.33)['close'] + + dataframe["MACD-2-10"] = gene_calculator(dataframe, "MACD-2-10") + dataframe["CDLIDENTICAL3CROWS-10"] = gene_calculator(dataframe, "CDLIDENTICAL3CROWS-10") + dataframe["PPO-10"] = gene_calculator(dataframe, "PPO-10") + dataframe["MINUS_DM-10"] = gene_calculator(dataframe, "MINUS_DM-10") + dataframe["MOM-10"] = gene_calculator(dataframe, "MOM-10") + dataframe["MACDEXT-0-100"] = gene_calculator(dataframe, "MACDEXT-0-100") + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + + percent_lower = False + current_price = dataframe['close'].iloc[-1] + + dataframe['should_sell'] = False + dataframe['should_buy'] = False + + # Get the previous trade + # open_trades = Trade.get_trades_proxy(is_open=True) + # print(open_trades) + + trade = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + if trade: + trade = trade[-1] + lsp = trade.close_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + # Found a bug? When force selling it doesnt close it + else: + lsp = trade.open_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + else: + lsp = 0.00 + + # Get the current Trade + trade = Trade.get_trades_proxy(is_open=True, pair=metadata['pair']) + if trade: + trade = trade[-1] + lbp = trade.open_rate + open_trade = True + profit = self.calc_profit(price=lbp, current=current_price) + profit_percent = (profit/lbp)*100 + else: + lbp = 0.00 + open_trade = False + profit = False + profit_percent = False + # print("------------") + # print("Last Sold For:", lsp) + + # if open_trade: + # print("Bought for: ", lbp) + # print("Current Price: ", current_price) + # if profit: + # print("Current Profit: ", profit, " ", float(f"{profit_percent:.8f}"), "%") + # if percent_lower and not open_trade: + # print("Percent Lower: ", float(f"{percent_lower:.8f}"), "%") + + # Should we Sell? + if profit_percent: + if profit_percent > 1: + dataframe['should_sell'] = True + + # Should we buy? + if not open_trade: + if (lsp == 0.00) & (lbp == 0.00): + dataframe['should_buy'] = True + # Is the percentage of what we sold for and the current price 2% lower + if percent_lower > 2: + dataframe['should_buy'] = True + + dataframe['last_sell_price'] = lsp + dataframe['last_buy_price'] = lbp + dataframe['current_price'] = current_price + dataframe['profit_percent'] = profit_percent + # print("Current Dataframe:") + # print(dataframe.tail(1)) + + # ## Base Timeframe / Pair + # + # # Kaufmann Adaptive Moving Average + # dataframe['kama'] = ta.KAMA(dataframe, length=233) + # + # # RMI: https://www.tradingview.com/script/kwIt9OgQ-Relative-Momentum-Index/ + # dataframe['rmi'] = csa.RMI(dataframe, length=24, mom=5) + # + # # Momentum Pinball: https://www.tradingview.com/script/fBpVB1ez-Momentum-Pinball-Indicator/ + # dataframe['roc-mp'] = ta.ROC(dataframe, timeperiod=1) + # dataframe['mp'] = ta.RSI(dataframe['roc-mp'], timeperiod=3) + # + # # MA Streak: https://www.tradingview.com/script/Yq1z7cIv-MA-Streak-Can-Show-When-a-Run-Is-Getting-Long-in-the-Tooth/ + # dataframe['mastreak'] = csa.mastreak(dataframe, period=4) + # + # # Percent Change Channel: https://www.tradingview.com/script/6wwAWXA1-MA-Streak-Change-Channel/ + # upper, mid, lower = csa.pcc(dataframe, period=40, mult=3) + # dataframe['pcc-lowerband'] = lower + # dataframe['pcc-upperband'] = upper + # + # lookup_idxs = dataframe.index.values - (abs(dataframe['mastreak'].values) + 1) + # valid_lookups = lookup_idxs >= 0 + # dataframe['sbc'] = np.nan + # dataframe.loc[valid_lookups, 'sbc'] = dataframe['close'].to_numpy()[lookup_idxs[valid_lookups].astype(int)] + # + # dataframe['streak-roc'] = 100 * (dataframe['close'] - dataframe['sbc']) / dataframe['sbc'] + # + # # Trends, Peaks and Crosses + # dataframe['candle-up'] = np.where(dataframe['close'] >= dataframe['open'], 1, 0) + # dataframe['candle-up-trend'] = np.where(dataframe['candle-up'].rolling(5).sum() >= 3, 1, 0) + # + # dataframe['rmi-up'] = np.where(dataframe['rmi'] >= dataframe['rmi'].shift(), 1, 0) + # dataframe['rmi-up-trend'] = np.where(dataframe['rmi-up'].rolling(5).sum() >= 3, 1, 0) + # + # dataframe['rmi-dn'] = np.where(dataframe['rmi'] <= dataframe['rmi'].shift(), 1, 0) + # dataframe['rmi-dn-count'] = dataframe['rmi-dn'].rolling(8).sum() + # + # dataframe['streak-bo'] = np.where(dataframe['streak-roc'] < dataframe['pcc-lowerband'], 1, 0) + # dataframe['streak-bo-count'] = dataframe['streak-bo'].rolling(8).sum() + # + # # Indicators used only for ROI and Custom Stoploss + # ssldown, sslup = csa.SSLChannels_ATR(dataframe, length=21) + # dataframe['sroc'] = csa.SROC(dataframe, roclen=21, emalen=13, smooth=21) + # dataframe['ssl-dir'] = np.where(sslup > ssldown, 'up', 'down') + # + # Base pair informative timeframe indicators + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_timeframe) + # + # # Get the "average day range" between the 1d high and 1d low to set up guards + # informative['1d-high'] = informative['close'].rolling(24).max() + # informative['1d-low'] = informative['close'].rolling(24).min() + # informative['adr'] = informative['1d-high'] - informative['1d-low'] + # + # # Base pair informative timeframe indicators + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_timeframe) + # + # # Get the "average day range" between the 1d high and 1d low to set up guards + # informative['1d-high'] = informative['close'].rolling(24).max() + # informative['1d-low'] = informative['close'].rolling(24).min() + # informative['adr'] = informative['1d-high'] - informative['1d-low'] + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_timeframe, ffill=True) + # # + # # Other stake specific informative indicators + # # e.g if stake is BTC and current coin is XLM (pair: XLM/BTC) + # if self.config['stake_currency'] in ('BTC', 'ETH'): + # coin, stake = metadata['pair'].split('/') + # fiat = self.custom_fiat + # coin_fiat = f"{coin}/{fiat}" + # stake_fiat = f"{stake}/{fiat}" + # + # # Informative COIN/FIAT e.g. XLM/USD - Base Timeframe + # coin_fiat_tf = self.dp.get_pair_dataframe(pair=coin_fiat, timeframe=self.timeframe) + # dataframe[f"{fiat}_rmi"] = csa.RMI(coin_fiat_tf, length=55, mom=5) + # + # # Informative STAKE/FIAT e.g. BTC/USD - Base Timeframe + # stake_fiat_tf = self.dp.get_pair_dataframe(pair=stake_fiat, timeframe=self.timeframe) + # dataframe[f"{stake}_rmi"] = csa.RMI(stake_fiat_tf, length=55, mom=5) + # + # # Informatives for BTC/STAKE if not in whitelist + # else: + # pairs = self.dp.current_whitelist() + # btc_stake = f"BTC/{self.config['stake_currency']}" + # if not btc_stake in pairs: + # self.custom_btc_inf = True + # # BTC/STAKE - Base Timeframe + # btc_stake_tf = self.dp.get_pair_dataframe(pair=btc_stake, timeframe=self.timeframe) + # dataframe['BTC_rmi'] = csa.RMI(btc_stake_tf, length=55, mom=5) + # dataframe['BTC_close'] = btc_stake_tf['close'] + # dataframe['BTC_kama'] = ta.KAMA(btc_stake_tf, length=144) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + conditions2 = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + 0.7 #self.buy_real_num0.value + ) + conditions.append(condition1) + + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['low'] < dataframe['min20']) + & (dataframe['percent'] > 0) + # & (dataframe['max'] < dataframe['close'] * self.buy_signal_condition_high.value) + ), ['buy', 'buy_tag']] = (1, 'buy_signal_condition') + + #################################################################### + + condition2, dataframe = condition_generator(dataframe, "/=R", "CMO-10", "HT_DCPERIOD-20", 0.37) + conditions2.append(condition2) + + dataframe.loc[ + (reduce(lambda x, y: x & y, conditions2) + # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + & (dataframe['close'].shift(9) < dataframe['bb_lowerband'].shift(9)) + # & (dataframe['max'] < dataframe['close'] * self.buy_signal_bb_width.value) + ), ['buy', 'buy_tag']] = (1, 'buy_bb_width_1') + + #################################################################### + conditions = list() + + condition, dataframe = condition_generator(dataframe, "/= 10) + & (dataframe['sma10_pente'] > self.buy_signal_sma10_pente.value) + & (dataframe['sma10'].shift(1) < dataframe['sma10'] * self.buy_signal_sma10.value) + & (dataframe['sma20'].shift(1) < dataframe['sma20']) + & (dataframe['sma50'].shift(1) < dataframe['sma50']) + & (dataframe['close'] < dataframe['bb_upperband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['percent50'] < self.buy_signal_sma_percent50.value) + # & (dataframe['max'] < dataframe['close'] * self.buy_signal_sma_max.value) + # & (dataframe['close'] < dataframe['min'] * self.buy_signal_sma_min.value) + # & (dataframe['close'] > dataframe['1d-low_1h'] * self.buy_signal_sma_min.value) + # & (dataframe['close'] < dataframe['1d-high_1h'] * self.buy_signal_sma_max.value) + ), + ['buy', 'buy_tag']] = (1, 'buy_sma') + # print(len(dataframe.keys())) + + #################################################################### + # conditions3 = list() + # + # condition3, dataframe = condition_generator(dataframe, "D", "MACD-2-10", "CDLIDENTICAL3CROWS-10", 0.88) + # conditions3.append(condition3) + # + # condition3, dataframe = condition_generator(dataframe, "/", "MOM-10", "MACDEXT-0-100", 0.87) + # #conditions3.append(condition3) + # + # if conditions3: + # dataframe.loc[ + # (reduce(lambda x, y: x & y, conditions3) + # # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['close'].shift(7) < dataframe['bb_lowerband'].shift(7)) + # & (dataframe['max'] < dataframe['close'] * self.buy_signal_minus.value) + # ), + # ['buy', 'buy_tag']] = (1, 'buy_minus_dm') + # print(len(dataframe.keys())) + + # ################################################################### + # + # dataframe.loc[ + # (dataframe['close'] > dataframe['bb_upperband']) + # & (dataframe['percent'] > 0.01) + # & (dataframe['percent20'] < 0.035) + # & (dataframe['cond1'] > 13) + # & (dataframe['bb_width'] > 0.02) + # & (dataframe['cond1'].shift(4) < 8) + # & (dataframe['bb_width'].shift(4) < 0.012) + # , ['buy', 'buy_tag']] = (1, 'buy_cond1') + # + # #################################################################### + # + # dataframe.loc[ + # (dataframe['bb_lower_pente'].shift(4) < -0.50) + # & (dataframe['sma10_pente'] > -0.2) + # & (dataframe['sma10_pente'].shift(4) < -0.4) + # & (dataframe['percent5'] < 0.01) + # , ['buy', 'buy_tag']] = (1, 'buy_lower_pente') + # + # #################################################################### + # + # dataframe.loc[ + # (dataframe['percent50'].shift(4) < -0.05) + # & (dataframe['sma10_pente'].shift(1) < 0) + # & (dataframe['sma10_pente'] >= 0) + # & (dataframe['open'] < dataframe['sma10']) + # , ['buy', 'buy_tag']] = (1, 'buy_sma50') + # + # pandas.set_option('display.max_rows', dataframe.shape[0] + 1) + # pandas.set_option('display.max_columns', 30) + # print(condition1) + # print(dataframe["q_0.1"]) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = list() + # + # condition1, dataframe = condition_generator( + # dataframe, + # self.sell_operator0.value, + # self.sell_indicator0.value, + # self.sell_crossed_indicator0.value, + # self.sell_real_num0.value + # ) + # conditions.append(condition1) + # + # # print(self.sell_percent.value, ' ', + # # self.sell_percent.value + self.sell_percent3.value, ' ', + # # self.sell_percent.value + self.sell_percent3.value + self.sell_percent5.value) + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) & + # (dataframe['percent'] < - self.sell_percent.value) & + # (dataframe['percent3'] < - (self.sell_percent3.value + self.sell_percent.value)) & + # (dataframe['percent5'] < - (self.sell_percent5.value + self.sell_percent3.value + self.sell_percent.value)) & + # (dataframe['close'] < dataframe['open']) + # # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe + diff --git a/GodStraJD4.py b/GodStraJD4.py new file mode 100644 index 0000000..5b602d3 --- /dev/null +++ b/GodStraJD4.py @@ -0,0 +1,848 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD4(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.14) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD5.py b/GodStraJD5.py new file mode 100644 index 0000000..981cabd --- /dev/null +++ b/GodStraJD5.py @@ -0,0 +1,828 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD5(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.14) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + #dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1 + + if conditions: + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + ), + 'sell']=1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/GodStraJD_P.py b/GodStraJD_P.py new file mode 100644 index 0000000..177feb0 --- /dev/null +++ b/GodStraJD_P.py @@ -0,0 +1,673 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraJD_P(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + # #################### END OF RESULT PLACE #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter( + god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter( + god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter( + god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.10) + & (dataframe['volume'] > 0) + ) | + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.15) + & (dataframe['volume'] > 0) + ) | + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'sell']=1 + return dataframe diff --git a/GodStraJD_Test.json b/GodStraJD_Test.json new file mode 100644 index 0000000..9e47fe9 --- /dev/null +++ b/GodStraJD_Test.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraJD", + "params": { + "buy": { + "buy_crossed_indicator0": "ADD-20", + "buy_crossed_indicator1": "ASIN-6", + "buy_crossed_indicator2": "CDLEVENINGSTAR-50", + "buy_indicator0": "SMA-100", + "buy_indicator1": "WILLR-50", + "buy_indicator2": "CDLHANGINGMAN-20", + "buy_operator0": "/R", + "sell_real_num0": 0.1, + "sell_real_num1": 0.8, + "sell_real_num2": 0.9 + }, + "protection": {}, + "roi": { + "0": 0.259, + "33": 0.097, + "93": 0.033, + "193": 0 + }, + "stoploss": { + "stoploss": -0.164 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.243, + "trailing_stop_positive_offset": 0.262, + "trailing_only_offset_is_reached": false + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-11-25 17:47:44.984352+00:00" +} \ No newline at end of file diff --git a/GodStraNew.json b/GodStraNew.json new file mode 100644 index 0000000..60d74e7 --- /dev/null +++ b/GodStraNew.json @@ -0,0 +1,51 @@ +{ + "strategy_name": "GodStraNew", + "params": { + "roi": { + "0": 0.598, + "644": 0.166, + "3269": 0.115, + "7289": 0 + }, + "stoploss": { + "stoploss": -0.128 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_crossed_indicator0": "SAREXT-12", + "buy_crossed_indicator1": "BOP-5", + "buy_crossed_indicator2": "OBV-5", + "buy_indicator0": "AROONOSC-110", + "buy_indicator1": "CDLHIKKAKE-50", + "buy_indicator2": "CDLSHORTLINE-110", + "buy_operator0": "R", + "sell_real_num0": 0.1, + "sell_real_num1": 0.8, + "sell_real_num2": 0.9 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 06:15:28.024140+00:00" +} \ No newline at end of file diff --git a/GodStraNew.py b/GodStraNew.py new file mode 100644 index 0000000..71c2e7c --- /dev/null +++ b/GodStraNew.py @@ -0,0 +1,639 @@ +# GodStraNew Strategy +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew +# --- Do not remove these libs --- +from freqtrade import data +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# -------------------------------- + +# Add your lib to import here +# TODO: talib is fast but have not more indicators +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from random import shuffle +# TODO: this gene is removed 'MAVP' cuz or error on periods +all_god_genes = { + 'Overlap Studies': { + 'BBANDS-0', # Bollinger Bands + 'BBANDS-1', # Bollinger Bands + 'BBANDS-2', # Bollinger Bands + 'DEMA', # Double Exponential Moving Average + 'EMA', # Exponential Moving Average + 'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline + 'KAMA', # Kaufman Adaptive Moving Average + 'MA', # Moving average + 'MAMA-0', # MESA Adaptive Moving Average + 'MAMA-1', # MESA Adaptive Moving Average + # TODO: Fix this + # 'MAVP', # Moving average with variable period + 'MIDPOINT', # MidPoint over period + 'MIDPRICE', # Midpoint Price over period + 'SAR', # Parabolic SAR + 'SAREXT', # Parabolic SAR - Extended + 'SMA', # Simple Moving Average + 'T3', # Triple Exponential Moving Average (T3) + 'TEMA', # Triple Exponential Moving Average + 'TRIMA', # Triangular Moving Average + 'WMA', # Weighted Moving Average + }, + 'Momentum Indicators': { + 'ADX', # Average Directional Movement Index + 'ADXR', # Average Directional Movement Index Rating + 'APO', # Absolute Price Oscillator + 'AROON-0', # Aroon + 'AROON-1', # Aroon + 'AROONOSC', # Aroon Oscillator + 'BOP', # Balance Of Power + 'CCI', # Commodity Channel Index + 'CMO', # Chande Momentum Oscillator + 'DX', # Directional Movement Index + 'MACD-0', # Moving Average Convergence/Divergence + 'MACD-1', # Moving Average Convergence/Divergence + 'MACD-2', # Moving Average Convergence/Divergence + 'MACDEXT-0', # MACD with controllable MA type + 'MACDEXT-1', # MACD with controllable MA type + 'MACDEXT-2', # MACD with controllable MA type + 'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26 + 'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26 + 'MFI', # Money Flow Index + 'MINUS_DI', # Minus Directional Indicator + 'MINUS_DM', # Minus Directional Movement + 'MOM', # Momentum + 'PLUS_DI', # Plus Directional Indicator + 'PLUS_DM', # Plus Directional Movement + 'PPO', # Percentage Price Oscillator + 'ROC', # Rate of change : ((price/prevPrice)-1)*100 + # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCP', + 'ROCR', # Rate of change ratio: (price/prevPrice) + # Rate of change ratio 100 scale: (price/prevPrice)*100 + 'ROCR100', + 'RSI', # Relative Strength Index + 'STOCH-0', # Stochastic + 'STOCH-1', # Stochastic + 'STOCHF-0', # Stochastic Fast + 'STOCHF-1', # Stochastic Fast + 'STOCHRSI-0', # Stochastic Relative Strength Index + 'STOCHRSI-1', # Stochastic Relative Strength Index + # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + 'TRIX', + 'ULTOSC', # Ultimate Oscillator + 'WILLR', # Williams' %R + }, + 'Volume Indicators': { + 'AD', # Chaikin A/D Line + 'ADOSC', # Chaikin A/D Oscillator + 'OBV', # On Balance Volume + }, + 'Volatility Indicators': { + 'ATR', # Average True Range + 'NATR', # Normalized Average True Range + 'TRANGE', # True Range + }, + 'Price Transform': { + 'AVGPRICE', # Average Price + 'MEDPRICE', # Median Price + 'TYPPRICE', # Typical Price + 'WCLPRICE', # Weighted Close Price + }, + 'Cycle Indicators': { + 'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period + 'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase + 'HT_PHASOR-0', # Hilbert Transform - Phasor Components + 'HT_PHASOR-1', # Hilbert Transform - Phasor Components + 'HT_SINE-0', # Hilbert Transform - SineWave + 'HT_SINE-1', # Hilbert Transform - SineWave + 'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode + }, + 'Pattern Recognition': { + 'CDL2CROWS', # Two Crows + 'CDL3BLACKCROWS', # Three Black Crows + 'CDL3INSIDE', # Three Inside Up/Down + 'CDL3LINESTRIKE', # Three-Line Strike + 'CDL3OUTSIDE', # Three Outside Up/Down + 'CDL3STARSINSOUTH', # Three Stars In The South + 'CDL3WHITESOLDIERS', # Three Advancing White Soldiers + 'CDLABANDONEDBABY', # Abandoned Baby + 'CDLADVANCEBLOCK', # Advance Block + 'CDLBELTHOLD', # Belt-hold + 'CDLBREAKAWAY', # Breakaway + 'CDLCLOSINGMARUBOZU', # Closing Marubozu + 'CDLCONCEALBABYSWALL', # Concealing Baby Swallow + 'CDLCOUNTERATTACK', # Counterattack + 'CDLDARKCLOUDCOVER', # Dark Cloud Cover + 'CDLDOJI', # Doji + 'CDLDOJISTAR', # Doji Star + 'CDLDRAGONFLYDOJI', # Dragonfly Doji + 'CDLENGULFING', # Engulfing Pattern + 'CDLEVENINGDOJISTAR', # Evening Doji Star + 'CDLEVENINGSTAR', # Evening Star + 'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines + 'CDLGRAVESTONEDOJI', # Gravestone Doji + 'CDLHAMMER', # Hammer + 'CDLHANGINGMAN', # Hanging Man + 'CDLHARAMI', # Harami Pattern + 'CDLHARAMICROSS', # Harami Cross Pattern + 'CDLHIGHWAVE', # High-Wave Candle + 'CDLHIKKAKE', # Hikkake Pattern + 'CDLHIKKAKEMOD', # Modified Hikkake Pattern + 'CDLHOMINGPIGEON', # Homing Pigeon + 'CDLIDENTICAL3CROWS', # Identical Three Crows + 'CDLINNECK', # In-Neck Pattern + 'CDLINVERTEDHAMMER', # Inverted Hammer + 'CDLKICKING', # Kicking + 'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu + 'CDLLADDERBOTTOM', # Ladder Bottom + 'CDLLONGLEGGEDDOJI', # Long Legged Doji + 'CDLLONGLINE', # Long Line Candle + 'CDLMARUBOZU', # Marubozu + 'CDLMATCHINGLOW', # Matching Low + 'CDLMATHOLD', # Mat Hold + 'CDLMORNINGDOJISTAR', # Morning Doji Star + 'CDLMORNINGSTAR', # Morning Star + 'CDLONNECK', # On-Neck Pattern + 'CDLPIERCING', # Piercing Pattern + 'CDLRICKSHAWMAN', # Rickshaw Man + 'CDLRISEFALL3METHODS', # Rising/Falling Three Methods + 'CDLSEPARATINGLINES', # Separating Lines + 'CDLSHOOTINGSTAR', # Shooting Star + 'CDLSHORTLINE', # Short Line Candle + 'CDLSPINNINGTOP', # Spinning Top + 'CDLSTALLEDPATTERN', # Stalled Pattern + 'CDLSTICKSANDWICH', # Stick Sandwich + # Takuri (Dragonfly Doji with very long lower shadow) + 'CDLTAKURI', + 'CDLTASUKIGAP', # Tasuki Gap + 'CDLTHRUSTING', # Thrusting Pattern + 'CDLTRISTAR', # Tristar Pattern + 'CDLUNIQUE3RIVER', # Unique 3 River + 'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows + 'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods + + }, + 'Statistic Functions': { + 'BETA', # Beta + 'CORREL', # Pearson's Correlation Coefficient (r) + 'LINEARREG', # Linear Regression + 'LINEARREG_ANGLE', # Linear Regression Angle + 'LINEARREG_INTERCEPT', # Linear Regression Intercept + 'LINEARREG_SLOPE', # Linear Regression Slope + 'STDDEV', # Standard Deviation + 'TSF', # Time Series Forecast + 'VAR', # Variance + } + +} +god_genes = set() +########################### SETTINGS ############################## + +# god_genes = {'SMA'} +god_genes |= all_god_genes['Overlap Studies'] +god_genes |= all_god_genes['Momentum Indicators'] +god_genes |= all_god_genes['Volume Indicators'] +god_genes |= all_god_genes['Volatility Indicators'] +god_genes |= all_god_genes['Price Transform'] +god_genes |= all_god_genes['Cycle Indicators'] +god_genes |= all_god_genes['Pattern Recognition'] +god_genes |= all_god_genes['Statistic Functions'] + +timeperiods = [5, 6, 12, 15, 50, 55, 100, 110] +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator( + dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator( + dataframe, indicator_trend_sma) + + if operator == ">": + condition = ( + dataframe[indicator] > dataframe[crossed_indicator] + ) + elif operator == "=": + condition = ( + np.isclose(dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "<": + condition = ( + dataframe[indicator] < dataframe[crossed_indicator] + ) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) | + (qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator])) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == "CB": + condition = ( + qtpylib.crossed_below( + dataframe[indicator], dataframe[crossed_indicator]) + ) + elif operator == ">R": + condition = ( + dataframe[indicator] > real_num + ) + elif operator == "=R": + condition = ( + np.isclose(dataframe[indicator], real_num) + ) + elif operator == "R": + condition = ( + dataframe[indicator].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div( + dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ dataframe[indicator_trend_sma] + ) + elif operator == "DT": + condition = ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + elif operator == "OT": + condition = ( + + np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]) + ) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] > dataframe[indicator_trend_sma] + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) & + ( + dataframe[indicator] < dataframe[indicator_trend_sma] + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) | + ( + qtpylib.crossed_above( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) & + ( + np.isclose( + dataframe[indicator], + dataframe[indicator_trend_sma] + ) + ) + ) + + return condition, dataframe + + +class GodStraNew(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 #################### + + # TODO: Its not dry code! + # Buy Hyperoptable Parameters/Spaces. + buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy') + buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy') + buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy') + + buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy') + buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy') + buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy') + + buy_operator0 = CategoricalParameter(operators, default="/ DataFrame: + ''' + It's good to calculate all indicators in all time periods here and so optimize the strategy. + But this strategy can take much time to generate anything that may not use in his optimization. + I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed. + Also, this method (populate_indicators) just calculates default value of hyperoptable params + so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators + ''' + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + + # TODO: Its not dry code! + buy_indicator = self.buy_indicator0.value + buy_crossed_indicator = self.buy_crossed_indicator0.value + buy_operator = self.buy_operator0.value + buy_real_num = self.buy_real_num0.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + # backup + buy_indicator = self.buy_indicator1.value + buy_crossed_indicator = self.buy_crossed_indicator1.value + buy_operator = self.buy_operator1.value + buy_real_num = self.buy_real_num1.value + + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + buy_indicator = self.buy_indicator2.value + buy_crossed_indicator = self.buy_crossed_indicator2.value + buy_operator = self.buy_operator2.value + buy_real_num = self.buy_real_num2.value + condition, dataframe = condition_generator( + dataframe, + buy_operator, + buy_indicator, + buy_crossed_indicator, + buy_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'buy']=1 + + # print(len(dataframe.keys())) + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + conditions = list() + # TODO: Its not dry code! + sell_indicator = self.sell_indicator0.value + sell_crossed_indicator = self.sell_crossed_indicator0.value + sell_operator = self.sell_operator0.value + sell_real_num = self.sell_real_num0.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator1.value + sell_crossed_indicator = self.sell_crossed_indicator1.value + sell_operator = self.sell_operator1.value + sell_real_num = self.sell_real_num1.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + sell_indicator = self.sell_indicator2.value + sell_crossed_indicator = self.sell_crossed_indicator2.value + sell_operator = self.sell_operator2.value + sell_real_num = self.sell_real_num2.value + condition, dataframe = condition_generator( + dataframe, + sell_operator, + sell_indicator, + sell_crossed_indicator, + sell_real_num + ) + conditions.append(condition) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'sell']=1 + return dataframe + + diff --git a/GodStraNew.txt b/GodStraNew.txt new file mode 100644 index 0000000..24bcaac --- /dev/null +++ b/GodStraNew.txt @@ -0,0 +1,72 @@ +Result for strategy GodStraNew +=========================================================== BACKTESTING REPORT =========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| SAND/USDT | 10 | 13.46 | 134.59 | 134.726 | 13.47 | 1 day, 17:48:00 | 8 0 2 80.0 | +| XRP/USDT | 7 | 17.80 | 124.59 | 124.713 | 12.47 | 1 day, 4:14:00 | 6 0 1 85.7 | +| GALA/USDT | 2 | 38.16 | 76.32 | 76.400 | 7.64 | 11:02:00 | 2 0 0 100 | +| BNB/USDT | 11 | 6.83 | 75.08 | 75.156 | 7.52 | 2 days, 22:45:00 | 9 0 2 81.8 | +| TRX/USDT | 6 | 9.74 | 58.44 | 58.499 | 5.85 | 3 days, 13:46:00 | 6 0 0 100 | +| ZEC/USDT | 3 | 14.89 | 44.66 | 44.700 | 4.47 | 1 day, 21:40:00 | 3 0 0 100 | +| IOTX/USDT | 8 | 5.40 | 43.18 | 43.222 | 4.32 | 3 days, 4:43:00 | 5 1 2 62.5 | +| EGLD/USDT | 3 | 13.35 | 40.04 | 40.076 | 4.01 | 2 days, 1:53:00 | 3 0 0 100 | +| ETH/USDT | 2 | 20.01 | 40.03 | 40.066 | 4.01 | 1 day, 7:05:00 | 2 0 0 100 | +| SOL/USDT | 4 | 9.19 | 36.78 | 36.813 | 3.68 | 19:50:00 | 3 0 1 75.0 | +| CELR/USDT | 3 | 11.94 | 35.81 | 35.848 | 3.58 | 2 days, 13:58:00 | 3 0 0 100 | +| AVAX/USDT | 2 | 16.58 | 33.17 | 33.200 | 3.32 | 2 days, 2:22:00 | 2 0 0 100 | +| ADA/USDT | 4 | 7.92 | 31.68 | 31.713 | 3.17 | 1 day, 10:49:00 | 3 0 1 75.0 | +| ROSE/USDT | 4 | 6.65 | 26.59 | 26.613 | 2.66 | 2 days, 14:16:00 | 3 0 1 75.0 | +| BTC/USDT | 5 | 3.79 | 18.94 | 18.955 | 1.90 | 3 days, 10:25:00 | 4 0 1 80.0 | +| TOTAL | 74 | 11.08 | 819.88 | 820.697 | 82.07 | 2 days, 6:51:00 | 62 1 11 83.8 | +=========================================================== BUY TAG STATS =========================================================== +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------| +| TOTAL | 74 | 11.08 | 819.88 | 820.697 | 82.07 | 2 days, 6:51:00 | 62 1 11 83.8 | +===================================================== SELL REASON STATS ===================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 63 | 62 1 0 100 | 15.28 | 962.59 | 963.556 | 64.17 | +| stop_loss | 11 | 0 0 11 0 | -12.97 | -142.72 | -142.859 | -9.51 | +====================================================== LEFT OPEN TRADES REPORT ====================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|--------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------| +| TOTAL | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 74 / 0.23 | +| Starting balance | 1000.000 USDT | +| Final balance | 1820.697 USDT | +| Absolute profit | 820.697 USDT | +| Total profit % | 82.07% | +| Trades per day | 0.23 | +| Avg. daily profit % | 0.25% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 7400.000 USDT | +| | | +| Best Pair | SAND/USDT 134.59% | +| Worst Pair | BTC/USDT 18.94% | +| Best trade | SAND/USDT 59.74% | +| Worst trade | SOL/USDT -12.97% | +| Best day | 77.900 USDT | +| Worst day | -38.962 USDT | +| Days win/draw/lose | 32 / 224 / 2 | +| Avg. Duration Winners | 2 days, 6:59:00 | +| Avg. Duration Loser | 1 day, 22:00:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 1016.600 USDT | +| Max balance | 1820.697 USDT | +| Drawdown | 51.90% | +| Drawdown | 51.949 USDT | +| Drawdown high | 394.815 USDT | +| Drawdown low | 342.866 USDT | +| Drawdown Start | 2021-01-10 05:20:00 | +| Drawdown End | 2021-01-11 06:40:00 | +| Market change | 2716.79% | +================================================ + diff --git a/Heracles.py b/Heracles.py new file mode 100644 index 0000000..e5c7d3d --- /dev/null +++ b/Heracles.py @@ -0,0 +1,127 @@ +# Heracles Strategy: Strongest Son of GodStra +# ( With just 1 Genome! its a bacteria :D ) +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT:Add to your pairlists inside config.json (Under StaticPairList): +# { +# "method": "AgeFilter", +# "min_days_listed": 100 +# }, +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces roi buy --strategy Heracles +# ###################################################################### +# --- Do not remove these libs --- +from freqtrade.strategy.parameters import IntParameter, DecimalParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- +# Add your lib to import here +# import talib.abstract as ta +import pandas as pd +import ta +from ta.utils import dropna +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np + + +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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.015 + trailing_only_offset_is_reached = True + + ########################################## 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 diff --git a/Heracles.txt b/Heracles.txt new file mode 100644 index 0000000..47f3017 --- /dev/null +++ b/Heracles.txt @@ -0,0 +1,87 @@ +Result for strategy Heracles +=========================================================== BACKTESTING REPORT =========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| SAND/USDT | 100 | 6.54 | 653.55 | 654.205 | 65.42 | 3 days, 4:19:00 | 72 7 21 72.0 | +| SOL/USDT | 91 | 6.05 | 550.81 | 551.356 | 55.14 | 3 days, 11:25:00 | 67 11 13 73.6 | +| IOTX/USDT | 87 | 5.47 | 475.86 | 476.334 | 47.63 | 3 days, 15:17:00 | 53 13 21 60.9 | +| AVAX/USDT | 97 | 4.42 | 428.92 | 429.347 | 42.93 | 3 days, 7:05:00 | 66 11 20 68.0 | +| CELR/USDT | 98 | 4.04 | 396.36 | 396.759 | 39.68 | 3 days, 6:15:00 | 68 8 22 69.4 | +| EGLD/USDT | 82 | 3.32 | 272.19 | 272.459 | 27.25 | 3 days, 21:22:00 | 58 7 17 70.7 | +| ROSE/USDT | 89 | 2.76 | 245.45 | 245.694 | 24.57 | 3 days, 14:27:00 | 54 15 20 60.7 | +| ADA/USDT | 74 | 3.24 | 239.60 | 239.837 | 23.98 | 4 days, 8:01:00 | 51 8 15 68.9 | +| BNB/USDT | 78 | 2.95 | 230.00 | 230.229 | 23.02 | 4 days, 2:22:00 | 49 14 15 62.8 | +| GALA/USDT | 23 | 7.37 | 169.53 | 169.704 | 16.97 | 2 days, 21:36:00 | 16 1 6 69.6 | +| ETH/USDT | 64 | 2.64 | 168.86 | 169.030 | 16.90 | 4 days, 23:19:00 | 45 10 9 70.3 | +| XRP/USDT | 73 | 2.23 | 162.52 | 162.686 | 16.27 | 4 days, 8:38:00 | 47 12 14 64.4 | +| TRX/USDT | 70 | 1.90 | 133.05 | 133.185 | 13.32 | 4 days, 13:53:00 | 44 13 13 62.9 | +| ZEC/USDT | 68 | 1.38 | 93.76 | 93.851 | 9.39 | 4 days, 16:14:00 | 42 12 14 61.8 | +| BTC/USDT | 42 | 1.55 | 65.16 | 65.227 | 6.52 | 7 days, 13:52:00 | 22 15 5 52.4 | +| TOTAL | 1136 | 3.77 | 4285.62 | 4289.906 | 428.99 | 3 days, 23:42:00 | 754 157 225 66.4 | +=========================================================== BUY TAG STATS ============================================================ +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| TOTAL | 1136 | 3.77 | 4285.62 | 4289.906 | 428.99 | 3 days, 23:42:00 | 754 157 225 66.4 | +===================================================== SELL REASON STATS ===================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 905 | 748 157 0 100 | 10.95 | 9908.73 | 9918.64 | 660.58 | +| stop_loss | 216 | 0 0 216 0 | -25.75 | -5561.71 | -5567.27 | -370.78 | +| force_sell | 15 | 6 0 9 40.0 | -4.09 | -61.4 | -61.462 | -4.09 | +========================================================= LEFT OPEN TRADES REPORT ========================================================= +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------| +| SOL/USDT | 1 | 10.52 | 10.52 | 10.526 | 1.05 | 1 day, 7:15:00 | 1 0 0 100 | +| ADA/USDT | 1 | 8.67 | 8.67 | 8.680 | 0.87 | 1 day, 6:45:00 | 1 0 0 100 | +| EGLD/USDT | 1 | 6.62 | 6.62 | 6.625 | 0.66 | 12:20:00 | 1 0 0 100 | +| ZEC/USDT | 1 | 5.44 | 5.44 | 5.450 | 0.54 | 1 day, 15:50:00 | 1 0 0 100 | +| SAND/USDT | 1 | 3.56 | 3.56 | 3.568 | 0.36 | 1 day, 11:50:00 | 1 0 0 100 | +| AVAX/USDT | 1 | 2.05 | 2.05 | 2.055 | 0.21 | 11:25:00 | 1 0 0 100 | +| ETH/USDT | 1 | -7.97 | -7.97 | -7.976 | -0.80 | 8 days, 18:30:00 | 0 0 1 0 | +| CELR/USDT | 1 | -8.43 | -8.43 | -8.443 | -0.84 | 1 day, 22:35:00 | 0 0 1 0 | +| ROSE/USDT | 1 | -8.76 | -8.76 | -8.773 | -0.88 | 2:35:00 | 0 0 1 0 | +| BTC/USDT | 1 | -10.15 | -10.15 | -10.158 | -1.02 | 6 days, 9:10:00 | 0 0 1 0 | +| GALA/USDT | 1 | -10.40 | -10.40 | -10.408 | -1.04 | 1 day, 12:15:00 | 0 0 1 0 | +| TRX/USDT | 1 | -10.65 | -10.65 | -10.662 | -1.07 | 5 days, 3:40:00 | 0 0 1 0 | +| BNB/USDT | 1 | -11.18 | -11.18 | -11.188 | -1.12 | 9 days, 11:25:00 | 0 0 1 0 | +| XRP/USDT | 1 | -14.78 | -14.78 | -14.791 | -1.48 | 10 days, 18:25:00 | 0 0 1 0 | +| IOTX/USDT | 1 | -15.95 | -15.95 | -15.966 | -1.60 | 3 days, 2:45:00 | 0 0 1 0 | +| TOTAL | 15 | -4.09 | -61.40 | -61.462 | -6.15 | 3 days, 14:19:00 | 6 0 9 40.0 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 1136 / 3.52 | +| Starting balance | 1000.000 USDT | +| Final balance | 5289.906 USDT | +| Absolute profit | 4289.906 USDT | +| Total profit % | 428.99% | +| Trades per day | 3.52 | +| Avg. daily profit % | 1.33% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 113600.000 USDT | +| | | +| Best Pair | SAND/USDT 653.55% | +| Worst Pair | BTC/USDT 65.16% | +| Best trade | SAND/USDT 59.74% | +| Worst trade | XRP/USDT -25.75% | +| Best day | 281.693 USDT | +| Worst day | -524.662 USDT | +| Days win/draw/lose | 232 / 38 / 54 | +| Avg. Duration Winners | 2 days, 18:54:00 | +| Avg. Duration Loser | 4 days, 23:38:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 1018.871 USDT | +| Max balance | 5380.309 USDT | +| Drawdown | 1230.25% | +| Drawdown | 1231.483 USDT | +| Drawdown high | 3146.373 USDT | +| Drawdown low | 1914.890 USDT | +| Drawdown Start | 2021-05-07 16:05:00 | +| Drawdown End | 2021-06-22 13:45:00 | +| Market change | 2716.79% | +================================================ diff --git a/Heracles_2.json b/Heracles_2.json new file mode 100644 index 0000000..62cb7df --- /dev/null +++ b/Heracles_2.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "Heracles_2", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "buy": { + "buy_bb_lowerband": 1.04, + "buy_bb_width": 0.03, + "buy_crossed_indicator_shift": 2, + "buy_div_max": 0.65, + "buy_div_min": 0.52, + "buy_indicator_shift": 17, + "buy_max_min": 0.01 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.22599999999999998, + "39": 0.078, + "61": 0.025, + "148": 0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.16, + "trailing_stop_positive_offset": 0.20600000000000002, + "trailing_only_offset_is_reached": true + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-31 20:36:56.362578+00:00" +} \ No newline at end of file diff --git a/Heracles_2.py b/Heracles_2.py new file mode 100644 index 0000000..53b6119 --- /dev/null +++ b/Heracles_2.py @@ -0,0 +1,274 @@ +# Heracles Strategy: Strongest Son of GodStra +# ( With just 1 Genome! its a bacteria :D ) +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT:Add to your pairlists inside config.json (Under StaticPairList): +# { +# "method": "AgeFilter", +# "min_days_listed": 100 +# }, +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces roi buy --strategy Heracles +# ###################################################################### +# --- Do not remove these libs --- +from freqtrade.strategy.parameters import IntParameter, DecimalParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- +# Add your lib to import here +# import talib.abstract as ta +import pandas as pd +import talib.abstract as talib +import ta +from ta.utils import dropna +import freqtrade.vendor.qtpylib.indicators as qtpylib +from functools import reduce +import numpy as np +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +class Heracles_2(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' + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.015 + trailing_only_offset_is_reached = True + + plot_config = { + "main_plot": { + "max50": { + "color": "#dd1384", + "type": "line" + }, + "min50": { + "color": "#850678", + "type": "line" + }, + "min3_1d": { + "color": "#30c310", + "type": "line" + }, + "max3_1d": { + "color": "#e64062", + "type": "line" + }, + "min200": { + "color": "#86c932", + "type": "line" + } + }, + "subplots": { + "Vol": { + "volume10": { + "color": "#7b53f5", + "type": "line" + } + }, + "Percent": { + "max_min": { + "color": "#74effc", + "type": "line" + } + } + } +} + + ########################################## 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') + + #buy_rsi_min = IntParameter(10, 40, default=10, space='buy') + #buy_rsi_max = IntParameter(50, 98, default=90, space='buy') + + buy_max_min = DecimalParameter(0, 0.05, default=0.02, decimals=2, space='buy') + buy_bb_lowerband = DecimalParameter(1, 1.05, default=1, decimals=2, space='buy') + buy_bb_width = DecimalParameter(0.01, 0.15, default=0.065, decimals=2, space='buy') + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0.01) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if (current_profit > 0.01) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + # informative_pairs = [(pair, "5m") for pair in pairs] + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")] + + return informative_pairs + + 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 + ) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max_min'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe['volume_cond'] = (dataframe["volume10"] * dataframe['close'] / 1000 >= 19) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + 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[ + ( + (dataframe['volume10'] * dataframe['close'] / 1000 >= 19) + & (reduce(lambda x, y: x & y, conditions)) + & (dataframe['close_1d'] <= dataframe['open_1d']) + & (dataframe['max_min'] >= self.buy_max_min.value) + & (dataframe['close'] <= dataframe['min200'] * 1.005) + & (dataframe['close'].shift(1) <= dataframe['min200'].shift(1) * 1.005) + & (dataframe['min200'].shift(1) == dataframe['min200']) + & (dataframe['min50'] <= dataframe['min3_1d'] * 1.005) + & (dataframe['close'].shift(1) < dataframe['bb_lowerband'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width'].shift(1) >= self.buy_bb_width.value) + ), + 'buy']=1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Sell strategy Hyperopt will build and use. + """ + # dataframe.loc[ + # (dataframe['close'] >= dataframe['max50'] * 0.998) + # , 'sell'] = 1 + return dataframe diff --git a/HourBasedStrategy.py b/HourBasedStrategy.py new file mode 100644 index 0000000..c8c30db --- /dev/null +++ b/HourBasedStrategy.py @@ -0,0 +1,105 @@ +# Hour Strategy +# In this strategy we try to find the best hours to buy and sell in a day.(in hourly timeframe) +# Because of that you should just use 1h timeframe on this strategy. +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# Requires hyperopt before running. +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy HourBasedStrategy -e 200 + + +from freqtrade.strategy import IntParameter, IStrategy +from pandas import DataFrame + +# -------------------------------- +# Add your lib to import here +# No need to These imports. just for who want to add more conditions: +# import talib.abstract as ta +# import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class HourBasedStrategy(IStrategy): + # SHIB/USDT, 1000$x1:100days + # 158/1000: 51 trades. 29/19/3 Wins/Draws/Losses. Avg profit 4.02%. Median profit 2.48%. Total profit 4867.53438466 USDT ( 486.75%). Avg duration 1 day, 19:38:00 min. Objective: -4.17276 + # buy_params = {"buy_hour_max": 18,"buy_hour_min": 7,} + # sell_params = {"sell_hour_max": 9,"sell_hour_min": 21,} + # minimal_roi = {"0": 0.18,"171": 0.155,"315": 0.075,"1035": 0} + # stoploss = -0.292 + + # SHIB/USDT, 1000$x1:100days + # 36/1000: 113 trades. 55/14/44 Wins/Draws/Losses. Avg profit 2.06%. Median profit 0.00%. Total profit 5126.14785426 USDT ( 512.61%). Avg duration 16:48:00 min. Objective: -4.57837 + # buy_params = {"buy_hour_max": 21,"buy_hour_min": 6,} + # sell_params = {"sell_hour_max": 6,"sell_hour_min": 4,} + # minimal_roi = {"0": 0.247,"386": 0.186,"866": 0.052,"1119": 0} + # stoploss = -0.302 + + # SAND/USDT, 1000$x1:100days + # 72/1000: 158 trades. 67/13/78 Wins/Draws/Losses. Avg profit 1.37%. Median profit 0.00%. Total profit 4274.73622346 USDT ( 427.47%). Avg duration 13:50:00 min. Objective: -4.87331 + # buy_params = {"buy_hour_max": 23,"buy_hour_min": 4,} + # sell_params = {"sell_hour_max": 23,"sell_hour_min": 3,} + # minimal_roi = {"0": 0.482,"266": 0.191,"474": 0.09,"1759": 0} + # stoploss = -0.05 + + # KDA/USDT, 1000$x1:100days + # 7/1000: 65 trades. 40/23/2 Wins/Draws/Losses. Avg profit 6.42%. Median profit 7.59%. Total profit 41120.00939125 USDT ( 4112.00%). Avg duration 1 day, 9:40:00 min. Objective: -8.46089 + # buy_params = {"buy_hour_max": 22,"buy_hour_min": 9,} + # sell_params = {"sell_hour_max": 1,"sell_hour_min": 7,} + # minimal_roi = {"0": 0.517,"398": 0.206,"1003": 0.076,"1580": 0} + # stoploss = -0.338 + + # {KDA/USDT, BTC/USDT, DOGE/USDT, SAND/USDT, ETH/USDT, SOL/USDT}, 1000$x1:100days, ShuffleFilter42 + # 56/1000: 63 trades. 41/19/3 Wins/Draws/Losses. Avg profit 4.60%. Median profit 8.89%. Total profit 11596.50333022 USDT ( 1159.65%). Avg duration 1 day, 14:46:00 min. Objective: -5.76694 + + # Buy hyperspace params: + buy_params = { + "buy_hour_max": 24, + "buy_hour_min": 4, + } + + # Sell hyperspace params: + sell_params = { + "sell_hour_max": 21, + "sell_hour_min": 22, + } + + # ROI table: + minimal_roi = { + "0": 0.528, + "169": 0.113, + "528": 0.089, + "1837": 0 + } + + # Stoploss: + stoploss = -0.10 + + # Optimal timeframe + timeframe = '1h' + + buy_hour_min = IntParameter(0, 24, default=1, space='buy') + buy_hour_max = IntParameter(0, 24, default=0, space='buy') + + sell_hour_min = IntParameter(0, 24, default=1, space='sell') + sell_hour_max = IntParameter(0, 24, default=0, space='sell') + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['hour'] = dataframe['date'].dt.hour + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + min, max = self.buy_hour_min.value, self.buy_hour_max.value + dataframe.loc[ + ( + (dataframe['hour'].between(min, max)) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + min, max = self.sell_hour_min.value, self.sell_hour_max.value + dataframe.loc[ + ( + (dataframe['hour'].between(min, max)) + ), + 'buy'] = 1 + return dataframe diff --git a/HourBasedStrategy.txt b/HourBasedStrategy.txt new file mode 100644 index 0000000..32f1550 --- /dev/null +++ b/HourBasedStrategy.txt @@ -0,0 +1,87 @@ +Result for strategy HourBasedStrategy +=========================================================== BACKTESTING REPORT ========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------| +| SAND/USDT | 256 | 1.81 | 462.34 | 462.800 | 46.28 | 1 day, 2:59:00 | 125 26 105 48.8 | +| SOL/USDT | 248 | 1.74 | 432.15 | 432.585 | 43.26 | 1 day, 4:33:00 | 142 14 92 57.3 | +| IOTX/USDT | 229 | 1.81 | 414.71 | 415.123 | 41.51 | 1 day, 7:16:00 | 110 26 93 48.0 | +| AVAX/USDT | 239 | 1.48 | 354.65 | 355.007 | 35.50 | 1 day, 5:52:00 | 129 17 93 54.0 | +| BNB/USDT | 196 | 1.66 | 325.65 | 325.975 | 32.60 | 1 day, 12:46:00 | 118 17 61 60.2 | +| ADA/USDT | 194 | 1.62 | 314.28 | 314.595 | 31.46 | 1 day, 13:10:00 | 112 18 64 57.7 | +| CELR/USDT | 282 | 1.10 | 309.01 | 309.315 | 30.93 | 1 day, 1:13:00 | 142 16 124 50.4 | +| ROSE/USDT | 223 | 1.34 | 298.59 | 298.886 | 29.89 | 1 day, 8:12:00 | 121 16 86 54.3 | +| EGLD/USDT | 200 | 1.23 | 245.40 | 245.642 | 24.56 | 1 day, 11:11:00 | 111 20 69 55.5 | +| TRX/USDT | 175 | 1.13 | 197.06 | 197.253 | 19.73 | 1 day, 17:16:00 | 104 17 54 59.4 | +| ETH/USDT | 177 | 1.01 | 179.05 | 179.230 | 17.92 | 1 day, 16:57:00 | 104 23 50 58.8 | +| XRP/USDT | 209 | 0.74 | 155.56 | 155.719 | 15.57 | 1 day, 10:32:00 | 106 24 79 50.7 | +| GALA/USDT | 53 | 2.74 | 145.04 | 145.188 | 14.52 | 1 day, 4:33:00 | 27 2 24 50.9 | +| ZEC/USDT | 209 | 0.47 | 99.11 | 99.204 | 9.92 | 1 day, 10:22:00 | 114 16 79 54.5 | +| BTC/USDT | 131 | 0.24 | 31.06 | 31.096 | 3.11 | 2 days, 6:12:00 | 76 25 30 58.0 | +| TOTAL | 3021 | 1.31 | 3963.65 | 3967.618 | 396.76 | 1 day, 9:36:00 | 1641 277 1103 54.3 | +========================================================== BUY TAG STATS =========================================================== +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------| +| TOTAL | 3021 | 1.31 | 3963.65 | 3967.618 | 396.76 | 1 day, 9:36:00 | 1641 277 1103 54.3 | +===================================================== SELL REASON STATS ===================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 1906 | 1629 277 0 100 | 7.92 | 15090.2 | 15105.3 | 1006.02 | +| stop_loss | 1100 | 0 0 1100 0 | -10.18 | -11197.8 | -11209 | -746.52 | +| force_sell | 15 | 12 0 3 80.0 | 4.75 | 71.23 | 71.301 | 4.75 | +======================================================== LEFT OPEN TRADES REPORT ======================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------| +| AVAX/USDT | 1 | 15.62 | 15.62 | 15.633 | 1.56 | 1 day, 7:35:00 | 1 0 0 100 | +| SOL/USDT | 1 | 10.52 | 10.52 | 10.532 | 1.05 | 1 day, 8:35:00 | 1 0 0 100 | +| EGLD/USDT | 1 | 10.01 | 10.01 | 10.016 | 1.00 | 1 day, 19:55:00 | 1 0 0 100 | +| ZEC/USDT | 1 | 8.03 | 8.03 | 8.040 | 0.80 | 1 day, 8:40:00 | 1 0 0 100 | +| IOTX/USDT | 1 | 6.84 | 6.84 | 6.851 | 0.69 | 1 day, 6:45:00 | 1 0 0 100 | +| CELR/USDT | 1 | 6.39 | 6.39 | 6.392 | 0.64 | 1 day, 8:35:00 | 1 0 0 100 | +| XRP/USDT | 1 | 6.32 | 6.32 | 6.327 | 0.63 | 1 day, 6:45:00 | 1 0 0 100 | +| BNB/USDT | 1 | 5.14 | 5.14 | 5.144 | 0.51 | 1 day, 8:30:00 | 1 0 0 100 | +| ROSE/USDT | 1 | 3.86 | 3.86 | 3.867 | 0.39 | 19:55:00 | 1 0 0 100 | +| SAND/USDT | 1 | 2.72 | 2.72 | 2.721 | 0.27 | 19:55:00 | 1 0 0 100 | +| TRX/USDT | 1 | 2.19 | 2.19 | 2.193 | 0.22 | 1 day, 7:25:00 | 1 0 0 100 | +| ETH/USDT | 1 | 0.04 | 0.04 | 0.036 | 0.00 | 1 day, 19:55:00 | 1 0 0 100 | +| ADA/USDT | 1 | -1.42 | -1.42 | -1.419 | -0.14 | 1 day, 19:55:00 | 0 0 1 0 | +| GALA/USDT | 1 | -1.75 | -1.75 | -1.754 | -0.18 | 19:55:00 | 0 0 1 0 | +| BTC/USDT | 1 | -3.27 | -3.27 | -3.277 | -0.33 | 1 day, 19:55:00 | 0 0 1 0 | +| TOTAL | 15 | 4.75 | 71.23 | 71.301 | 7.13 | 1 day, 8:41:00 | 12 0 3 80.0 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 3021 / 9.35 | +| Starting balance | 1000.000 USDT | +| Final balance | 4967.618 USDT | +| Absolute profit | 3967.618 USDT | +| Total profit % | 396.76% | +| Trades per day | 9.35 | +| Avg. daily profit % | 1.23% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 302100.000 USDT | +| | | +| Best Pair | SAND/USDT 462.34% | +| Worst Pair | BTC/USDT 31.06% | +| Best trade | SAND/USDT 120.20% | +| Worst trade | ZEC/USDT -10.18% | +| Best day | 351.483 USDT | +| Worst day | -604.011 USDT | +| Days win/draw/lose | 226 / 6 / 92 | +| Avg. Duration Winners | 1 day, 11:00:00 | +| Avg. Duration Loser | 1 day, 1:56:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 989.810 USDT | +| Max balance | 4972.649 USDT | +| Drawdown | 1128.21% | +| Drawdown | 1129.342 USDT | +| Drawdown high | 3121.246 USDT | +| Drawdown low | 1991.905 USDT | +| Drawdown Start | 2021-05-09 00:05:00 | +| Drawdown End | 2021-06-22 13:50:00 | +| Market change | 2716.79% | +================================================ diff --git a/InformativeSample.py b/InformativeSample.py new file mode 100644 index 0000000..8e00856 --- /dev/null +++ b/InformativeSample.py @@ -0,0 +1,131 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy, merge_informative_pair +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class InformativeSample(IStrategy): + """ + Sample strategy implementing Informative Pairs - compares stake_currency with USDT. + Not performing very well - but should serve as an example how to use a referential pair against USDT. + author@: xmatthias + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 freqtrade -s InformativeSample + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.04 + + # run "populate_indicators" only for new candle + ta_on_candle = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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 [(f"BTC/USDT", '15m')] + + 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. + """ + + dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + if self.dp: + # Get ohlcv data for informative pair at 15m interval. + inf_tf = '15m' + informative = self.dp.get_pair_dataframe(pair=f"BTC/USDT", + timeframe=inf_tf) + + # calculate SMA20 on informative pair + informative['sma20'] = informative['close'].rolling(20).mean() + + # Combine the 2 dataframe + # This will result in a column named 'closeETH' or 'closeBTC' - depending on stake_currency. + dataframe = merge_informative_pair(dataframe, informative, + self.timeframe, inf_tf, ffill=True) + + 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['ema20'] > dataframe['ema50']) & + # stake/USDT above sma(stake/USDT, 20) + (dataframe['close_15m'] > dataframe['sma20_15m']) + ), + '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['ema20'] < dataframe['ema50']) & + # stake/USDT below sma(stake/USDT, 20) + (dataframe['close_15m'] < dataframe['sma20_15m']) + ), + 'sell'] = 1 + return dataframe diff --git a/Ishimoku_1.json b/Ishimoku_1.json new file mode 100644 index 0000000..ab8e00f --- /dev/null +++ b/Ishimoku_1.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_1", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-28 22:33:13.383313+00:00" +} diff --git a/Ishimoku_1.py b/Ishimoku_1.py new file mode 100644 index 0000000..63c16e0 --- /dev/null +++ b/Ishimoku_1.py @@ -0,0 +1,554 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_1(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = False + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + } + }, + "BB": { + "bb_width": { + "color": "white" + }, + # "bb_lower_5": { + # "color": "yellow" + # } + }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + # "rsi_1d": { + # "color": "yellow" + # } + }, + # "Percent": { + # "max_min": { + # "color": "#74effc" + # }, + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi = IntParameter(20, 60, default=45, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if (self.stop_buying is True) & ( + (info_last_candle['percent'] > self.protection_up_percent.value) + | (info_last_candle['percent3'] > self.protection_up_percent3.value) + | (info_last_candle['percent5'] > self.protection_up_percent5.value)): + # print("Enable buying") + self.stop_buying = False + + if self.stop_buying: + allow_to_buy = False + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if self.stop_buying is True: + if (info_last_candle['percent'] > 0) | (info_last_candle['percent3'] > 0) | ( + info_last_candle['percent5'] > 0): + # print("Enable buying") + self.stop_buying = False + else: + if self.stop_buying is False: + if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + self.stop_buying = True + # print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # return 'send_all' + + if (last_candle['pct_change_1_1h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit > last_candle['bb_width'] / 2) & (previous_last_candle['close'] > previous_last_candle['bb_upperband'])\ + & (last_candle['percent'] < -0.005) & ((current_time - trade.open_date_utc).seconds <= 3600): + return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1h')] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair='BTC/USDT', timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['sma7_1h'].shift(1) <= dataframe['sma7_1h']) + & (dataframe['close_1h'] <= dataframe['bb_middleband_1h']) + + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_2.json b/Ishimoku_2.json new file mode 100644 index 0000000..5911ef5 --- /dev/null +++ b/Ishimoku_2.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_2", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-28 22:33:13.383313+00:00" +} diff --git a/Ishimoku_2.py b/Ishimoku_2.py new file mode 100644 index 0000000..cb97aa2 --- /dev/null +++ b/Ishimoku_2.py @@ -0,0 +1,554 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_2(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = False + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + } + }, + "BB": { + "bb_width": { + "color": "white" + }, + # "bb_lower_5": { + # "color": "yellow" + # } + }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + # "rsi_1d": { + # "color": "yellow" + # } + }, + # "Percent": { + # "max_min": { + # "color": "#74effc" + # }, + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi = IntParameter(20, 60, default=45, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if (self.stop_buying is True) & ( + (info_last_candle['percent'] > self.protection_up_percent.value) + | (info_last_candle['percent3'] > self.protection_up_percent3.value) + | (info_last_candle['percent5'] > self.protection_up_percent5.value)): + # print("Enable buying") + self.stop_buying = False + + if self.stop_buying: + allow_to_buy = False + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if self.stop_buying is True: + if (info_last_candle['percent'] > 0) | (info_last_candle['percent3'] > 0) | ( + info_last_candle['percent5'] > 0): + # print("Enable buying") + self.stop_buying = False + else: + if self.stop_buying is False: + if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + self.stop_buying = True + # print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # return 'send_all' + + if (last_candle['pct_change_1_1h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit > last_candle['bb_width'] / 2) & (previous_last_candle['close'] > previous_last_candle['bb_upperband'])\ + & (last_candle['percent'] < -0.005) & ((current_time - trade.open_date_utc).seconds <= 3600): + return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1h')] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair='BTC/USDT', timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + #& (dataframe['close'] < dataframe['sma10']) + #& (dataframe['sma7_1h'].shift(1) <= dataframe['sma7_1h']) + #& (dataframe['close_1h'] <= dataframe['bb_middleband_1h']) + + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_3.json b/Ishimoku_3.json new file mode 100644 index 0000000..7a2f7e5 --- /dev/null +++ b/Ishimoku_3.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_3", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-28 22:33:13.383313+00:00" +} diff --git a/Ishimoku_3.py b/Ishimoku_3.py new file mode 100644 index 0000000..4292a7c --- /dev/null +++ b/Ishimoku_3.py @@ -0,0 +1,554 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_3(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = False + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + } + }, + "BB": { + "bb_width": { + "color": "white" + }, + # "bb_lower_5": { + # "color": "yellow" + # } + }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + # "rsi_1d": { + # "color": "yellow" + # } + }, + # "Percent": { + # "max_min": { + # "color": "#74effc" + # }, + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi = IntParameter(20, 60, default=45, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if (self.stop_buying is True) & ( + (info_last_candle['percent'] > self.protection_up_percent.value) + | (info_last_candle['percent3'] > self.protection_up_percent3.value) + | (info_last_candle['percent5'] > self.protection_up_percent5.value)): + # print("Enable buying") + self.stop_buying = False + + if self.stop_buying: + allow_to_buy = False + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if self.stop_buying is True: + if (info_last_candle['percent'] > 0) | (info_last_candle['percent3'] > 0) | ( + info_last_candle['percent5'] > 0): + # print("Enable buying") + self.stop_buying = False + else: + if self.stop_buying is False: + if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + self.stop_buying = True + # print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # return 'send_all' + + if (last_candle['pct_change_1_1h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit > last_candle['bb_width'] / 2) & (previous_last_candle['close'] > previous_last_candle['bb_upperband'])\ + & (last_candle['percent'] < -0.005) & ((current_time - trade.open_date_utc).seconds <= 3600): + return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1h')] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair='BTC/USDT', timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + #& (dataframe['close'] < dataframe['sma10']) + #& (dataframe['sma7_1h'].shift(1) <= dataframe['sma7_1h']) + & (dataframe['close_1h'] <= dataframe['bb_middleband_1h']) + + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_4.json b/Ishimoku_4.json new file mode 100644 index 0000000..5e7cc9a --- /dev/null +++ b/Ishimoku_4.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_4", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-28 22:33:13.383313+00:00" +} diff --git a/Ishimoku_4.py b/Ishimoku_4.py new file mode 100644 index 0000000..5147e23 --- /dev/null +++ b/Ishimoku_4.py @@ -0,0 +1,554 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_4(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = False + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + } + }, + "BB": { + "bb_width": { + "color": "white" + }, + # "bb_lower_5": { + # "color": "yellow" + # } + }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + # "rsi_1d": { + # "color": "yellow" + # } + }, + # "Percent": { + # "max_min": { + # "color": "#74effc" + # }, + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi = IntParameter(20, 60, default=45, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if (self.stop_buying is True) & ( + (info_last_candle['percent'] > self.protection_up_percent.value) + | (info_last_candle['percent3'] > self.protection_up_percent3.value) + | (info_last_candle['percent5'] > self.protection_up_percent5.value)): + # print("Enable buying") + self.stop_buying = False + + if self.stop_buying: + allow_to_buy = False + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if self.stop_buying is True: + if (info_last_candle['percent'] > 0) | (info_last_candle['percent3'] > 0) | ( + info_last_candle['percent5'] > 0): + # print("Enable buying") + self.stop_buying = False + else: + if self.stop_buying is False: + if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + self.stop_buying = True + # print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # return 'send_all' + + if (last_candle['pct_change_1_1h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit > last_candle['bb_width'] / 2) & (previous_last_candle['close'] > previous_last_candle['bb_upperband'])\ + & (last_candle['percent'] < -0.005) & ((current_time - trade.open_date_utc).seconds <= 3600): + return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1h')] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair='BTC/USDT', timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + #& (dataframe['close'] < dataframe['sma10']) + & (dataframe['sma7_1h'].shift(1) <= dataframe['sma7_1h']) + & (dataframe['close_1h'] <= dataframe['bb_middleband_1h']) + + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_5.json b/Ishimoku_5.json new file mode 100644 index 0000000..7f9ffdd --- /dev/null +++ b/Ishimoku_5.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_5", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-28 22:33:13.383313+00:00" +} diff --git a/Ishimoku_5.py b/Ishimoku_5.py new file mode 100644 index 0000000..f94a2b1 --- /dev/null +++ b/Ishimoku_5.py @@ -0,0 +1,554 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_5(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = False + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + } + }, + "BB": { + "bb_width": { + "color": "white" + }, + # "bb_lower_5": { + # "color": "yellow" + # } + }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + # "rsi_1d": { + # "color": "yellow" + # } + }, + # "Percent": { + # "max_min": { + # "color": "#74effc" + # }, + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi = IntParameter(20, 60, default=45, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # info_last_candle = informative.iloc[-1].squeeze() + # + # if (self.stop_buying is True) & ( + # (info_last_candle['percent'] > self.protection_up_percent.value) + # | (info_last_candle['percent3'] > self.protection_up_percent3.value) + # | (info_last_candle['percent5'] > self.protection_up_percent5.value)): + # # print("Enable buying") + # self.stop_buying = False + # + # if self.stop_buying: + # allow_to_buy = False + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # info_last_candle = informative.iloc[-1].squeeze() + # + # if self.stop_buying is True: + # if (info_last_candle['percent'] > 0) | (info_last_candle['percent3'] > 0) | ( + # info_last_candle['percent5'] > 0): + # # print("Enable buying") + # self.stop_buying = False + # else: + # if self.stop_buying is False: + # if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + # | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + # | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + # self.stop_buying = True + # # print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # return 'send_all' + + if (last_candle['pct_change_1_1h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit > last_candle['bb_width'] / 2) & (previous_last_candle['close'] > previous_last_candle['bb_upperband'])\ + & (last_candle['percent'] < -0.005) & ((current_time - trade.open_date_utc).seconds <= 3600): + return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1h')] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair='BTC/USDT', timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['sma7_1h'].shift(1) <= dataframe['sma7_1h']) + # & (dataframe['close_1h'] <= dataframe['bb_middleband_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_6.json b/Ishimoku_6.json new file mode 100644 index 0000000..950bd05 --- /dev/null +++ b/Ishimoku_6.json @@ -0,0 +1,77 @@ +{ + "strategy_name": "Ishimoku_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.08, + "buy_rsi": 70 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": true, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": true, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 85, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01, + "sell_rsi5_1h": 41 + }, + "protection": { + "btc_allow_to_buy": 0.0, + "btc_fall_1": -0.02, + "btc_fall_3": -0.1, + "btc_fall_5": -0.04, + "btc_sell_all_profit": -0.42 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-13 11:54:30.328274+00:00" +} \ No newline at end of file diff --git a/Ishimoku_6.py b/Ishimoku_6.py new file mode 100644 index 0000000..8821562 --- /dev/null +++ b/Ishimoku_6.py @@ -0,0 +1,728 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +from technical import pivots_points +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_6(IStrategy): + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = {} + max_open_trades = 5 + stop_buy_for_all = False + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "bb_lowerband": { + "color": "#da59a6" + }, + "bb_upperband": { + "color": "#da59a6" + }, + "sar": { + "color": "#4f9f51" + }, + "enter_tag": { + "color": "#b400c7", + "type": "line" + }, + "sma10": { + "color": "#271db5", + "type": "line" + }, + "r1": { + "color": "#3181d9", + "type": "line" + }, + "r2": { + "color": "#e31837", + "type": "line" + }, + "r3": { + "color": "#a0f99b", + "type": "line" + }, + "s1": { + "color": "#ee7d7d", + "type": "line" + }, + "s2": { + "color": "#740346", + "type": "line" + }, + "s3": { + "color": "#ff2a10", + "type": "line" + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + }, + "ichimoku_conversion_line": { + "color": "#83a12a", + "type": "line" + } + }, + "BB": { + "ichimoku_cut_below_1h": { + "color": "#9ee22c", + "type": "line" + }, + "ichimoku_cut_above_1h": { + "color": "#aa2a1f", + "type": "line" + } + }, + "Cond": { + "cond1": { + "color": "yellow" + } + }, + "Rsi": { + "rsi": { + "color": "pink" + }, + "rsi_5_1h": { + "color": "#34e97f", + "type": "line" + }, + "rsi_1h": { + "color": "#3ce8ea", + "type": "line" + }, + "rsi5": { + "color": "#47f377", + "type": "line" + } + }, + "Percent": { + "percent5": { + "color": "#2250f1", + "type": "line" + }, + "percent10": { + "color": "#e02bbb", + "type": "line" + } + } + } + } + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.10, space='buy') + buy_rsi = IntParameter(20, 80, default=70, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_rsi5_1h = IntParameter(30, 80, default=41, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + btc_fall_1 = DecimalParameter(-0.1, 0, decimals=2, default=0.0, space='protection') + btc_fall_3 = DecimalParameter(-0.1, 0, decimals=2, default=0.0, space='protection') + btc_fall_5 = DecimalParameter(-0.1, 0, decimals=2, default=0.0, space='protection') + btc_sell_all_profit = DecimalParameter(-0.5, 0, decimals=2, default=0.0, space='protection') + btc_allow_to_buy = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + def bot_loop_start(self, **kwargs) -> None: + inf_tf = '5m' + pairs = self.dp.current_whitelist() + print("Calcul des pairs informatives") + for pairname in pairs: + self.stop_buying[pairname] = True + print("Fin Calcul des pairs informatives") + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buy_for_all is True: + if info_last_candle['pct_change_1_1d'] > self.btc_allow_to_buy.value: + self.stop_buy_for_all = False + logger.info("1 -BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + else: + logger.info("1 -BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + return False + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + # if (info_last_candle['rsi_1h'] < self.protection_RSI_enable.value) & (self.stop_buying[pair] is True): + # print("Enable buying", pair) + # self.stop_buying[pair] = False + + # if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] > 20) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']) \ + # & (info_last_candle['max_rsi_1h'] < 50): + # print("2 - Enable buying", pair, info_last_candle['date'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + if self.stop_buying[pair] is True: + if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + # , (info_last_candle['trend_ichimoku_base'], + # (info_last_candle['close'] < info_last_candle['sma10']), + # (info_previous_last_candle['sma10'], info_last_candle['sma10']))) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (self.stop_buy_for_all is True) & (current_profit < self.btc_sell_all_profit.value): + return "btc_fall" + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if self.stop_buying[pair] is False: + if (last_candle['rsi5'] < 16): + logger.info("0 - Disable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = True + if (current_profit > 0): + return "stop_buying" + + if self.stop_buying[pair] is True: + if (last_candle['rsi5'] > 20) & (last_candle['percent10'] > 0): + logger.info("1 - Enable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + # print("1 - Enable buying ", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = False + + + if (btc_last_candle['percent5'] < self.btc_fall_5.value) | (btc_last_candle['percent3'] < self.btc_fall_3.value) | ( + btc_last_candle['percent'] < self.btc_fall_1.value): + self.stop_buy_for_all = True + return "btc_fall" + + if last_candle['rsi_5_1h'] < self.sell_rsi5_1h.value: + if (current_profit > 0.01) & ((last_candle['percent'] < -0.003) | (last_candle['percent3'] < -0.003) | ( + last_candle['percent5'] < -0.003) | (last_candle['rsi5'] < 41)): + return 'b_percent_quick' + + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < self.sell_b_RSI2_percent.value): + # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) \ + & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): + # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + informative_pairs = [('BTC/USDT', '1d')] + pairs = self.dp.current_whitelist() + informative_pairs += [(pair, '1h') for pair in pairs] + # self.stop_buying[pair] = [(pair, False) for pair in pairs] + # print(self.stop_buying) + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['ichimoku_conversion_line'] = ta.trend.ichimoku_conversion_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min5'] = talib.MIN(dataframe['close'], timeperiod=5) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma5_ma_2'] = dataframe['sma5'].pct_change(2) + dataframe['sma5_ma_5'] = dataframe['sma5'].pct_change(5) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + dataframe['ichimoku_conversion_line_1'] = dataframe['ichimoku_conversion_line'] + dataframe['trend_ichimoku_base_1'] = dataframe['trend_ichimoku_base'] + dataframe['trend_kst_diff_1'] = dataframe['trend_kst_diff'] + + tib = dataframe['ichimoku_conversion_line'] + dataframe['ichimoku_conversion_line'] = (tib - tib.min()) / (tib.max() - tib.min()) + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + pivot = pivots_points.pivots_points(dataframe, 72, 3) + dataframe['r1'] = pivot['r1'] + dataframe['r2'] = pivot['r2'] + dataframe['r3'] = pivot['r3'] + dataframe['s1'] = pivot['s1'] + dataframe['s2'] = pivot['s2'] + dataframe['s3'] = pivot['s3'] + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair="BTC/USDT", timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative["rsi_ma"] = informative["rsi"].rolling(5).mean() + informative['max_rsi'] = talib.MAX(informative['rsi'], timeperiod=10) + informative['min_rsi'] = talib.MIN(informative['rsi'], timeperiod=10) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + informative['ichimoku_conversion_line'] = ta.trend.ichimoku_conversion_line( + informative['high'], + informative['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + + informative['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + informative['high'], + informative['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + informative['ichimoku_conversion_line_1'] = informative['ichimoku_conversion_line'] + informative['trend_ichimoku_base_1'] = informative['trend_ichimoku_base'] + + informative['ichimoku_cut_below'] = qtpylib.crossed_below(informative['ichimoku_conversion_line_1'], + informative['trend_ichimoku_base_1']) + informative['ichimoku_cut_above'] = qtpylib.crossed_above(informative['ichimoku_conversion_line_1'], + informative['trend_ichimoku_base_1']) + + tib = informative['ichimoku_conversion_line'] + informative['ichimoku_conversion_line'] = (tib - tib.min()) / (tib.max() - tib.min()) + tib = informative['trend_ichimoku_base'] + informative['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + # tkd = informative['trend_kst_diff'] + # informative['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= 0.03) #self.buy_base.value) + # & (dataframe['rsi'] < self.buy_rsi.value) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['pct_change_1_1h'] < 0) + # # & (dataframe['close'] <= dataframe['min50'] * (1 + dataframe['bb_width'] / 1.8)) + # ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_b') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.08) # self.buy_base.value) + # & (dataframe['rsi'] < 42) #self.buy_rsi.value) + # & (dataframe['sma5_ma_2'] > - 0.002) + & (dataframe['close'].shift(2) < dataframe['sma10'].shift(2)) + & (dataframe['close'].shift(2) < dataframe['sar'].shift(2)) + & (dataframe['open'].shift(2) < dataframe['sar'].shift(2)) + # & (dataframe['close'] < dataframe['bb_lowerband'] + dataframe['bb_width'] / 3) + & (dataframe['sma10'].shift(1) * 1.001 < dataframe['sma10']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['rsi_5_1h'] > 35) + # & (dataframe['close'] <= dataframe['min50'] * (1 + dataframe['bb_width'] / 1.8)) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_h') + + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= 0.08) + # & (dataframe['open'] == dataframe['min50']) + # & (dataframe['min50'].shift(4) == dataframe['min50']) + # ), ['buy', 'buy_tag']] = (1, 'buy_test') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Ishimoku_6Best.json b/Ishimoku_6Best.json new file mode 100644 index 0000000..2b8c44f --- /dev/null +++ b/Ishimoku_6Best.json @@ -0,0 +1,81 @@ +{ + "strategy_name": "Ishimoku_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.05, + "buy_rsi": 42 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "bb_width_force_sell": 1.0, + "my_stoploss_percent": 0.38, + "my_stoploss_profit": 0.28, + "protection_down_percent": 0.019, + "protection_down_percent3": 0.05, + "protection_down_percent5": 0.02, + "protection_up_percent": -0.013, + "protection_up_percent3": -0.02, + "protection_up_percent5": -0.01, + "send_all_percent": 0.46 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-30 14:34:22.357711+00:00" +} \ No newline at end of file diff --git a/Ishimoku_7.json b/Ishimoku_7.json new file mode 100644 index 0000000..198d8e6 --- /dev/null +++ b/Ishimoku_7.json @@ -0,0 +1,70 @@ +{ + "strategy_name": "Ishimoku_7", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.08, + "buy_rsi": 78 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": true, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": true, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 85, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-07 18:58:24.628568+00:00" +} \ No newline at end of file diff --git a/Ishimoku_7.py b/Ishimoku_7.py new file mode 100644 index 0000000..0610082 --- /dev/null +++ b/Ishimoku_7.py @@ -0,0 +1,752 @@ +# +# +# +from datetime import timedelta, datetime +from typing import Optional +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +import logging +from technical import pivots_points +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +logger = logging.getLogger(__name__) + + +class Ishimoku_7(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = {} + max_open_trades = 5 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "bb_lowerband": { + "color": "#da59a6" + }, + "bb_upperband": { + "color": "#da59a6" + }, + "sar": { + "color": "#4f9f51" + }, + "enter_tag": { + "color": "#b400c7", + "type": "line" + }, + "sma10": { + "color": "#271db5", + "type": "line" + }, + "r1": { + "color": "#3181d9", + "type": "line" + }, + "r2": { + "color": "#e31837", + "type": "line" + }, + "r3": { + "color": "#a0f99b", + "type": "line" + }, + "s1": { + "color": "#ee7d7d", + "type": "line" + }, + "s2": { + "color": "#740346", + "type": "line" + }, + "s3": { + "color": "#ff2a10", + "type": "line" + } + }, + "subplots": { + "Ind": { + "trend_ichimoku_base": { + "color": "#dd1384" + }, + "trend_kst_diff": { + "color": "#850678" + }, + "ichimoku_conversion_line": { + "color": "#83a12a", + "type": "line" + } + }, + "BB": { + "ichimoku_cut_below_1h": { + "color": "#9ee22c", + "type": "line" + }, + "ichimoku_cut_above_1h": { + "color": "#aa2a1f", + "type": "line" + } + }, + "Cond": { + "cond1": { + "color": "yellow" + } + }, + "Rsi": { + "rsi": { + "color": "pink" + }, + "rsi_5_1h": { + "color": "#34e97f", + "type": "line" + }, + "rsi_1h": { + "color": "#3ce8ea", + "type": "line" + }, + "rsi5": { + "color": "#47f377", + "type": "line" + } + }, + "Percent": { + "percent5": { + "color": "#2250f1", + "type": "line" + }, + "percent10": { + "color": "#e02bbb", + "type": "line" + } + } + } +} + trades = list() + + buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.10, space='buy') + buy_rsi = IntParameter(20, 80, default=70, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_rsi5_1h = IntParameter(30, 80, default=41, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + # protection_max_allowed_dd = DecimalParameter(0, 1, decimals=2, default=0.04, space='protection') + # protection_stop = IntParameter(0, 100, default=48, space='protection') + # protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection') + # lookback = IntParameter(0, 200, default=48, space='protection') + # trade_limit = IntParameter(0, 10, default=2, space='protection') + + # protection_down_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='protection') + # protection_down_percent3 = DecimalParameter(0, 0.05, decimals=2, default=0.02, space='protection') + # protection_down_percent5 = DecimalParameter(0, 0.05, decimals=2, default=0.03, space='protection') + # protection_up_percent = DecimalParameter(-0.02, 0.02, decimals=3, default=0.0, space='protection') + # protection_up_percent3 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + # protection_up_percent5 = DecimalParameter(-0.02, 0.05, decimals=2, default=0.0, space='protection') + + # protection_RSI_enable = IntParameter(10, 50, default=30, space='protection') + # protection_RSI_disable = IntParameter(50, 90, default=65, space='protection') + + # send_all_percent = DecimalParameter(0, 0.5, decimals=2, default=0.0, space='protection') + # bb_width_force_sell = DecimalParameter(1, 3, decimals=1, default=0.0, space='protection') + # my_stoploss_percent = DecimalParameter(0, 0.5, decimals=2, default=0.01, space='protection') + # my_stoploss_profit = DecimalParameter(0, 0.5, decimals=2, default=0, space='protection') + + def bot_loop_start(self, **kwargs) -> None: + inf_tf = '5m' + pairs = self.dp.current_whitelist() + # print( "Calcul des pairs informatives") + for pairname in pairs: + self.stop_buying[pairname] = True + # print( "Fin Calcul des pairs informatives") + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe=self.timeframe) + # # current_candle = informative.iloc[-1].squeeze() + # + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if current > 50000: + # self.max_open_trades = 2 + # proposed_stake = self.config['stake_amount'] / 2 + # else: + # if current > 32000: + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # proposed_stake = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # proposed_stake = self.config['stake_amount'] + # + # return min(max_stake, proposed_stake) + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 10 + }, + # { + # "method": "MaxDrawdown", + # "lookback_period_candles": self.lookback.value, + # "trade_limit": self.trade_limit.value, + # "stop_duration_candles": self.protection_stop.value, + # "max_allowed_drawdown": self.protection_max_allowed_dd.value, + # "only_per_pair": False + # } + ] + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + # print("enable buying tag", pair) + self.stop_buying[pair] = False + # if (info_last_candle['rsi_1h'] < self.protection_RSI_enable.value) & (self.stop_buying[pair] is True): + # print("Enable buying", pair) + # self.stop_buying[pair] = False + + #if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] > 20) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']) \ + # & (info_last_candle['max_rsi_1h'] < 50): + # print("2 - Enable buying", pair, info_last_candle['date'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + if self.stop_buying[pair] is True: + if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + # print("3 - cancel buying", pair, info_last_candle['date']) + # else: + # print("3 - accept buying", pair, info_last_candle['date'], (info_last_candle['trend_ichimoku_base'], + # (info_last_candle['close'] < info_last_candle['sma10']), + # (info_previous_last_candle['sma10'], info_last_candle['sma10']))) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + # print("enable buying tag", pair) + self.stop_buying[pair] = False + + if self.stop_buying[pair] is False: + if (last_candle['rsi5'] < 16): + # print("0 - Disable buying", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = True + if (current_profit > 0): + return "stop_buying" + + if self.stop_buying[pair] is True: + if (last_candle['rsi5'] > 20) & (last_candle['percent10'] > 0): + # print("1 - Enable buying ", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = False + + # if self.stop_buying[pair] is False: + # if ((info_previous_last_candle['rsi_5_1h'] > 78) & (info_last_candle['pct_change_1_1h'] < - 0.005)) | \ + # (info_last_candle['rsi_5_1h'] > 88): + # print("0 - Disable buying", pair, info_last_candle['date'], info_previous_last_candle['rsi_5_1h'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = True + # + # if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] < 30) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_previous_last_candle['rsi_5_1h'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + # if self.stop_buying is True: + # if (info_last_candle['percent'] > self.protection_up_percent.value) \ + # & (info_last_candle['percent3'] > self.protection_up_percent3.value): + # # print("Enable buying") + # self.stop_buying = False + # else: + # if self.stop_buying is False: + # if (info_last_candle['percent'] < - self.protection_down_percent.value) \ + # | (info_last_candle['percent3'] < - self.protection_down_percent3.value) \ + # | (info_last_candle['percent5'] < - self.protection_down_percent5.value): + # self.stop_buying = True + # #print("Disable buying", info_last_candle['percent'], info_last_candle['percent3'], info_last_candle['percent5']) + # # if (current_profit < - self.send_all_percent.value): + # return 'send_all' + + #if (current_profit < -0.08) & (last_candle['rsi5'] < 10) & (btc_last_candle['close'] > 30000): + # return "send_rsi5"; + + # if (current_profit < - self.my_stoploss_profit.value) & (info_last_candle['percent20'] < - self.my_stoploss_percent.value): + # return 'my_stoploss' + + if last_candle['rsi_5_1h'] < self.sell_rsi5_1h.value: + if (current_profit > 0.01) & ((last_candle['percent'] < -0.003) | (last_candle['percent3'] < -0.003) | ( + last_candle['percent5'] < -0.003) | (last_candle['rsi5'] < 41)): + return 'b_percent_quick' + + #if (current_profit > last_candle['bb_width'] / self.bb_width_force_sell.value)\ + # & (last_candle['percent5'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600): + # return 'b_bb_width' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): + # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) \ + & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | ( + last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): + # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # informative_pairs = [('BTC/USDT', '1h')] + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1h') for pair in pairs] + #self.stop_buying[pair] = [(pair, False) for pair in pairs] + #print(self.stop_buying) + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['ichimoku_conversion_line'] = ta.trend.ichimoku_conversion_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min5'] = talib.MIN(dataframe['close'], timeperiod=5) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + dataframe['ichimoku_conversion_line_1'] = dataframe['ichimoku_conversion_line'] + dataframe['trend_ichimoku_base_1'] = dataframe['trend_ichimoku_base'] + dataframe['trend_kst_diff_1'] = dataframe['trend_kst_diff'] + + tib = dataframe['ichimoku_conversion_line'] + dataframe['ichimoku_conversion_line'] = (tib - tib.min()) / (tib.max() - tib.min()) + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + pivot = pivots_points.pivots_points(dataframe, 72, 3) + dataframe['r1'] = pivot['r1'] + dataframe['r2'] = pivot['r2'] + dataframe['r3'] = pivot['r3'] + dataframe['s1'] = pivot['s1'] + dataframe['s2'] = pivot['s2'] + dataframe['s3'] = pivot['s3'] + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative["rsi_ma"] = informative["rsi"].rolling(5).mean() + informative['max_rsi'] = talib.MAX(informative['rsi'], timeperiod=10) + informative['min_rsi'] = talib.MIN(informative['rsi'], timeperiod=10) + informative['sma7'] = talib.SMA(informative, timeperiod=7) + informative['pct_change_1'] = informative['close'].pct_change(1) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + informative['ichimoku_conversion_line'] = ta.trend.ichimoku_conversion_line( + informative['high'], + informative['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + + informative['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + informative['high'], + informative['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + informative['ichimoku_conversion_line_1'] = informative['ichimoku_conversion_line'] + informative['trend_ichimoku_base_1'] = informative['trend_ichimoku_base'] + + informative['ichimoku_cut_below'] = qtpylib.crossed_below(informative['ichimoku_conversion_line_1'], informative['trend_ichimoku_base_1']) + informative['ichimoku_cut_above'] = qtpylib.crossed_above(informative['ichimoku_conversion_line_1'], informative['trend_ichimoku_base_1']) + + tib = informative['ichimoku_conversion_line'] + informative['ichimoku_conversion_line'] = (tib - tib.min()) / (tib.max() - tib.min()) + tib = informative['trend_ichimoku_base'] + informative['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + # tkd = informative['trend_kst_diff'] + # informative['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= 0.03) #self.buy_base.value) + # & (dataframe['rsi'] < self.buy_rsi.value) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['pct_change_1_1h'] < 0) + # # & (dataframe['close'] <= dataframe['min50'] * (1 + dataframe['bb_width'] / 1.8)) + # ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_b') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi_1h'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['sma10'].shift(1) * 1.001 < dataframe['sma10']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['rsi_5_1h'] > 35) + # & (dataframe['close'] <= dataframe['min50'] * (1 + dataframe['bb_width'] / 1.8)) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_h') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_real.value + # OPR = self.sell_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == " 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 diff --git a/MyStrategy.py b/MyStrategy.py new file mode 100644 index 0000000..f428d75 --- /dev/null +++ b/MyStrategy.py @@ -0,0 +1,362 @@ +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy as np # noqa + + +def activate(x): + return np.tanh(x) # tanh + +params = { + '0-0-0-w': -0.53814, + '0-0-bias': -0.96407, + '1-0-0-w': -0.49249, + '10-0-0-w': 0.08845, + '11-0-0-w': -0.14317, + '12-0-0-w': 0.00923, + '13-0-0-w': 0.30464, + '14-0-0-w': -0.35835, + '15-0-0-w': -0.49712, + '16-0-0-w': 0.76135, + '17-0-0-w': -0.75257, + '18-0-0-w': -0.04622, + '19-0-0-w': 0.10012, + '2-0-0-w': -0.23534, + '20-0-0-w': -0.04553, + '21-0-0-w': -0.35334, + '22-0-0-w': 0.17952, + '23-0-0-w': 0.44446, + '24-0-0-w': -0.15875, + '25-0-0-w': 0.97565, + '26-0-0-w': -0.89948, + '27-0-0-w': 0.61777, + '28-0-0-w': -0.60204, + '29-0-0-w': -0.85229, + '3-0-0-w': 0.47262, + '30-0-0-w': -0.52791, + '31-0-0-w': 0.98494, + '4-0-0-w': -0.54942, + '5-0-0-w': 0.40523, + '6-0-0-w': 0.4723, + '7-0-0-w': 0.63297, + '8-0-0-w': 0.07159, + '9-0-0-w': -0.86791, + 'adx-bias': -0.48719, + 'ao-bias': -0.87518, + 'aroonosc-bias': -0.56096, + 'bb_percent-bias': -0.98703, + 'bb_width-bias': -0.73742, + 'cci-bias': 0.47039, + 'end-0-w': -0.81658, + 'end-bias': 0.74656, + 'fastd-bias': -0.2793, + 'fisher_rsi_norm-bias': -0.36065, + 'kc_percent-bias': 0.76707, + 'kc_width-bias': 0.5489, + 'macd-bias': 0.55448, + 'macdhist-bias': -0.83133, + 'macdsignal-bias': 0.30828, + 'mfi-bias': -0.13097, + 'roc-bias': -0.78885, + 'rsi-bias': 0.9856, + 'sar-bias': 0.43812, + 'sma10-bias': -0.39019, + 'sma100-bias': 0.03558, + 'sma21-bias': 0.07457, + 'sma3-bias': 0.93633, + 'sma5-bias': -0.93329, + 'sma50-bias': -0.60637, + 'tema10-bias': -0.45946, + 'tema100-bias': 0.1662, + 'tema21-bias': 0.68466, + 'tema3-bias': 0.25368, + 'tema5-bias': -0.88818, + 'tema50-bias': 0.3019, + 'uo-bias': 0.71019, + 'wbb_percent-bias': -0.55964, + 'wbb_width-bias': 0.23523, + + 's-0-0-0-w': 0.85409, + 's-0-0-bias': -0.04613, + 's-1-0-0-w': -0.14997, + 's-10-0-0-w': -0.67008, + 's-11-0-0-w': -0.40221, + 's-12-0-0-w': 0.64553, + 's-13-0-0-w': 0.22838, + 's-14-0-0-w': 0.99977, + 's-15-0-0-w': 0.89363, + 's-16-0-0-w': -0.88212, + 's-17-0-0-w': -0.71813, + 's-18-0-0-w': 0.41602, + 's-19-0-0-w': -0.48389, + 's-2-0-0-w': 0.09649, + 's-20-0-0-w': 0.64273, + 's-21-0-0-w': -0.31671, + 's-22-0-0-w': 0.9663, + 's-23-0-0-w': 0.00229, + 's-24-0-0-w': 0.96244, + 's-25-0-0-w': -0.24513, + 's-26-0-0-w': 0.52312, + 's-27-0-0-w': 0.44742, + 's-28-0-0-w': -0.03916, + 's-29-0-0-w': 0.88882, + 's-3-0-0-w': -0.32112, + 's-30-0-0-w': -0.70886, + 's-31-0-0-w': -0.42672, + 's-4-0-0-w': -0.55265, + 's-5-0-0-w': 0.56105, + 's-6-0-0-w': 0.47436, + 's-7-0-0-w': 0.58136, + 's-8-0-0-w': -0.48308, + 's-9-0-0-w': -0.16024, + 's-adx-bias': -0.4091, + 's-ao-bias': 0.76889, + 's-aroonosc-bias': 0.16228, + 's-bb_percent-bias': 0.19407, + 's-bb_width-bias': 0.11795, + 's-cci-bias': 0.8379, + 's-end-0-w': -0.14648, + 's-end-bias': -0.85697, + 's-fastd-bias': -0.00581, + 's-fisher_rsi_norm-bias': -0.05253, + 's-kc_percent-bias': -0.3562, + 's-kc_width-bias': 0.67451, + 's-macd-bias': -0.17742, + 's-macdhist-bias': -0.58328, + 's-macdsignal-bias': -0.79847, + 's-mfi-bias': -0.48236, + 's-roc-bias': -0.5914, + 's-rsi-bias': -0.9618, + 's-sar-bias': 0.57033, + 's-sma10-bias': 0.14349, + 's-sma100-bias': 0.02401, + 's-sma21-bias': 0.78191, + 's-sma3-bias': 0.72279, + 's-sma5-bias': -0.19383, + 's-sma50-bias': 0.63697, + 's-tema10-bias': 0.96837, + 's-tema100-bias': 0.77171, + 's-tema21-bias': 0.67279, + 's-tema3-bias': -0.24583, + 's-tema5-bias': -0.08997, + 's-tema50-bias': 0.65532, + 's-uo-bias': 0.67701, + 's-wbb_percent-bias': -0.658, + 's-wbb_width-bias': -0.71056 +} + +network_shape = [1] + +class MyStrategy(IStrategy): + # ROI table: + minimal_roi = { + "0": 0.21029, + "11": 0.05876, + "57": 0.02191, + "281": 0 + } + + # Stoploss: + stoploss = -0.07693 + + # Optimal ticker interval for the strategy + ticker_interval = '2h' + + # Trailing stop: + trailing_only_offset_is_reached = False + trailing_stop = True + trailing_stop_positive = 0.01019 + trailing_stop_positive_offset = 0.01164 + + # run "populate_indicators" only for new candle + process_only_new_candles = True + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = True + + startup_candle_count = 100 + + 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. + """ + + # Momentum Indicators + # ------------------------------------ + + # ADX + dataframe['adx'] = ta.ADX(dataframe) / 100 + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # # Minus Directional Indicator / Movement + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) / 100 + + # # Awesome Oscillator + dataframe['ao'] = ((qtpylib.awesome_oscillator(dataframe) > 0).astype(int) - 0.5) * 2 + + # # Keltner Channel + keltner = qtpylib.keltner_channel(dataframe) + dataframe["kc_upperband"] = keltner["upper"] + dataframe["kc_lowerband"] = keltner["lower"] + dataframe["kc_middleband"] = keltner["mid"] + dataframe["kc_percent"] = ( + (dataframe["close"] - dataframe["kc_lowerband"]) / + (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + ) + dataframe["kc_width"] = ( + (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + ) + + # # Ultimate Oscillator + dataframe['uo'] = ta.ULTOSC(dataframe) / 100 + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + dataframe['cci'] = ta.CCI(dataframe) / 200 + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) / 100 + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] * 100 - 50) + fisher_rsi = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + dataframe['fisher_rsi_norm'] = 50 * (fisher_rsi + 1) / 100 + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] / 100 + + # # Stochastic RSI + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) / 100 + + # # ROC + dataframe['roc'] = ta.ROC(dataframe) / 100 + + # Overlap Studies + # ------------------------------------ + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # SMA - Simple Moving Average + dataframe['sma3'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=3) - 1 + dataframe['sma5'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=5) - 1 + dataframe['sma10'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=10) - 1 + dataframe['sma21'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=21) - 1 + dataframe['sma50'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=50) - 1 + dataframe['sma100'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=100) - 1 + + # Parabolic SAR + dataframe['sar'] = dataframe['close'] / ta.SAR(dataframe) - 1 + + # TEMA - Triple Exponential Moving Average + dataframe['tema3'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=3) - 1 + dataframe['tema5'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=5) - 1 + dataframe['tema10'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=10) - 1 + dataframe['tema21'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=21) - 1 + dataframe['tema50'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=50) - 1 + dataframe['tema100'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=100) - 1 + + 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 + """ + indicators = ['aroonosc', 'ao', 'uo', 'cci', 'rsi', 'fisher_rsi_norm', 'sar', + 'sma3', 'sma5', 'sma10', 'sma21', 'sma50', 'sma100', + 'tema3', 'tema5', 'tema10', 'tema21', 'tema50', 'tema100', + 'fastd', 'adx', 'bb_percent', 'bb_width', 'macd', 'macdsignal', 'macdhist', 'mfi', + 'wbb_percent', 'wbb_width', 'roc', 'kc_percent', 'kc_width'] + inputs = [] + for indicator in indicators: + inputs.append(dataframe[indicator] + params[indicator + '-bias']) + + for index, layer_size in enumerate(network_shape): + outputs = [] + for n in range(layer_size): + weight = 0 + for i, input in enumerate(inputs): + weight += params['{}-{}-{}-w'.format(i, index, n)] * input + weight += params['{}-{}-bias'.format(index, n)] + outputs.append(activate(weight)) + inputs = outputs + + weight = 0 + for i, input in enumerate(inputs): + weight += params['end-{}-w'.format(i)] * input + weight += params['end-bias'] + + dataframe.loc[activate(weight) > 0, 'buy'] = 1 + + # Check that the candle had volume + dataframe.loc[dataframe['volume'] <= 0, 'buy'] = 0 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/NotAnotherSMAOffsetStrategy.py b/NotAnotherSMAOffsetStrategy.py new file mode 100644 index 0000000..4d2d11e --- /dev/null +++ b/NotAnotherSMAOffsetStrategy.py @@ -0,0 +1,224 @@ +# --- Do not remove these libs --- +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt + +# @Rallipanos + +# Buy hyperspace params: +buy_params = { + "base_nb_candles_buy": 14, + "ewo_high": 2.327, + "ewo_high_2": -2.327, + "ewo_low": -20.988, + "low_offset": 0.975, + "low_offset_2": 0.955, + "rsi_buy": 69 + } + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 24, + "high_offset": 0.991, + "high_offset_2": 0.997 + } + +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['low'] * 100 + return emadif + + + +class NotAnotherSMAOffsetStrategy(IStrategy): + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + "0": 0.215, + "40": 0.032, + "87": 0.016, + "201": 0 + } + + # Stoploss: + stoploss = -0.35 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + low_offset_2 = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + high_offset_2 = DecimalParameter( + 0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + + ewo_high_2 = DecimalParameter( + -6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + + # Trailing stop: + trailing_stop = True + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + ## Optional order time in force. + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'ioc' + } + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + process_only_new_candles = True + startup_candle_count = 200 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['hma_50']*1.149 > last_candle['ema_100']) and (last_candle['close'] < last_candle['ema_100']*0.951): #*1.2 + return False + return True + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewo1') + + + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ), + ['buy', 'buy_tag']] = (1, 'ewo2') + + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewolow') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( (dataframe['close']>dataframe['sma_9'])& + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['rsi']>50)& + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + | + ( + (dataframe['close'] (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/NotAnotherSMAOffsetStrategyHO.json b/NotAnotherSMAOffsetStrategyHO.json new file mode 100644 index 0000000..0631ad1 --- /dev/null +++ b/NotAnotherSMAOffsetStrategyHO.json @@ -0,0 +1,37 @@ +{ + "strategy_name": "NotAnotherSMAOffsetStrategyHO", + "params": { + "roi": { + "0": 0.289, + "25": 0.105, + "80": 0.038, + "140": 0 + }, + "stoploss": { + "stoploss": -0.35 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.005, + "trailing_stop_positive_offset": 0.03, + "trailing_only_offset_is_reached": true + }, + "buy": { + "base_nb_candles_buy": 16, + "ewo_high": 3.422, + "ewo_low": -8.562, + "low_offset": 0.966, + "ewo_high_2": -5.793, + "low_offset_2": 0.955, + "rsi_buy": 64 + }, + "sell": { + "high_offset": 1.014, + "base_nb_candles_sell": 18, + "high_offset_2": 1.008 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-07-06 18:58:29.710728+00:00" +} \ No newline at end of file diff --git a/NotAnotherSMAOffsetStrategyHO.py b/NotAnotherSMAOffsetStrategyHO.py new file mode 100644 index 0000000..9ad05e5 --- /dev/null +++ b/NotAnotherSMAOffsetStrategyHO.py @@ -0,0 +1,301 @@ +# --- Do not remove these libs --- +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt + +# @Rallipanos + +# # Buy hyperspace params: +# buy_params = { +# "base_nb_candles_buy": 14, +# "ewo_high": 2.327, +# "ewo_high_2": -2.327, +# "ewo_low": -20.988, +# "low_offset": 0.975, +# "low_offset_2": 0.955, +# "rsi_buy": 69 +# } + +# # Buy hyperspace params: +# buy_params = { +# "base_nb_candles_buy": 18, +# "ewo_high": 3.422, +# "ewo_high_2": -3.436, +# "ewo_low": -8.562, +# "low_offset": 0.966, +# "low_offset_2": 0.959, +# "rsi_buy": 66, +# } + +# # # Sell hyperspace params: +# # sell_params = { +# # "base_nb_candles_sell": 17, +# # "high_offset": 0.997, +# # "high_offset_2": 1.01, +# # } + +# # Sell hyperspace params: +# sell_params = { +# "base_nb_candles_sell": 7, +# "high_offset": 1.014, +# "high_offset_2": 0.995, +# } + +# # Buy hyperspace params: +# buy_params = { +# "ewo_high_2": -5.642, +# "low_offset_2": 0.951, +# "rsi_buy": 54, +# "base_nb_candles_buy": 16, # value loaded from strategy +# "ewo_high": 3.422, # value loaded from strategy +# "ewo_low": -8.562, # value loaded from strategy +# "low_offset": 0.966, # value loaded from strategy +# } + +# # Sell hyperspace params: +# sell_params = { +# "base_nb_candles_sell": 8, +# "high_offset_2": 1.002, +# "high_offset": 1.014, # value loaded from strategy +# } + +# Buy hyperspace params: +buy_params = { + "ewo_high_2": -4.58, + "low_offset_2": 0.951, + "rsi_buy": 52, + "base_nb_candles_buy": 16, # value loaded from strategy + "ewo_high": 3.422, # value loaded from strategy + "ewo_low": -8.562, # value loaded from strategy + "low_offset": 0.966, # value loaded from strategy +} + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 10, + "high_offset_2": 1.002, + "high_offset": 1.014, # value loaded from strategy +} + + +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['low'] * 100 + return emadif + + +class NotAnotherSMAOffsetStrategyHO(IStrategy): + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + "0": 0.289, + "25": 0.105, + "80": 0.038, + "140": 0 + } + + # Stoploss: + stoploss = -0.35 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=False) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=False) + low_offset_2 = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=False) + high_offset_2 = DecimalParameter( + 0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=False) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=False) + + ewo_high_2 = DecimalParameter( + -6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + + # Trailing stop: + trailing_stop = True + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + # Optional order time in force. + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'ioc' + } + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + process_only_new_candles = True + startup_candle_count = 200 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + + slippage_protection = { + 'retries': 3, + 'max_slippage': -0.02 + } + + buy_signals = {} + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['hma_50']*1.149 > last_candle['ema_100']) and (last_candle['close'] < last_candle['ema_100']*0.951): # *1.2 + return False + + # slippage + try: + state = self.slippage_protection['__pair_retries'] + except KeyError: + state = self.slippage_protection['__pair_retries'] = {} + + candle = dataframe.iloc[-1].squeeze() + + slippage = (rate / candle['close']) - 1 + if slippage < self.slippage_protection['max_slippage']: + pair_retries = state.get(pair, 0) + if pair_retries < self.slippage_protection['retries']: + state[pair] = pair_retries + 1 + return False + + state[pair] = 0 + + return True + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35) & + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < ( + dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewo1') + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35) & + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['rsi'] < 25) + ), + ['buy', 'buy_tag']] = (1, 'ewo2') + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35) & + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < ( + dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewolow') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ((dataframe['close'] > dataframe['sma_9']) & + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['rsi'] > 50) & + (dataframe['volume'] > 0) & + (dataframe['rsi_fast'] > dataframe['rsi_slow']) + ) + | + ( + (dataframe['close'] < dataframe['hma_50']) & + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0) & + (dataframe['rsi_fast'] > dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/NotAnotherSMAOffsetStrategyX1.py b/NotAnotherSMAOffsetStrategyX1.py new file mode 100644 index 0000000..80037ab --- /dev/null +++ b/NotAnotherSMAOffsetStrategyX1.py @@ -0,0 +1,299 @@ +# --- Do not remove these libs --- +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt +import pandas_ta as pta + +# @Rallipanos + + +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['low'] * 100 + emadif = (ema1 - ema2) / df['close'] * 100 + return emadif + + + +class NotAnotherSMAOffsetStrategyX1(IStrategy): + INTERFACE_VERSION = 2 + + # Buy hyperspace params: + buy_params = { + "base_nb_candles_buy": 14, + "ewo_high": 2.327, + "ewo_high_2": -2.327, + "ewo_low": -19.988, + "low_offset": 0.975, + "low_offset_2": 0.955, + "rsi_buy": 69, + } + + # Sell hyperspace params: + sell_params = { + "base_nb_candles_sell": 24, + "high_offset": 0.991, + "high_offset_2": 0.997, + "pHSL": -0.99, + "pPF_1": 0.022, + "pSL_1": 0.021, + "pPF_2": 0.08, + "pSL_2": 0.04, + } + + # ROI table: + minimal_roi = { + "0": 0.215, + "40": 0.032, + "87": 0.016, + "201": 0 + } + + # Stoploss: + stoploss = -0.35 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + low_offset_2 = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + high_offset_2 = DecimalParameter( + 0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + + ewo_high_2 = DecimalParameter( + -6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + + # trailing stoploss hyperopt parameters + # hard stoploss profit + pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', optimize=False, load=True) + # profit threshold 1, trigger point, SL_1 is used + pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', optimize=True, load=True) + pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', optimize=True, load=True) + + # profit threshold 2, SL_2 is used + pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) + pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) + + protections = [ + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 12, + # "trade_limit": 1, + # "stop_duration_candles": 6, + # "only_per_pair": True + # }, + # { + # "method": "StoplossGuard", + # "lookback_period_candles": 12, + # "trade_limit": 2, + # "stop_duration_candles": 6, + # "only_per_pair": False + # }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 60, + "trade_limit": 1, + "stop_duration": 60, + "required_profit": -0.05 + }, + { + "method": "CooldownPeriod", + "stop_duration_candles": 2 + } + ] + + # Trailing stop: + trailing_stop = False + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Custom stoploss + use_custom_stoploss = True + + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + process_only_new_candles = True + startup_candle_count = 400 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['hma_50']*1.149 > last_candle['ema_100']) and (last_candle['close'] < last_candle['ema_100']*0.951): #*1.2 + return False + return True + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['hma_50'] = pta.hma(dataframe['close'], 50) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + + return dataframe + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + # hard stoploss profit + HSL = self.pHSL.value + PF_1 = self.pPF_1.value + SL_1 = self.pSL_1.value + PF_2 = self.pPF_2.value + SL_2 = self.pSL_2.value + + # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + + if (current_profit > PF_2): + sl_profit = SL_2 + (current_profit - PF_2) + elif (current_profit > PF_1): + sl_profit = SL_1 + ((current_profit - PF_1)*(SL_2 - SL_1)/(PF_2 - PF_1)) + else: + sl_profit = HSL + + return stoploss_from_open(sl_profit, current_profit) + + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewo1') + + + """ + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ), + ['buy', 'buy_tag']] = (1, 'ewo2') + """ + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewolow') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( + (dataframe['close']>dataframe['hma_50'])& + #(dataframe['close']>dataframe['sma_9'])& + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['rsi']>50)& + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + | + ( + (dataframe['close'] (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/NotAnotherSMAOffsetStrategy_uzi2.py b/NotAnotherSMAOffsetStrategy_uzi2.py new file mode 100644 index 0000000..e5257d7 --- /dev/null +++ b/NotAnotherSMAOffsetStrategy_uzi2.py @@ -0,0 +1,269 @@ +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from datetime import datetime +from freqtrade.persistence import Trade +from freqtrade.strategy import DecimalParameter, IntParameter +import numpy as np + +# @Rallipanos mod. Uzirox + + +def zlema2(dataframe, fast): + df = dataframe.copy() + zema1=ta.EMA(df['close'], fast) + zema2=ta.EMA(zema1, fast) + d1=zema1-zema2 + df['zlema2']=zema1+d1 + return df['zlema2'] + + + +# Buy hyperspace params: +buy_params = { + "base_nb_candles_buy": 14, + "ewo_high": 2.327, + "ewo_high_2": -2.327, + "ewo_low": -20.988, + "low_offset": 0.975, + "low_offset_2": 0.955, + "rsi_buy": 69 + } + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 24, + "high_offset": 0.991, + "high_offset_2": 0.997 + } + +order_types = { + 'buy': 'limit', + 'sell': 'market', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + +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 + + + +class NotAnotherSMAOffsetStrategy_uzi2(IStrategy): + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + "0": 0.215, + "40": 0.032, + "87": 0.016, + "201": 0 + } + + # Stoploss: + stoploss = -0.1 + + # SMAOffset + base_nb_candles_buy = IntParameter(5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter(5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter(0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + low_offset_2 = DecimalParameter(0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter(0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + high_offset_2 = DecimalParameter(0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0,default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter(2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + ewo_high_2 = DecimalParameter(-6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + + # Trailing stop: + trailing_stop = True + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.005 + ignore_roi_if_buy_signal = False + + # Optimal timeframe for the strategy + timeframe = '5m' + + process_only_new_candles = True + startup_candle_count = 400 + + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['hma_50']*1.149 > last_candle['ema_100']) and (last_candle['close'] < last_candle['ema_100']*0.951): #*1.2 + return False + return True + + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + + # *MAs + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod = 100) + dataframe['ema_10'] = zlema2(dataframe, 10) + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod = 9) + + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + # strategy BinHV45 + bb_40 = qtpylib.bollinger_bands(dataframe['close'], window=40, stds=2) + dataframe['lower'] = bb_40['lower'] + dataframe['mid'] = bb_40['mid'] + dataframe['bbdelta'] = (bb_40['mid'] - dataframe['lower']).abs() + dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs() + dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs() + + # strategy ClucMay72018 + 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['ema_slow'] = ta.EMA(dataframe, timeperiod=50) + dataframe['volume_mean_slow'] = dataframe['volume'].rolling(window=30).mean() + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewo1') + + + dataframe.loc[ + ( + (dataframe['rsi_fast'] <35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ), + ['buy', 'buy_tag']] = (1, 'ewo2') + + dataframe.loc[ + ( + (dataframe['rsi_fast'] < 35)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0) & + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ), + ['buy', 'buy_tag']] = (1, 'ewolow') + + + # buy in bull market + dataframe.loc[ + ( + (dataframe['ema_10'].rolling(10).mean() > dataframe['ema_100'].rolling(10).mean()) & + (dataframe['lower'].shift().gt(0)) & + (dataframe['bbdelta'].gt(dataframe['close'] * 0.031)) & + (dataframe['closedelta'].gt(dataframe['close'] * 0.018)) & + (dataframe['tail'].lt(dataframe['bbdelta'] * 0.233)) & + (dataframe['close'].lt(dataframe['lower'].shift())) & + (dataframe['close'].le(dataframe['close'].shift())) & + (dataframe['volume'] > 0) + ) + | + ( + (dataframe['ema_10'].rolling(10).mean() > dataframe['ema_100'].rolling(10).mean()) & + (dataframe['close'] > dataframe['ema_100']) & + (dataframe['close'] < dataframe['ema_slow']) & + (dataframe['close'] < 0.993 * dataframe['bb_lowerband']) & + (dataframe['volume'] < (dataframe['volume_mean_slow'].shift(1) * 21)) & + (dataframe['volume'] > 0) + ), + ['buy', 'buy_tag']] = (1, 'bb_bull') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( + + (dataframe['close'] > dataframe['sma_9']) & + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['rsi']>50) & + (dataframe['volume'] > 0) & + (dataframe['rsi_fast'] > dataframe['rsi_slow']) + + ) + | + ( + (dataframe['sma_9'] > (dataframe['sma_9'].shift(1) + dataframe['sma_9'].shift(1)*0.005)) & + (dataframe['close'] < dataframe['hma_50']) & + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0) & + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe + + plot_config = { + 'main_plot':{ + 'ema_100':{}, + 'ema_10':{}, + 'sma_9':{} + } + } \ No newline at end of file diff --git a/Pierrick_20211201.py b/Pierrick_20211201.py new file mode 100644 index 0000000..73682d3 --- /dev/null +++ b/Pierrick_20211201.py @@ -0,0 +1,132 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class S000(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband'] * 0.998) + & (dataframe['bb_width'] >= 0.065) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/PremiereStrategie.py b/PremiereStrategie.py new file mode 100644 index 0000000..b565510 --- /dev/null +++ b/PremiereStrategie.py @@ -0,0 +1,552 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 + +# --- Do not remove these libs --- +import operator +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, + IStrategy, IntParameter) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class PremiereStrategie(IStrategy): + """ + This is a strategy template to get you started. + More information in https://www.freqtrade.io/en/latest/strategy-customization/ + + You can: + :return: a Dataframe with all mandatory indicators for the strategies + - Rename the class name (Do not forget to update class_name) + - Add any methods you want to build your strategy + - Add any lib you need to build your strategy + + You must keep: + - the lib in the section "Do not remove these libs" + - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + You should keep: + - timeframe, minimal_roi, stoploss, trailing_* + """ + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + # "240": 0.002, + # "120": 0.005, + # "60": 0.01, + # "30": 0.015, + # "15": 0.02, + "0": 0.015 + } + + # minimal_roi = { + # "0": 0.015 + # } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -0.10 + + # Trailing stoploss + trailing_stop = False + # trailing_only_offset_is_reached = False + # trailing_stop_positive = 0.01 + # trailing_stop_positive_offset = 0.0 # Disabled / not configured + + # Optimal timeframe for the strategy. + timeframe = '5m' + + # 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 = True + ignore_roi_if_buy_signal = False + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + 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 + # ------------------------------------ + + # # ADX + # dataframe['adx'] = ta.ADX(dataframe) + # + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + # + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # # Awesome Oscillator + # dataframe['ao'] = qtpylib.awesome_oscillator(dataframe) + + # # Keltner Channel + # keltner = qtpylib.keltner_channel(dataframe) + # dataframe["kc_upperband"] = keltner["upper"] + # dataframe["kc_lowerband"] = keltner["lower"] + # dataframe["kc_middleband"] = keltner["mid"] + # dataframe["kc_percent"] = ( + # (dataframe["close"] - dataframe["kc_lowerband"]) / + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + # ) + # dataframe["kc_width"] = ( + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + # ) + + # # Ultimate Oscillator + # dataframe['uo'] = ta.ULTOSC(dataframe) + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + # dataframe['cci'] = ta.CCI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # # Stochastic Fast + # stoch_fast = ta.STOCHF(dataframe) + # dataframe['fastd'] = stoch_fast['fastd'] + # dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. + # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # # ROC + # dataframe['roc'] = ta.ROC(dataframe) + + # Overlap Studies + # ------------------------------------ + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + + # Parabolic SAR + dataframe['sar'] = ta.SAR(dataframe) + + # TEMA - Triple Exponential Moving Average + dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9) + + # # Cycle Indicator + # # ------------------------------------ + # # Hilbert Transform Indicator - SineWave + # hilbert = ta.HT_SINE(dataframe) + # dataframe['htsine'] = hilbert['sine'] + # dataframe['htleadsine'] = hilbert['leadsine'] + # + # # Pattern Recognition - Bullish candlestick patterns + # # ------------------------------------ + # # Hammer: values [0, 100] + # dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + # # Inverted Hammer: values [0, 100] + # dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe) + # # Dragonfly Doji: values [0, 100] + # dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe) + # # Piercing Line: values [0, 100] + # dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100] + # # Morningstar: values [0, 100] + # dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100] + # # Three White Soldiers: values [0, 100] + # dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100] + + # Pattern Recognition - Bearish candlestick patterns + # ------------------------------------ + # # Hanging Man: values [0, 100] + # dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe) + # # Shooting Star: values [0, 100] + # dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe) + # # Gravestone Doji: values [0, 100] + # dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe) + # # Dark Cloud Cover: values [0, 100] + # dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe) + # # Evening Doji Star: values [0, 100] + # dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe) + # # Evening Star: values [0, 100] + # dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe) + + # Pattern Recognition - Bullish/Bearish candlestick patterns + # ------------------------------------ + # # Three Line Strike: values [0, -100, 100] + # dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe) + # # Spinning Top: values [0, -100, 100] + # dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100] + # # Engulfing: values [0, -100, 100] + # dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100] + # # Harami: values [0, -100, 100] + # dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100] + # # Three Outside Up/Down: values [0, -100, 100] + # dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100] + # # Three Inside Up/Down: values [0, -100, 100] + # dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100] + + # # Chart type + # # ------------------------------------ + # # Heikin Ashi Strategy + # heikinashi = qtpylib.heikinashi(dataframe) + # dataframe['ha_open'] = heikinashi['open'] + # dataframe['ha_close'] = heikinashi['close'] + # dataframe['ha_high'] = heikinashi['high'] + # dataframe['ha_low'] = heikinashi['low'] + + # Retrieve best bid and best ask from the orderbook + # ------------------------------------ + """ + # first check if dataprovider is available + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + ob = self.dp.orderbook(metadata['pair'], 1) + dataframe['best_bid'] = ob['bids'][0][0] + dataframe['best_ask'] = ob['asks'][0][0] + """ + + 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.loc[ + ( + # (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 + # (dataframe['tema'] <= dataframe['bb_middleband']) & # Guard: tema below BB middle + # (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising + # (dataframe['volume'] > 0) # Make sure Volume is not 0 + # ) | ( + (dataframe['macd'] > dataframe['macdsignal']) & + (dataframe['macd'] > dataframe['macd'].shift(1)) & # Guard: macd is raising + # (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising + # (dataframe['macd'].shift(1) > dataframe['macd'].shift(2)) & + (StrategyHelperLocal.two_green_one_red_candle(dataframe)) & + # (StrategyHelperLocal.no_more_three_green_candles(dataframe)) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + '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 populated with indicators + :param metadata: Additional information, like the currently traded pair + :return: DataFrame with buy column + """ + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70 + (dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle + # (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling + (dataframe['volume'] > 0) # Make sure Volume is not 0 + # ) | ( + # (StrategyHelperLocal.four_green_one_red_candle(dataframe)) & + # (dataframe['volume'] > 0) # Make sure Volume is not 0 + # ) | ( + # (StrategyHelperLocal.two_red_candles(dataframe)) & + # (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling + # (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'sell'] = 1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return not ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/RalliV1.py b/RalliV1.py new file mode 100644 index 0000000..e17c8f4 --- /dev/null +++ b/RalliV1.py @@ -0,0 +1,292 @@ +# --- Do not remove these libs --- +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt + +# @Rallipanos + +# Buy hyperspace params: +buy_params = { + "base_nb_candles_buy": 14, + "ewo_high": 2.327, + "ewo_high_2": -2.327, + "ewo_low": -20.988, + "low_offset": 0.975, + "low_offset_2": 0.955, + "rsi_buy": 60, + "rsi_buy_2": 45 + } + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 24, + "high_offset": 0.991, + "high_offset_2": 0.997 + } + +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['low'] * 100 + return emadif + + + +class RalliV1(IStrategy): + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + "0": 0.04, + "40": 0.032, + "87": 0.018, + "201": 0 + } + + # Stoploss: + stoploss = -0.3 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + low_offset_2 = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + high_offset_2 = DecimalParameter( + 0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + + ewo_high_2 = DecimalParameter( + -6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + rsi_buy_2 = IntParameter(30, 70, default=buy_params['rsi_buy_2'], space='buy', optimize=True) + + # Trailing stop: + trailing_stop = False + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + ## Optional order time in force. + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'gtc' + } + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + process_only_new_candles = True + startup_candle_count = 200 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['rsi'] < 45 ) and (last_candle['hma_50'] > last_candle['ema_100']): #*1.2 + return False + return True + + use_custom_stoploss = True + + def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, + current_profit: float, **kwargs) -> float: + df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + candle = df.iloc[-1].squeeze() + + if current_profit < 0.001 and current_time - timedelta(minutes=140) > trade.open_date_utc: + return -0.005 + + return 1 + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['hma_9'] = qtpylib.hull_moving_average(dataframe['close'], window=9) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + dataframe['ema_14'] = ta.EMA(dataframe, timeperiod=14) + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + dataframe['ema_9'] = ta.EMA(dataframe, timeperiod=9) + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy_2.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy_2.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ) + ) + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] < 35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ) + ) + + conditions.append( + ( (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + (dataframe['rsi_fast'] < 35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.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( + ( (dataframe['hma_50']>dataframe['ema_100'])& + (dataframe['close']>dataframe['sma_9'])& + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + | + ( + (dataframe['close'] (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/RalliV1_disable56.py b/RalliV1_disable56.py new file mode 100644 index 0000000..d0008b0 --- /dev/null +++ b/RalliV1_disable56.py @@ -0,0 +1,292 @@ +# --- Do not remove these libs --- +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt + +# @Rallipanos + +# Buy hyperspace params: +buy_params = { + "base_nb_candles_buy": 14, + "ewo_high": 2.327, + "ewo_high_2": -2.327, + "ewo_low": -20.988, + "low_offset": 0.975, + "low_offset_2": 0.955, + "rsi_buy": 60, + "rsi_buy_2": 45 + } + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 24, + "high_offset": 0.991, + "high_offset_2": 0.997 + } + +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['low'] * 100 + return emadif + + + +class RalliV1_disable56(IStrategy): + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + "0": 0.04, + "40": 0.032, + "87": 0.018, + "201": 0 + } + + # Stoploss: + stoploss = -0.3 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + low_offset_2 = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset_2'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.95, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + high_offset_2 = DecimalParameter( + 0.99, 1.5, default=sell_params['high_offset_2'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + + ewo_high_2 = DecimalParameter( + -6.0, 12.0, default=buy_params['ewo_high_2'], space='buy', optimize=True) + + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + rsi_buy_2 = IntParameter(30, 70, default=buy_params['rsi_buy_2'], space='buy', optimize=True) + + # Trailing stop: + trailing_stop = False + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.03 + trailing_only_offset_is_reached = True + + # Sell signal + use_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + ## Optional order time in force. + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'gtc' + } + + # Optimal timeframe for the strategy + timeframe = '5m' + inf_1h = '1h' + + process_only_new_candles = True + startup_candle_count = 200 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, + rate: float, time_in_force: str, sell_reason: str, + current_time: datetime, **kwargs) -> bool: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + + if (last_candle is not None): + if (sell_reason in ['sell_signal']): + if (last_candle['rsi'] < 45 ) and (last_candle['hma_50'] > last_candle['ema_100']): #*1.2 + return False + return True + + use_custom_stoploss = True + + def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, + current_profit: float, **kwargs) -> float: + df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + candle = df.iloc[-1].squeeze() + + if current_profit < 0.001 and current_time - timedelta(minutes=140) > trade.open_date_utc: + return -0.005 + + return 1 + + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + dataframe['hma_50'] = qtpylib.hull_moving_average(dataframe['close'], window=50) + dataframe['hma_9'] = qtpylib.hull_moving_average(dataframe['close'], window=9) + dataframe['ema_100'] = ta.EMA(dataframe, timeperiod=100) + dataframe['ema_14'] = ta.EMA(dataframe, timeperiod=14) + dataframe['sma_9'] = ta.SMA(dataframe, timeperiod=9) + dataframe['ema_9'] = ta.EMA(dataframe, timeperiod=9) + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=4) + dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=20) + + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy_2.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + (dataframe['EWO'] > self.ewo_high_2.value) & + (dataframe['rsi'] < self.rsi_buy_2.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + (dataframe['rsi']<25) + ) + ) + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] < dataframe['ema_100'])& + (dataframe['sma_9'] < dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'])& + (dataframe['rsi_fast'] < 35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + + conditions.append( + ( + (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + (dataframe['rsi_fast'] <35)& + (dataframe['rsi_fast'] >4)& + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0)& + (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) + ) + ) + + # conditions.append( + # ( + # (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + # (dataframe['rsi_fast'] <35)& + # (dataframe['rsi_fast'] >4)& + # (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset_2.value)) & + # (dataframe['EWO'] > self.ewo_high_2.value) & + # (dataframe['rsi'] < self.rsi_buy.value) & + # (dataframe['volume'] > 0)& + # (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value))& + # (dataframe['rsi']<25) + # ) + # ) + + # conditions.append( + # ( (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] > dataframe['ema_100'])& + # (dataframe['rsi_fast'] < 35)& + # (dataframe['rsi_fast'] >4)& + # (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + # (dataframe['EWO'] < self.ewo_low.value) & + # (dataframe['volume'] > 0)& + # (dataframe['close'] < (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.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( + ( (dataframe['hma_50']>dataframe['ema_100'])& + (dataframe['close']>dataframe['sma_9'])& + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset_2.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + | + ( + (dataframe['close'] (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0)& + (dataframe['rsi_fast']>dataframe['rsi_slow']) + ) + + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/Reco_1.py b/Reco_1.py new file mode 100644 index 0000000..63bb6a1 --- /dev/null +++ b/Reco_1.py @@ -0,0 +1,129 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +import numpy as np # noqa +import pandas as pd # noqa + +from freqtrade.strategy import IStrategy, merge_informative_pair +from pandas import DataFrame + +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +class Reco_1(IStrategy): + + minimal_roi = { + "0": 1 + } + + # Stoploss + stoploss = -0.05 + + # Trailing stoploss + trailing_stop = True + trailing_only_offset_is_reached = True + trailing_stop_positive = 0.015 + trailing_stop_positive_offset = 0.02 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # These values can be overridden in the "ask_strategy" section in the config. + use_sell_signal = False + sell_profit_only = False + ignore_roi_if_buy_signal = False + + # Optional order type mapping. + order_types = { + 'buy': 'market', + 'sell': 'market', + 'stoploss': 'market', + 'stoploss_on_exchange': True + } + + # Optional order time in force. + order_time_in_force = { + 'buy': 'gtc', + 'sell': 'gtc' + } + + def informative_pairs(self): + + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + informative_pairs = [(pair, '6h') for pair in pairs] + # Optionally Add additional "static" pairs + informative_pairs += [("ETH/USDT", "5m"), + ("BTC/TUSD", "5m"), + ("ALGO/BTC", "5m"), + ("ATOM/BTC", "5m"), + ("BAT/BTC", "5m"), + ("BCH/BTC", "5m"), + ("BRD/BTC", "5m"), + ("EOS/BTC", "5m"), + ("ETH/BTC", "5m"), + ("IOTA/BTC", "5m"), + ("LINK/BTC", "5m"), + ("LTC/BTC", "5m"), + ("NEO/BTC", "5m"), + ("NXS/BTC", "5m"), + ("XMR/BTC", "5m"), + ("XRP/BTC", "5m"), + ("XTZ/BTC", "5m"), + ] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if not self.dp: + # Don't do anything if DataProvider is not available. + return dataframe + + inf_tf = '6h' + # Get the informative pair + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe = inf_tf) + # Get the 18 hours 3WHITESOLDIERS + informative['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(informative, timeperiod=3) + + # Use the helper function merge_informative_pair to safely merge the pair + # Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, inf_tf, ffill = True) + + # Calculate 3WHITESOLDIERS of the original dataframe (5m timeframe) + dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe, timeperiod=3) + + + # Momentum Indicators + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # # Chart type + # # Heikin Ashi Strategy + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['ha_open'] = heikinashi['open'] + dataframe['ha_close'] = heikinashi['close'] + dataframe['ha_high'] = heikinashi['high'] + dataframe['ha_low'] = heikinashi['low'] + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['mfi'] > 18)) & + (dataframe['CDL3WHITESOLDIERS_6h'] == True) & + (dataframe['volume'] > 0) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + ), + 'sell'] = 1 + + return dataframe diff --git a/SMAOG.py b/SMAOG.py new file mode 100644 index 0000000..4f10568 --- /dev/null +++ b/SMAOG.py @@ -0,0 +1,109 @@ +from datetime import datetime, timedelta +import talib.abstract as ta +from freqtrade.persistence import Trade +from freqtrade.strategy import CategoricalParameter +from freqtrade.strategy import DecimalParameter, IntParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame + +# og @tirail +# author @Jooopieeert#0239 + +ma_types = { + 'SMA': ta.SMA, + 'EMA': ta.EMA, +} +class SMAOG(IStrategy): + INTERFACE_VERSION = 2 + buy_params = { + "base_nb_candles_buy": 26, + "buy_trigger": "SMA", + "low_offset": 0.968, + "pair_is_bad_0_threshold": 0.555, + "pair_is_bad_1_threshold": 0.172, + "pair_is_bad_2_threshold": 0.198, + } + sell_params = { + "base_nb_candles_sell": 28, + "high_offset": 0.985, + "sell_trigger": "EMA", + } + base_nb_candles_buy = IntParameter(16, 45, default=buy_params['base_nb_candles_buy'], space='buy', optimize=False, load=True) + base_nb_candles_sell = IntParameter(16, 45, default=sell_params['base_nb_candles_sell'], space='sell', optimize=False, load=True) + low_offset = DecimalParameter(0.8, 0.99, default=buy_params['low_offset'], space='buy', optimize=False, load=True) + high_offset = DecimalParameter(0.8, 1.1, default=sell_params['high_offset'], space='sell', optimize=False, load=True) + buy_trigger = CategoricalParameter(ma_types.keys(), default=buy_params['buy_trigger'], space='buy', optimize=False, load=True) + sell_trigger = CategoricalParameter(ma_types.keys(), default=sell_params['sell_trigger'], space='sell', optimize=False, load=True) + pair_is_bad_0_threshold = DecimalParameter(0.0, 0.600, default=0.220, space='buy', optimize=True, load=True) + pair_is_bad_1_threshold = DecimalParameter(0.0, 0.350, default=0.090, space='buy', optimize=True, load=True) + pair_is_bad_2_threshold = DecimalParameter(0.0, 0.200, default=0.060, space='buy', optimize=True, load=True) + + timeframe = '5m' + stoploss = -0.23 + minimal_roi = {"0": 10,} + trailing_stop = True + trailing_only_offset_is_reached = True + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + use_sell_signal = True + sell_profit_only = False + ignore_roi_if_buy_signal = False + process_only_new_candles = True + startup_candle_count = 400 + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if not self.config['runmode'].value == 'hyperopt': + dataframe['ma_offset_buy'] = ma_types[self.buy_trigger.value](dataframe, int(self.base_nb_candles_buy.value)) * self.low_offset.value + dataframe['ma_offset_sell'] = ma_types[self.sell_trigger.value](dataframe, int(self.base_nb_candles_sell.value)) * self.high_offset.value + dataframe['pair_is_bad'] = ( + (((dataframe['open'].rolling(144).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_0_threshold.value) | + (((dataframe['open'].rolling(12).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_1_threshold.value) | + (((dataframe['open'].rolling(2).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_2_threshold.value)).astype('int') + dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) + dataframe['rsi_exit'] = ta.RSI(dataframe, timeperiod=2) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if self.config['runmode'].value == 'hyperopt': + dataframe['ma_offset_buy'] = ma_types[self.buy_trigger.value](dataframe, int(self.base_nb_candles_buy.value)) * self.low_offset.value + dataframe['pair_is_bad'] = ( + (((dataframe['open'].rolling(144).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_0_threshold.value) | + (((dataframe['open'].rolling(12).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_1_threshold.value) | + (((dataframe['open'].rolling(2).min() - dataframe['close']) / dataframe[ + 'close']) >= self.pair_is_bad_2_threshold.value)).astype('int') + dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) + dataframe['rsi_exit'] = ta.RSI(dataframe, timeperiod=2) + + dataframe.loc[ + ( + (dataframe['ema_50'] > dataframe['ema_200']) & + (dataframe['close'] > dataframe['ema_200']) & + (dataframe['pair_is_bad'] < 1) & + (dataframe['close'] < dataframe['ma_offset_buy']) & + (dataframe['volume'] > 0) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if self.config['runmode'].value == 'hyperopt': + dataframe['ma_offset_sell'] = ta.EMA(dataframe, int(self.base_nb_candles_sell.value)) * self.high_offset.value + dataframe.loc[ + ( + (dataframe['close'] > dataframe['ma_offset_sell']) & + ( + (dataframe['open'] < dataframe['open'].shift(1)) | + (dataframe['rsi_exit'] < 50) | + (dataframe['rsi_exit'] < dataframe['rsi_exit'].shift(1)) + ) & + (dataframe['volume'] > 0) + ), + 'sell'] = 1 + return dataframe diff --git a/SMAOffsetProtectOptV1Mod2.py b/SMAOffsetProtectOptV1Mod2.py new file mode 100644 index 0000000..7529d04 --- /dev/null +++ b/SMAOffsetProtectOptV1Mod2.py @@ -0,0 +1,191 @@ +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import numpy as np +import freqtrade.vendor.qtpylib.indicators as qtpylib +import datetime +from technical.util import resample_to_interval, resampled_merge +from datetime import datetime, timedelta +from freqtrade.persistence import Trade +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter +import technical.indicators as ftt + +######################################## Warning ######################################## +# You won't get a lot of benefits by simply changing to this strategy # +# with the HyperOpt values changed. # +# # +# You should test it closely, trying backtesting and dry running, and we recommend # +# customizing the terms of sale and purchase as well. # +# # +# You should always be careful in real trading! # +######################################################################################### + +# Modified Buy / Sell params - 20210619 +# Buy hyperspace params: +buy_params = { + "base_nb_candles_buy": 16, + "ewo_high": 5.672, + "ewo_low": -19.931, + "low_offset": 0.973, + "rsi_buy": 59, +} + +# Sell hyperspace params: +sell_params = { + "base_nb_candles_sell": 20, + "high_offset": 1.010, +} + +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 + + +class SMAOffsetProtectOptV1Mod2(IStrategy): + INTERFACE_VERSION = 2 + + # Modified ROI - 20210620 + # ROI table: + minimal_roi = { + "0": 0.028, + "10": 0.018, + "30": 0.010, + "40": 0.005 + } + + # Stoploss: + stoploss = -0.5 + + # SMAOffset + base_nb_candles_buy = IntParameter( + 5, 80, default=buy_params['base_nb_candles_buy'], space='buy', optimize=True) + base_nb_candles_sell = IntParameter( + 5, 80, default=sell_params['base_nb_candles_sell'], space='sell', optimize=True) + low_offset = DecimalParameter( + 0.9, 0.99, default=buy_params['low_offset'], space='buy', optimize=True) + high_offset = DecimalParameter( + 0.99, 1.1, default=sell_params['high_offset'], space='sell', optimize=True) + + # Protection + fast_ewo = 50 + slow_ewo = 200 + ewo_low = DecimalParameter(-20.0, -8.0, + default=buy_params['ewo_low'], space='buy', optimize=True) + ewo_high = DecimalParameter( + 2.0, 12.0, default=buy_params['ewo_high'], space='buy', optimize=True) + rsi_buy = IntParameter(30, 70, default=buy_params['rsi_buy'], space='buy', optimize=True) + + + # 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_sell_signal = True + sell_profit_only = False + sell_profit_offset = 0.01 + ignore_roi_if_buy_signal = False + + # Optimal timeframe for the strategy + timeframe = '5m' + informative_timeframe = '1h' + + process_only_new_candles = True + startup_candle_count: int = 30 + + plot_config = { + 'main_plot': { + 'ma_buy': {'color': 'orange'}, + 'ma_sell': {'color': 'orange'}, + }, + } + + use_custom_stoploss = False + + def informative_pairs(self): + + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, self.informative_timeframe) for pair in pairs] + + return informative_pairs + + def get_informative_indicators(self, metadata: dict): + + dataframe = self.dp.get_pair_dataframe( + pair=metadata['pair'], timeframe=self.informative_timeframe) + + return dataframe + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Calculate all ma_buy values + for val in self.base_nb_candles_buy.range: + dataframe[f'ma_buy_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Calculate all ma_sell values + for val in self.base_nb_candles_sell.range: + dataframe[f'ma_sell_{val}'] = ta.EMA(dataframe, timeperiod=val) + + # Elliot + dataframe['EWO'] = EWO(dataframe, self.fast_ewo, self.slow_ewo) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + conditions.append( + ( + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] > self.ewo_high.value) & + (dataframe['rsi'] < self.rsi_buy.value) & + (dataframe['volume'] > 0) + ) + ) + + conditions.append( + ( + (dataframe['close'] < (dataframe[f'ma_buy_{self.base_nb_candles_buy.value}'] * self.low_offset.value)) & + (dataframe['EWO'] < self.ewo_low.value) & + (dataframe['volume'] > 0) + ) + ) + + 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( + ( + (dataframe['close'] > (dataframe[f'ma_sell_{self.base_nb_candles_sell.value}'] * self.high_offset.value)) & + (dataframe['volume'] > 0) + ) + ) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x | y, conditions), + 'sell' + ]=1 + + return dataframe diff --git a/Scalp.py b/Scalp.py new file mode 100644 index 0000000..31701d5 --- /dev/null +++ b/Scalp.py @@ -0,0 +1,75 @@ +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class Scalp(IStrategy): + """ + this strategy is based around the idea of generating a lot of potentatils buys and make tiny profits on each trade + + we recommend to have at least 60 parallel trades at any time to cover non avoidable losses. + + Recommended is to only sell based on ROI for this strategy + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "0": 0.01 + } + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + # should not be below 3% loss + + stoploss = -0.04 + # Optimal timeframe for the strategy + # the shorter the better + timeframe = '1m' + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['ema_high'] = ta.EMA(dataframe, timeperiod=5, price='high') + dataframe['ema_close'] = ta.EMA(dataframe, timeperiod=5, price='close') + dataframe['ema_low'] = ta.EMA(dataframe, timeperiod=5, price='low') + stoch_fast = ta.STOCHF(dataframe, 5, 3, 0, 3, 0) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + dataframe['adx'] = ta.ADX(dataframe) + + # required for graphing + 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'] + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['open'] < dataframe['ema_low']) & + (dataframe['adx'] > 30) & + ( + (dataframe['fastk'] < 30) & + (dataframe['fastd'] < 30) & + (qtpylib.crossed_above(dataframe['fastk'], dataframe['fastd'])) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['open'] >= dataframe['ema_high']) + ) | + ( + (qtpylib.crossed_above(dataframe['fastk'], 70)) | + (qtpylib.crossed_above(dataframe['fastd'], 70)) + ), + 'sell'] = 1 + return dataframe diff --git a/SecondeStrategie.py b/SecondeStrategie.py new file mode 100644 index 0000000..5ebc510 --- /dev/null +++ b/SecondeStrategie.py @@ -0,0 +1,554 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 + +# --- Do not remove these libs --- +import operator +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, + IStrategy, IntParameter) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class SecondeStrategie(IStrategy): + """ + This is a strategy template to get you started. + More information in https://www.freqtrade.io/en/latest/strategy-customization/ + + You can: + :return: a Dataframe with all mandatory indicators for the strategies + - Rename the class name (Do not forget to update class_name) + - Add any methods you want to build your strategy + - Add any lib you need to build your strategy + + You must keep: + - the lib in the section "Do not remove these libs" + - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + You should keep: + - timeframe, minimal_roi, stoploss, trailing_* + """ + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + # minimal_roi = { + # "240": 0.002, + # "120": 0.005, + # "60": 0.01, + # "30": 0.015, + # "15": 0.02, + # "0": 0.03 + # } + + minimal_roi = { + "0": 0.015 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -0.03 + + # Trailing stoploss + trailing_stop = False + # trailing_only_offset_is_reached = False + # trailing_stop_positive = 0.01 + # trailing_stop_positive_offset = 0.0 # Disabled / not configured + + # Optimal timeframe for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + 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 + # ------------------------------------ + + # # ADX + # dataframe['adx'] = ta.ADX(dataframe) + # + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + # + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # Awesome Oscillator + dataframe['ao'] = qtpylib.awesome_oscillator(dataframe) + + # # Keltner Channel + # keltner = qtpylib.keltner_channel(dataframe) + # dataframe["kc_upperband"] = keltner["upper"] + # dataframe["kc_lowerband"] = keltner["lower"] + # dataframe["kc_middleband"] = keltner["mid"] + # dataframe["kc_percent"] = ( + # (dataframe["close"] - dataframe["kc_lowerband"]) / + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + # ) + # dataframe["kc_width"] = ( + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + # ) + + # # Ultimate Oscillator + # dataframe['uo'] = ta.ULTOSC(dataframe) + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + # dataframe['cci'] = ta.CCI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. + # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # # ROC + # dataframe['roc'] = ta.ROC(dataframe) + + # Overlap Studies + # ------------------------------------ + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + + # Parabolic SAR + dataframe['sar'] = ta.SAR(dataframe) + + # TEMA - Triple Exponential Moving Average + dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9) + + # # Cycle Indicator + # # ------------------------------------ + # # Hilbert Transform Indicator - SineWave + # hilbert = ta.HT_SINE(dataframe) + # dataframe['htsine'] = hilbert['sine'] + # dataframe['htleadsine'] = hilbert['leadsine'] + # + # # Pattern Recognition - Bullish candlestick patterns + # # ------------------------------------ + # # Hammer: values [0, 100] + # dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + # # Inverted Hammer: values [0, 100] + # dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe) + # # Dragonfly Doji: values [0, 100] + # dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe) + # # Piercing Line: values [0, 100] + # dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100] + # # Morningstar: values [0, 100] + # dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100] + # # Three White Soldiers: values [0, 100] + # dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100] + + # Pattern Recognition - Bearish candlestick patterns + # ------------------------------------ + # # Hanging Man: values [0, 100] + # dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe) + # # Shooting Star: values [0, 100] + # dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe) + # # Gravestone Doji: values [0, 100] + # dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe) + # # Dark Cloud Cover: values [0, 100] + # dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe) + # # Evening Doji Star: values [0, 100] + # dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe) + # # Evening Star: values [0, 100] + # dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe) + + # Pattern Recognition - Bullish/Bearish candlestick patterns + # ------------------------------------ + # # Three Line Strike: values [0, -100, 100] + # dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe) + # # Spinning Top: values [0, -100, 100] + # dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100] + # # Engulfing: values [0, -100, 100] + # dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100] + # # Harami: values [0, -100, 100] + # dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100] + # # Three Outside Up/Down: values [0, -100, 100] + # dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100] + # # Three Inside Up/Down: values [0, -100, 100] + # dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100] + + # # Chart type + # # ------------------------------------ + # # Heikin Ashi Strategy + # heikinashi = qtpylib.heikinashi(dataframe) + # dataframe['ha_open'] = heikinashi['open'] + # dataframe['ha_close'] = heikinashi['close'] + # dataframe['ha_high'] = heikinashi['high'] + # dataframe['ha_low'] = heikinashi['low'] + + # Retrieve best bid and best ask from the orderbook + # ------------------------------------ + """ + # first check if dataprovider is available + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + ob = self.dp.orderbook(metadata['pair'], 1) + dataframe['best_bid'] = ob['bids'][0][0] + dataframe['best_ask'] = ob['asks'][0][0] + """ + + 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.loc[ + # ( + # (qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30 + # (dataframe['tema'] <= dataframe['bb_middleband']) & # Guard: tema below BB middle + # (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising + # (dataframe['volume'] > 0) # Make sure Volume is not 0 + # ) + # | + ( + (dataframe['macd'] > dataframe['macdsignal']) & + (dataframe['macd'] > dataframe['macd'].shift(1)) & # Guard: macd is raising + (dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising + # (dataframe['macd'].shift(1) > dataframe['macd'].shift(2)) & + (StrategyHelperLocal.two_green_one_red_candle(dataframe)) & + # (StrategyHelperLocal.no_more_three_green_candles(dataframe)) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + '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 populated with indicators + :param metadata: Additional information, like the currently traded pair + :return: DataFrame with buy column + """ + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70 + (dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle + (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ) | ( + # # (StrategyHelperLocal.four_green_one_red_candle(dataframe)) & + # # (dataframe['volume'] > 0) # Make sure Volume is not 0 + # ) | ( + (StrategyHelperLocal.two_red_candles(dataframe)) & + (dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'sell'] = 1 + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def no_more_three_green_candles(dataframe): + """ + evaluates if we are having not more than 3 green candles in a row + :param self: + :param dataframe: + :return: + """ + return operator.not_( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + # (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def two_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) & + (dataframe['open'].shift(2) > dataframe['close'].shift(2)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/Solipsis5.json b/Solipsis5.json new file mode 100644 index 0000000..bf68e92 --- /dev/null +++ b/Solipsis5.json @@ -0,0 +1,49 @@ +{ + "strategy_name": "Solipsis5", + "params": { + "roi": { + "0": 100 + }, + "stoploss": { + "stoploss": -0.99 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "base_ma_streak": 4, + "base_mp": 48, + "base_rmi_max": 57, + "base_rmi_min": 22, + "base_rmi_streak": 5, + "base_trigger": "none", + "inf_pct_adr": 0.96, + "xbtc_base_rmi": 69, + "xbtc_guard": "lazy", + "xtra_base_fiat_rmi": 67, + "xtra_base_stake_rmi": 12 + }, + "sell": { + "csell_endtrend_respect_roi": false, + "csell_pullback": true, + "csell_pullback_amount": 0.025, + "csell_pullback_respect_roi": false, + "csell_roi_end": 0.005, + "csell_roi_start": 0.039, + "csell_roi_time": 1124, + "csell_roi_type": "static", + "csell_trend_type": "any", + "cstop_bail_how": "none", + "cstop_bail_roc": -3.211, + "cstop_bail_time": 949, + "cstop_bail_time_trend": true, + "cstop_loss_threshold": -0.042 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-02-15 00:02:16.762786+00:00" +} \ No newline at end of file diff --git a/Solipsis5.py b/Solipsis5.py new file mode 100644 index 0000000..d9a7c38 --- /dev/null +++ b/Solipsis5.py @@ -0,0 +1,588 @@ +import numpy as np +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import arrow + +from freqtrade.strategy import (IStrategy, merge_informative_pair, stoploss_from_open, + IntParameter, DecimalParameter, CategoricalParameter) + +from typing import Dict, List, Optional, Tuple, Union +from pandas import DataFrame, Series +from functools import reduce +from datetime import datetime, timedelta +from freqtrade.persistence import Trade + +# Get rid of pandas warnings during backtesting +import pandas as pd +pd.options.mode.chained_assignment = None # default='warn' + +# Strategy specific imports, files must reside in same folder as strategy +import sys +from pathlib import Path +sys.path.append(str(Path(__file__).parent)) + +# import custom_indicators as cta + +""" +Solipsis - By @werkkrew + +Credits - +@JimmyNixx for many of the ideas used throughout as well as helping me stay motivated throughout development! +@rk for submitting many PR's that have made this strategy possible! + +I ask for nothing in return except that if you make changes which bring you greater success than what has been provided, you share those ideas back to +the community. Also, please don't nag me with a million questions and especially don't blame me if you lose a ton of money using this. + +I take no responsibility for any success or failure you have using this strategy. + +VERSION: 5.2.1 +""" + + +""" +Misc. Helper Functions +""" +def same_length(bigger, shorter): + return np.concatenate((np.full((bigger.shape[0] - shorter.shape[0]), np.nan), shorter)) + +""" +Maths +""" +def linear_growth(start: float, end: float, start_time: int, end_time: int, trade_time: int) -> float: + """ + Simple linear growth function. Grows from start to end after end_time minutes (starts after start_time minutes) + """ + time = max(0, trade_time - start_time) + rate = (end - start) / (end_time - start_time) + + return min(end, start + (rate * time)) + +def linear_decay(start: float, end: float, start_time: int, end_time: int, trade_time: int) -> float: + """ + Simple linear decay function. Decays from start to end after end_time minutes (starts after start_time minutes) + """ + time = max(0, trade_time - start_time) + rate = (start - end) / (end_time - start_time) + + return max(end, start - (rate * time)) + +""" +TA Indicators +""" + +def zema(dataframe, period, field='close'): + """ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/overlap_studies.py#L79 + Modified slightly to use ta.EMA instead of technical ema + """ + df = dataframe.copy() + + df['ema1'] = ta.EMA(df[field], timeperiod=period) + df['ema2'] = ta.EMA(df['ema1'], timeperiod=period) + df['d'] = df['ema1'] - df['ema2'] + df['zema'] = df['ema1'] + df['d'] + + return df['zema'] + +def RMI(dataframe, *, length=20, mom=5): + """ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/indicators.py#L912 + """ + df = dataframe.copy() + + df['maxup'] = (df['close'] - df['close'].shift(mom)).clip(lower=0) + df['maxdown'] = (df['close'].shift(mom) - df['close']).clip(lower=0) + + df.fillna(0, inplace=True) + + df["emaInc"] = ta.EMA(df, price='maxup', timeperiod=length) + df["emaDec"] = ta.EMA(df, price='maxdown', timeperiod=length) + + df['RMI'] = np.where(df['emaDec'] == 0, 0, 100 - 100 / (1 + df["emaInc"] / df["emaDec"])) + + return df["RMI"] + +def mastreak(dataframe: DataFrame, period: int = 4, field='close') -> Series: + """ + MA Streak + Port of: https://www.tradingview.com/script/Yq1z7cIv-MA-Streak-Can-Show-When-a-Run-Is-Getting-Long-in-the-Tooth/ + """ + df = dataframe.copy() + + avgval = zema(df, period, field) + + arr = np.diff(avgval) + pos = np.clip(arr, 0, 1).astype(bool).cumsum() + neg = np.clip(arr, -1, 0).astype(bool).cumsum() + streak = np.where(arr >= 0, pos - np.maximum.accumulate(np.where(arr <= 0, pos, 0)), + -neg + np.maximum.accumulate(np.where(arr >= 0, neg, 0))) + + res = same_length(df['close'], streak) + + return res + +def pcc(dataframe: DataFrame, period: int = 20, mult: int = 2): + """ + Percent Change Channel + PCC is like KC unless it uses percentage changes in price to set channel distance. + https://www.tradingview.com/script/6wwAWXA1-MA-Streak-Change-Channel/ + """ + df = dataframe.copy() + + df['previous_close'] = df['close'].shift() + + df['close_change'] = (df['close'] - df['previous_close']) / df['previous_close'] * 100 + df['high_change'] = (df['high'] - df['close']) / df['close'] * 100 + df['low_change'] = (df['low'] - df['close']) / df['close'] * 100 + + df['delta'] = df['high_change'] - df['low_change'] + + mid = zema(df, period, 'close_change') + rangema = zema(df, period, 'delta') + + upper = mid + rangema * mult + lower = mid - rangema * mult + + return upper, rangema, lower + +def SSLChannels(dataframe, length=10, mode='sma'): + """ + Source: https://www.tradingview.com/script/xzIoaIJC-SSL-channel/ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/indicators.py#L1025 + Usage: + dataframe['sslDown'], dataframe['sslUp'] = SSLChannels(dataframe, 10) + """ + if mode not in ('sma'): + raise ValueError(f"Mode {mode} not supported yet") + + df = dataframe.copy() + + if mode == 'sma': + df['smaHigh'] = df['high'].rolling(length).mean() + df['smaLow'] = df['low'].rolling(length).mean() + + 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'] + +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'] + +def WaveTrend(dataframe, chlen=10, avg=21, smalen=4): + """ + WaveTrend Ocillator by LazyBear + https://www.tradingview.com/script/2KE8wTuF-Indicator-WaveTrend-Oscillator-WT/ + """ + df = dataframe.copy() + + df['hlc3'] = (df['high'] + df['low'] + df['close']) / 3 + df['esa'] = ta.EMA(df['hlc3'], timeperiod=chlen) + df['d'] = ta.EMA((df['hlc3'] - df['esa']).abs(), timeperiod=chlen) + df['ci'] = (df['hlc3'] - df['esa']) / (0.015 * df['d']) + df['tci'] = ta.EMA(df['ci'], timeperiod=avg) + + df['wt1'] = df['tci'] + df['wt2'] = ta.SMA(df['wt1'], timeperiod=smalen) + df['wt1-wt2'] = df['wt1'] - df['wt2'] + + return df['wt1'], df['wt2'] + +def T3(dataframe, length=5): + """ + T3 Average by HPotter on Tradingview + https://www.tradingview.com/script/qzoC9H1I-T3-Average/ + """ + df = dataframe.copy() + + df['xe1'] = ta.EMA(df['close'], timeperiod=length) + df['xe2'] = ta.EMA(df['xe1'], timeperiod=length) + df['xe3'] = ta.EMA(df['xe2'], timeperiod=length) + df['xe4'] = ta.EMA(df['xe3'], timeperiod=length) + df['xe5'] = ta.EMA(df['xe4'], timeperiod=length) + df['xe6'] = ta.EMA(df['xe5'], timeperiod=length) + b = 0.7 + c1 = -b*b*b + c2 = 3*b*b+3*b*b*b + c3 = -6*b*b-3*b-3*b*b*b + c4 = 1+3*b+b*b*b+3*b*b + df['T3Average'] = c1 * df['xe6'] + c2 * df['xe5'] + c3 * df['xe4'] + c4 * df['xe3'] + + return df['T3Average'] + + +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 + + +class Solipsis5(IStrategy): + + ## Buy Space Hyperopt Variables + + # Base Pair Params + base_mp = IntParameter(10, 50, default=30, space='buy', load=True, optimize=True) + base_rmi_max = IntParameter(30, 60, default=50, space='buy', load=True, optimize=True) + base_rmi_min = IntParameter(0, 30, default=20, space='buy', load=True, optimize=True) + base_ma_streak = IntParameter(1, 4, default=1, space='buy', load=True, optimize=True) + base_rmi_streak = IntParameter(3, 8, default=3, space='buy', load=True, optimize=True) + base_trigger = CategoricalParameter(['pcc', 'rmi', 'none'], default='rmi', space='buy', load=True, optimize=True) + inf_pct_adr = DecimalParameter(0.70, 0.99, default=0.80, space='buy', load=True, optimize=True) + # BTC Informative + xbtc_guard = CategoricalParameter(['strict', 'lazy', 'none'], default='lazy', space='buy', optimize=True) + xbtc_base_rmi = IntParameter(20, 70, default=40, space='buy', load=True, optimize=True) + # BTC / ETH Stake Parameters + xtra_base_stake_rmi = IntParameter(10, 50, default=50, space='buy', load=True, optimize=True) + xtra_base_fiat_rmi = IntParameter(30, 70, default=50, space='buy', load=True, optimize=True) + + ## Sell Space Params are being used for both custom_stoploss and custom_sell + + # Custom Sell Profit (formerly Dynamic ROI) + csell_roi_type = CategoricalParameter(['static', 'decay', 'step'], default='step', space='sell', load=True, optimize=True) + csell_roi_time = IntParameter(720, 1440, default=720, space='sell', load=True, optimize=True) + csell_roi_start = DecimalParameter(0.01, 0.05, default=0.01, space='sell', load=True, optimize=True) + csell_roi_end = DecimalParameter(0.0, 0.01, default=0, space='sell', load=True, optimize=True) + csell_trend_type = CategoricalParameter(['rmi', 'ssl', 'candle', 'any', 'none'], default='any', space='sell', load=True, optimize=True) + csell_pullback = CategoricalParameter([True, False], default=True, space='sell', load=True, optimize=True) + csell_pullback_amount = DecimalParameter(0.005, 0.03, default=0.01, space='sell', load=True, optimize=True) + csell_pullback_respect_roi = CategoricalParameter([True, False], default=False, space='sell', load=True, optimize=True) + csell_endtrend_respect_roi = CategoricalParameter([True, False], default=False, space='sell', load=True, optimize=True) + + # Custom Stoploss + cstop_loss_threshold = DecimalParameter(-0.05, -0.01, default=-0.03, space='sell', load=True, optimize=True) + cstop_bail_how = CategoricalParameter(['roc', 'time', 'any', 'none'], default='none', space='sell', load=True, optimize=True) + cstop_bail_roc = DecimalParameter(-5.0, -1.0, default=-3.0, space='sell', load=True, optimize=True) + cstop_bail_time = IntParameter(60, 1440, default=720, space='sell', load=True, optimize=True) + cstop_bail_time_trend = CategoricalParameter([True, False], default=True, space='sell', load=True, optimize=True) + + timeframe = '5m' + inf_timeframe = '1h' + + buy_params = {} + + sell_params = {} + + minimal_roi = { + "0": 100 + } + + stoploss = -0.99 + use_custom_stoploss = True + + # Recommended + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = True + + # Required + startup_candle_count: int = 233 + process_only_new_candles = False + + # Strategy Specific Variable Storage + custom_trade_info = {} + custom_fiat = "USD" # Only relevant if stake is BTC or ETH + custom_btc_inf = False # Don't change this. + + """ + Informative Pair Definitions + """ + def informative_pairs(self): + # add all whitelisted pairs on informative timeframe + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, self.inf_timeframe) for pair in pairs] + + # add extra informative pairs if the stake is BTC or ETH + if self.config['stake_currency'] in ('BTC', 'ETH'): + for pair in pairs: + coin, stake = pair.split('/') + coin_fiat = f"{coin}/{self.custom_fiat}" + informative_pairs += [(coin_fiat, self.timeframe)] + + stake_fiat = f"{self.config['stake_currency']}/{self.custom_fiat}" + informative_pairs += [(stake_fiat, self.timeframe)] + # if BTC/STAKE is not in whitelist, add it as an informative pair on both timeframes + else: + btc_stake = f"BTC/{self.config['stake_currency']}" + if not btc_stake in pairs: + informative_pairs += [(btc_stake, self.timeframe)] + + return informative_pairs + + """ + Indicator Definitions + """ + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + if not metadata['pair'] in self.custom_trade_info: + self.custom_trade_info[metadata['pair']] = {} + if not 'had-trend' in self.custom_trade_info[metadata["pair"]]: + self.custom_trade_info[metadata['pair']]['had-trend'] = False + + ## Base Timeframe / Pair + + # Kaufmann Adaptive Moving Average + dataframe['kama'] = ta.KAMA(dataframe, length=233) + + # RMI: https://www.tradingview.com/script/kwIt9OgQ-Relative-Momentum-Index/ + dataframe['rmi'] = RMI(dataframe, length=24, mom=5) + + # Momentum Pinball: https://www.tradingview.com/script/fBpVB1ez-Momentum-Pinball-Indicator/ + dataframe['roc-mp'] = ta.ROC(dataframe, timeperiod=1) + dataframe['mp'] = ta.RSI(dataframe['roc-mp'], timeperiod=3) + + # MA Streak: https://www.tradingview.com/script/Yq1z7cIv-MA-Streak-Can-Show-When-a-Run-Is-Getting-Long-in-the-Tooth/ + dataframe['mastreak'] = mastreak(dataframe, period=4) + + # Percent Change Channel: https://www.tradingview.com/script/6wwAWXA1-MA-Streak-Change-Channel/ + upper, mid, lower = pcc(dataframe, period=40, mult=3) + dataframe['pcc-lowerband'] = lower + dataframe['pcc-upperband'] = upper + + lookup_idxs = dataframe.index.values - (abs(dataframe['mastreak'].values) + 1) + valid_lookups = lookup_idxs >= 0 + dataframe['sbc'] = np.nan + dataframe.loc[valid_lookups, 'sbc'] = dataframe['close'].to_numpy()[lookup_idxs[valid_lookups].astype(int)] + + dataframe['streak-roc'] = 100 * (dataframe['close'] - dataframe['sbc']) / dataframe['sbc'] + + # Trends, Peaks and Crosses + dataframe['candle-up'] = np.where(dataframe['close'] >= dataframe['open'],1,0) + dataframe['candle-up-trend'] = np.where(dataframe['candle-up'].rolling(5).sum() >= 3,1,0) + + dataframe['rmi-up'] = np.where(dataframe['rmi'] >= dataframe['rmi'].shift(),1,0) + dataframe['rmi-up-trend'] = np.where(dataframe['rmi-up'].rolling(5).sum() >= 3,1,0) + + dataframe['rmi-dn'] = np.where(dataframe['rmi'] <= dataframe['rmi'].shift(),1,0) + dataframe['rmi-dn-count'] = dataframe['rmi-dn'].rolling(8).sum() + + dataframe['streak-bo'] = np.where(dataframe['streak-roc'] < dataframe['pcc-lowerband'],1,0) + dataframe['streak-bo-count'] = dataframe['streak-bo'].rolling(8).sum() + + # Indicators used only for ROI and Custom Stoploss + ssldown, sslup = SSLChannels_ATR(dataframe, length=21) + dataframe['sroc'] = SROC(dataframe, roclen=21, emalen=13, smooth=21) + dataframe['ssl-dir'] = np.where(sslup > ssldown,'up','down') + + # Base pair informative timeframe indicators + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_timeframe) + + # Get the "average day range" between the 1d high and 1d low to set up guards + informative['1d-high'] = informative['close'].rolling(24).max() + informative['1d-low'] = informative['close'].rolling(24).min() + informative['adr'] = informative['1d-high'] - informative['1d-low'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_timeframe, ffill=True) + + # Other stake specific informative indicators + # e.g if stake is BTC and current coin is XLM (pair: XLM/BTC) + if self.config['stake_currency'] in ('BTC', 'ETH'): + coin, stake = metadata['pair'].split('/') + fiat = self.custom_fiat + coin_fiat = f"{coin}/{fiat}" + stake_fiat = f"{stake}/{fiat}" + + # Informative COIN/FIAT e.g. XLM/USD - Base Timeframe + coin_fiat_tf = self.dp.get_pair_dataframe(pair=coin_fiat, timeframe=self.timeframe) + dataframe[f"{fiat}_rmi"] = RMI(coin_fiat_tf, length=55, mom=5) + + # Informative STAKE/FIAT e.g. BTC/USD - Base Timeframe + stake_fiat_tf = self.dp.get_pair_dataframe(pair=stake_fiat, timeframe=self.timeframe) + dataframe[f"{stake}_rmi"] = RMI(stake_fiat_tf, length=55, mom=5) + + # Informatives for BTC/STAKE if not in whitelist + else: + pairs = self.dp.current_whitelist() + btc_stake = f"BTC/{self.config['stake_currency']}" + if not btc_stake in pairs: + self.custom_btc_inf = True + # BTC/STAKE - Base Timeframe + btc_stake_tf = self.dp.get_pair_dataframe(pair=btc_stake, timeframe=self.timeframe) + dataframe['BTC_rmi'] = RMI(btc_stake_tf, length=55, mom=5) + dataframe['BTC_close'] = btc_stake_tf['close'] + dataframe['BTC_kama'] = ta.KAMA(btc_stake_tf, length=144) + + return dataframe + + """ + Buy Signal + """ + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + # Informative Timeframe Guards + conditions.append( + (dataframe['close'] <= dataframe[f"1d-low_{self.inf_timeframe}"] + + (self.inf_pct_adr.value * dataframe[f"adr_{self.inf_timeframe}"])) + ) + + # Base Timeframe Guards + conditions.append( + (dataframe['rmi-dn-count'] >= self.base_rmi_streak.value) & + (dataframe['streak-bo-count'] >= self.base_ma_streak.value) & + (dataframe['rmi'] <= self.base_rmi_max.value) & + (dataframe['rmi'] >= self.base_rmi_min.value) & + (dataframe['mp'] <= self.base_mp.value) + ) + + # Base Timeframe Trigger + if self.base_trigger.value == 'pcc': + conditions.append(qtpylib.crossed_above(dataframe['streak-roc'], dataframe['pcc-lowerband'])) + + if self.base_trigger.value == 'rmi': + conditions.append(dataframe['rmi-up-trend'] == 1) + + # Extra conditions for */BTC and */ETH stakes on additional informative pairs + if self.config['stake_currency'] in ('BTC', 'ETH'): + conditions.append( + (dataframe[f"{self.custom_fiat}_rmi"] > self.xtra_base_fiat_rmi.value) | + (dataframe[f"{self.config['stake_currency']}_rmi"] < self.xtra_base_stake_rmi.value) + ) + # Extra conditions for BTC/STAKE if not in whitelist + else: + if self.custom_btc_inf: + if self.xbtc_guard.value == 'strict': + conditions.append( + ( + (dataframe['BTC_rmi'] > self.xbtc_base_rmi.value) & + (dataframe['BTC_close'] > dataframe['BTC_kama']) + ) + ) + if self.xbtc_guard.value == 'lazy': + conditions.append( + (dataframe['close'] > dataframe['kama']) | + ( + (dataframe['BTC_rmi'] > self.xbtc_base_rmi.value) & + (dataframe['BTC_close'] > dataframe['BTC_kama']) + ) + ) + + conditions.append(dataframe['volume'].gt(0)) + + if conditions: + dataframe.loc[ + reduce(lambda x, y: x & y, conditions), + 'buy'] = 1 + + return dataframe + + """ + Sell Signal + """ + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe['sell'] = 0 + + return dataframe + + """ + Custom Stoploss + """ + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60) + in_trend = self.custom_trade_info[trade.pair]['had-trend'] + + # Determine how we sell when we are in a loss + if current_profit < self.cstop_loss_threshold.value: + if self.cstop_bail_how.value == 'roc' or self.cstop_bail_how.value == 'any': + # Dynamic bailout based on rate of change + if last_candle['sroc'] <= self.cstop_bail_roc.value: + return 0.01 + if self.cstop_bail_how.value == 'time' or self.cstop_bail_how.value == 'any': + # Dynamic bailout based on time, unless time_trend is true and there is a potential reversal + if trade_dur > self.cstop_bail_time.value: + if self.cstop_bail_time_trend.value == True and in_trend == True: + return 1 + else: + return 0.01 + return 1 + + """ + Custom Sell + """ + def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, + current_profit: float, **kwargs): + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + + trade_dur = int((current_time.timestamp() - trade.open_date_utc.timestamp()) // 60) + max_profit = max(0, trade.calc_profit_ratio(trade.max_rate)) + pullback_value = max(0, (max_profit - self.csell_pullback_amount.value)) + in_trend = False + + # Determine our current ROI point based on the defined type + if self.csell_roi_type.value == 'static': + min_roi = self.csell_roi_start.value + elif self.csell_roi_type.value == 'decay': + min_roi = linear_decay(self.csell_roi_start.value, self.csell_roi_end.value, 0, self.csell_roi_time.value, trade_dur) + elif self.csell_roi_type.value == 'step': + if trade_dur < self.csell_roi_time.value: + min_roi = self.csell_roi_start.value + else: + min_roi = self.csell_roi_end.value + + # Determine if there is a trend + if self.csell_trend_type.value == 'rmi' or self.csell_trend_type.value == 'any': + if last_candle['rmi-up-trend'] == 1: + in_trend = True + if self.csell_trend_type.value == 'ssl' or self.csell_trend_type.value == 'any': + if last_candle['ssl-dir'] == 'up': + in_trend = True + if self.csell_trend_type.value == 'candle' or self.csell_trend_type.value == 'any': + if last_candle['candle-up-trend'] == 1: + in_trend = True + + # Don't sell if we are in a trend unless the pullback threshold is met + if in_trend == True and current_profit > 0: + # Record that we were in a trend for this trade/pair for a more useful sell message later + self.custom_trade_info[trade.pair]['had-trend'] = True + # If pullback is enabled and profit has pulled back allow a sell, maybe + if self.csell_pullback.value == True and (current_profit <= pullback_value): + if self.csell_pullback_respect_roi.value == True and current_profit > min_roi: + return 'intrend_pullback_roi' + elif self.csell_pullback_respect_roi.value == False: + if current_profit > min_roi: + return 'intrend_pullback_roi' + else: + return 'intrend_pullback_noroi' + # We are in a trend and pullback is disabled or has not happened or various criteria were not met, hold + return None + # If we are not in a trend, just use the roi value + elif in_trend == False: + if self.custom_trade_info[trade.pair]['had-trend']: + if current_profit > min_roi: + self.custom_trade_info[trade.pair]['had-trend'] = False + return 'trend_roi' + elif self.csell_endtrend_respect_roi.value == False: + self.custom_trade_info[trade.pair]['had-trend'] = False + return 'trend_noroi' + elif current_profit > min_roi: + return 'notrend_roi' + else: + return None + diff --git a/StJD01.py b/StJD01.py new file mode 100644 index 0000000..2747fa1 --- /dev/null +++ b/StJD01.py @@ -0,0 +1,506 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 + +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, + IStrategy, IntParameter) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class StJD01(IStrategy): + """ + This is a strategy template to get you started. + More information in https://www.freqtrade.io/en/latest/strategy-customization/ + + You can: + :return: a Dataframe with all mandatory indicators for the strategies + - Rename the class name (Do not forget to update class_name) + - Add any methods you want to build your strategy + - Add any lib you need to build your strategy + + You must keep: + - the lib in the section "Do not remove these libs" + - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + You should keep: + - timeframe, minimal_roi, stoploss, trailing_* + """ + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + "0": 100 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -1 + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.015 + trailing_only_offset_is_reached = True + + # Optimal timeframe for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + 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 + # ------------------------------------ + + # # ADX + # dataframe['adx'] = ta.ADX(dataframe) + # + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + # + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # Awesome Oscillator + dataframe['ao'] = qtpylib.awesome_oscillator(dataframe) + + # # Keltner Channel + # keltner = qtpylib.keltner_channel(dataframe) + # dataframe["kc_upperband"] = keltner["upper"] + # dataframe["kc_lowerband"] = keltner["lower"] + # dataframe["kc_middleband"] = keltner["mid"] + # dataframe["kc_percent"] = ( + # (dataframe["close"] - dataframe["kc_lowerband"]) / + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + # ) + # dataframe["kc_width"] = ( + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + # ) + + # # Ultimate Oscillator + # dataframe['uo'] = ta.ULTOSC(dataframe) + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + # dataframe['cci'] = ta.CCI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. + # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # # ROC + # dataframe['roc'] = ta.ROC(dataframe) + + # Overlap Studies + # ------------------------------------ + + + fast_period = 5 + slow_period = 50 + dataframe['fast_MA'] = ta.SMA(dataframe, timeperiod=fast_period) + dataframe['slow_MA'] = ta.SMA(dataframe, timeperiod=slow_period) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + + # Parabolic SAR + dataframe['sar'] = ta.SAR(dataframe) + + # TEMA - Triple Exponential Moving Average + dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9) + + # # Cycle Indicator + # # ------------------------------------ + # # Hilbert Transform Indicator - SineWave + # hilbert = ta.HT_SINE(dataframe) + # dataframe['htsine'] = hilbert['sine'] + # dataframe['htleadsine'] = hilbert['leadsine'] + # + # # Pattern Recognition - Bullish candlestick patterns + # # ------------------------------------ + # # Hammer: values [0, 100] + # dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + # # Inverted Hammer: values [0, 100] + # dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe) + # # Dragonfly Doji: values [0, 100] + # dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe) + # # Piercing Line: values [0, 100] + # dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100] + # # Morningstar: values [0, 100] + # dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100] + # # Three White Soldiers: values [0, 100] + # dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100] + + # Pattern Recognition - Bearish candlestick patterns + # ------------------------------------ + # # Hanging Man: values [0, 100] + # dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe) + # # Shooting Star: values [0, 100] + # dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe) + # # Gravestone Doji: values [0, 100] + # dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe) + # # Dark Cloud Cover: values [0, 100] + # dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe) + # # Evening Doji Star: values [0, 100] + # dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe) + # # Evening Star: values [0, 100] + # dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe) + + # Pattern Recognition - Bullish/Bearish candlestick patterns + # ------------------------------------ + # # Three Line Strike: values [0, -100, 100] + # dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe) + # # Spinning Top: values [0, -100, 100] + # dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100] + # # Engulfing: values [0, -100, 100] + # dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100] + # # Harami: values [0, -100, 100] + # dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100] + # # Three Outside Up/Down: values [0, -100, 100] + # dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100] + # # Three Inside Up/Down: values [0, -100, 100] + # dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100] + + # # Chart type + # # ------------------------------------ + # # Heikin Ashi Strategy + # heikinashi = qtpylib.heikinashi(dataframe) + # dataframe['ha_open'] = heikinashi['open'] + # dataframe['ha_close'] = heikinashi['close'] + # dataframe['ha_high'] = heikinashi['high'] + # dataframe['ha_low'] = heikinashi['low'] + + # Retrieve best bid and best ask from the orderbook + # ------------------------------------ + """ + # first check if dataprovider is available + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + ob = self.dp.orderbook(metadata['pair'], 1) + dataframe['best_bid'] = ob['bids'][0][0] + dataframe['best_ask'] = ob['asks'][0][0] + """ + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + qtpylib.crossed_above(dataframe['fast_MA'], dataframe['slow_MA']) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + qtpylib.crossed_below(dataframe['fast_MA'], dataframe['slow_MA']) + ), + 'sell' + ] = 1 + + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) # & + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def three_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def three_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/StJD02.py b/StJD02.py new file mode 100644 index 0000000..db17d9c --- /dev/null +++ b/StJD02.py @@ -0,0 +1,525 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# flake8: noqa: F401 + +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, + IStrategy, IntParameter) + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class StJD02(IStrategy): + """ + This is a strategy template to get you started. + More information in https://www.freqtrade.io/en/latest/strategy-customization/ + + You can: + :return: a Dataframe with all mandatory indicators for the strategies + - Rename the class name (Do not forget to update class_name) + - Add any methods you want to build your strategy + - Add any lib you need to build your strategy + + You must keep: + - the lib in the section "Do not remove these libs" + - the methods: populate_indicators, populate_buy_trend, populate_sell_trend + You should keep: + - timeframe, minimal_roi, stoploss, trailing_* + """ + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + "0": 0.015 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -0.03 + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.015 + trailing_only_offset_is_reached = True + + # Optimal timeframe for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + 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 + # ------------------------------------ + + # # ADX + # dataframe['adx'] = ta.ADX(dataframe) + # + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + # + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # Awesome Oscillator + dataframe['ao'] = qtpylib.awesome_oscillator(dataframe) + + # # Keltner Channel + # keltner = qtpylib.keltner_channel(dataframe) + # dataframe["kc_upperband"] = keltner["upper"] + # dataframe["kc_lowerband"] = keltner["lower"] + # dataframe["kc_middleband"] = keltner["mid"] + # dataframe["kc_percent"] = ( + # (dataframe["close"] - dataframe["kc_lowerband"]) / + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) + # ) + # dataframe["kc_width"] = ( + # (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"] + # ) + + # # Ultimate Oscillator + # dataframe['uo'] = ta.ULTOSC(dataframe) + + # # Commodity Channel Index: values [Oversold:-100, Overbought:100] + # dataframe['cci'] = ta.CCI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1) + + # # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy) + # dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # # Stochastic Slow + # stoch = ta.STOCH(dataframe) + # dataframe['slowd'] = stoch['slowd'] + # dataframe['slowk'] = stoch['slowk'] + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + # Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this. + # STOCHRSI is NOT aligned with tradingview, which may result in non-expected results. + # stoch_rsi = ta.STOCHRSI(dataframe) + # dataframe['fastd_rsi'] = stoch_rsi['fastd'] + # dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # # ROC + # dataframe['roc'] = ta.ROC(dataframe) + + # Overlap Studies + # ------------------------------------ + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + fast_period = 5 + slow_period = 50 + dataframe['fast_MA'] = ta.SMA(dataframe, timeperiod=fast_period) + dataframe['slow_MA'] = ta.SMA(dataframe, timeperiod=slow_period) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + + # Parabolic SAR + dataframe['sar'] = ta.SAR(dataframe) + + # TEMA - Triple Exponential Moving Average + dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9) + + # # Cycle Indicator + # # ------------------------------------ + # # Hilbert Transform Indicator - SineWave + # hilbert = ta.HT_SINE(dataframe) + # dataframe['htsine'] = hilbert['sine'] + # dataframe['htleadsine'] = hilbert['leadsine'] + # + # # Pattern Recognition - Bullish candlestick patterns + # # ------------------------------------ + # # Hammer: values [0, 100] + # dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + # # Inverted Hammer: values [0, 100] + # dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe) + # # Dragonfly Doji: values [0, 100] + # dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe) + # # Piercing Line: values [0, 100] + # dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100] + # # Morningstar: values [0, 100] + # dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100] + # # Three White Soldiers: values [0, 100] + # dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100] + + # Pattern Recognition - Bearish candlestick patterns + # ------------------------------------ + # # Hanging Man: values [0, 100] + # dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe) + # # Shooting Star: values [0, 100] + # dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe) + # # Gravestone Doji: values [0, 100] + # dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe) + # # Dark Cloud Cover: values [0, 100] + # dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe) + # # Evening Doji Star: values [0, 100] + # dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe) + # # Evening Star: values [0, 100] + # dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe) + + # Pattern Recognition - Bullish/Bearish candlestick patterns + # ------------------------------------ + # # Three Line Strike: values [0, -100, 100] + # dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe) + # # Spinning Top: values [0, -100, 100] + # dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100] + # # Engulfing: values [0, -100, 100] + # dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100] + # # Harami: values [0, -100, 100] + # dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100] + # # Three Outside Up/Down: values [0, -100, 100] + # dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100] + # # Three Inside Up/Down: values [0, -100, 100] + # dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100] + + # # Chart type + # # ------------------------------------ + # # Heikin Ashi Strategy + # heikinashi = qtpylib.heikinashi(dataframe) + # dataframe['ha_open'] = heikinashi['open'] + # dataframe['ha_close'] = heikinashi['close'] + # dataframe['ha_high'] = heikinashi['high'] + # dataframe['ha_low'] = heikinashi['low'] + + # Linear Regression Angle + + #dataframe['angle'] = ta.LINEARREG_ANGLE(dataframe['close'], timeperiod=5) + dataframe['angle'] = ta.LINEARREG_ANGLE(dataframe['close'], timeperiod=30) + + # Linear Regression Line + dataframe['lr_middle'] = ta.LINEARREG(dataframe['close'], timeperiod=25) + dataframe['atr'] = ta.ATR(dataframe, timeperiod=25) + dataframe['lr_lower1.0'] = dataframe['lr_middle'] - dataframe['atr'] * 1 + + # Retrieve best bid and best ask from the orderbook + # ------------------------------------ + """ + # first check if dataprovider is available + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + ob = self.dp.orderbook(metadata['pair'], 1) + dataframe['best_bid'] = ob['bids'][0][0] + dataframe['best_ask'] = ob['asks'][0][0] + """ + + 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.loc[ + ( + # (dataframe["close"] >= dataframe["bb_upperband"]) & + (dataframe["close"] < dataframe["bb_lowerband"]) & + (dataframe["angle"] > 0) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + '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 populated with indicators + :param metadata: Additional information, like the currently traded pair + :return: DataFrame with buy column + dataframe.loc[ + ( + (StrategyHelperLocal.two_red_candles(dataframe)) & + (dataframe["bb_upperband"].shift(1) > dataframe["bb_upperband"]) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'sell'] = 1 + """ + return dataframe + + +class StrategyHelperLocal: + """ + simple helper class to predefine a couple of patterns for our + strategy + """ + + @staticmethod + def two_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (dataframe['open'] < dataframe['close']) & + (dataframe['open'].shift(1) < dataframe['close'].shift(1)) # & + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) + ) + + @staticmethod + def three_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def seven_green_candles(dataframe): + """ + evaluates if we are having 7 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def eight_green_candles(dataframe): + """ + evaluates if we are having 8 green candles in a row + :param self: + :param dataframe: + :return: + """ + return ( + (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['open'].shift(8) < dataframe['close'].shift(8)) + ) + + @staticmethod + def two_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) + ) + + @staticmethod + def four_red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) + # (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + # (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + # (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) & + # (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift)) + ) + + @staticmethod + def four_green_one_red_candle(dataframe): + """ + evaluates if we are having a red candle and 4 previous green + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) + + @staticmethod + def four_red_one_green_candle(dataframe): + """ + evaluates if we are having a green candle and 4 previous red + :param self: + :param dataframe: + :return: + """ + return ( + (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)) + ) diff --git a/Strategy001.py b/Strategy001.py new file mode 100644 index 0000000..64be087 --- /dev/null +++ b/Strategy001.py @@ -0,0 +1,121 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class Strategy001(IStrategy): + """ + Strategy 001 + author@: Gerald Lonlas + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy001 + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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. + """ + + dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['ha_open'] = heikinashi['open'] + dataframe['ha_close'] = heikinashi['close'] + + 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[ + ( + qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) & + (dataframe['ha_close'] > dataframe['ema20']) & + (dataframe['ha_open'] < dataframe['ha_close']) # green bar + ), + '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[ + ( + qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) & + (dataframe['ha_close'] < dataframe['ema20']) & + (dataframe['ha_open'] > dataframe['ha_close']) # red bar + ), + 'sell'] = 1 + return dataframe diff --git a/Strategy001_custom_sell.py b/Strategy001_custom_sell.py new file mode 100644 index 0000000..231d085 --- /dev/null +++ b/Strategy001_custom_sell.py @@ -0,0 +1,141 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +class Strategy001_custom_sell(IStrategy): + + """ + Strategy 001_custom_sell + author@: Gerald Lonlas, froggleston + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy001_custom_sell + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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. + """ + + dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['ha_open'] = heikinashi['open'] + dataframe['ha_close'] = heikinashi['close'] + + dataframe['rsi'] = ta.RSI(dataframe, 14) + + 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[ + ( + qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) & + (dataframe['ha_close'] > dataframe['ema20']) & + (dataframe['ha_open'] < dataframe['ha_close']) # green bar + ), + '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[ + ( + qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) & + (dataframe['ha_close'] < dataframe['ema20']) & + (dataframe['ha_open'] > dataframe['ha_close']) # red bar + ), + 'sell'] = 1 + return dataframe + + def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float, current_profit: float, **kwargs): + """ + Sell only when matching some criteria other than those used to generate the sell signal + :return: str sell_reason, if any, otherwise None + """ + # get dataframe + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + + # get the current candle + current_candle = dataframe.iloc[-1].squeeze() + + # if RSI greater than 70 and profit is positive, then sell + if (current_candle['rsi'] > 70) and (current_profit > 0): + return "rsi_profit_sell" + + # else, hold + return None \ No newline at end of file diff --git a/Strategy002.py b/Strategy002.py new file mode 100644 index 0000000..a7c0c98 --- /dev/null +++ b/Strategy002.py @@ -0,0 +1,135 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy # noqa + + +class Strategy002(IStrategy): + """ + Strategy 002 + author@: Gerald Lonlas + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy002 + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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. + """ + + # Stoch + stoch = ta.STOCH(dataframe) + dataframe['slowk'] = stoch['slowk'] + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] - 50) + dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) + + # Bollinger bands + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) + dataframe['bb_lowerband'] = bollinger['lower'] + + # SAR Parabol + dataframe['sar'] = ta.SAR(dataframe) + + # Hammer: values [0, 100] + dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + + 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['rsi'] < 30) & + (dataframe['slowk'] < 20) & + (dataframe['bb_lowerband'] > dataframe['close']) & + (dataframe['CDLHAMMER'] == 100) + ), + '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['sar'] > dataframe['close']) & + (dataframe['fisher_rsi'] > 0.3) + ), + 'sell'] = 1 + return dataframe diff --git a/Strategy003.py b/Strategy003.py new file mode 100644 index 0000000..8d8630b --- /dev/null +++ b/Strategy003.py @@ -0,0 +1,152 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy # noqa + + +class Strategy003(IStrategy): + """ + Strategy 003 + author@: Gerald Lonlas + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy003 + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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. + """ + + # MFI + dataframe['mfi'] = ta.MFI(dataframe) + + # Stoch fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] - 50) + dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) + + # Bollinger bands + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) + dataframe['bb_lowerband'] = bollinger['lower'] + + # EMA - Exponential Moving Average + dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # SAR Parabol + dataframe['sar'] = ta.SAR(dataframe) + + # SMA - Simple Moving Average + dataframe['sma'] = ta.SMA(dataframe, timeperiod=40) + + 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['rsi'] < 28) & + (dataframe['rsi'] > 0) & + (dataframe['close'] < dataframe['sma']) & + (dataframe['fisher_rsi'] < -0.94) & + (dataframe['mfi'] < 16.0) & + ( + (dataframe['ema50'] > dataframe['ema100']) | + (qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10'])) + ) & + (dataframe['fastd'] > dataframe['fastk']) & + (dataframe['fastd'] > 0) + ), + '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['sar'] > dataframe['close']) & + (dataframe['fisher_rsi'] > 0.3) + ), + 'sell'] = 1 + return dataframe diff --git a/Strategy004.py b/Strategy004.py new file mode 100644 index 0000000..120aff1 --- /dev/null +++ b/Strategy004.py @@ -0,0 +1,154 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta + + +class Strategy004(IStrategy): + + """ + Strategy 004 + author@: Gerald Lonlas + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy004 + """ + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "60": 0.01, + "30": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + 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. + """ + + # ADX + dataframe['adx'] = ta.ADX(dataframe) + dataframe['slowadx'] = ta.ADX(dataframe, 35) + + # Commodity Channel Index: values Oversold:<-100, Overbought:>100 + dataframe['cci'] = ta.CCI(dataframe) + + # Stoch + stoch = ta.STOCHF(dataframe, 5) + dataframe['fastd'] = stoch['fastd'] + dataframe['fastk'] = stoch['fastk'] + dataframe['fastk-previous'] = dataframe.fastk.shift(1) + dataframe['fastd-previous'] = dataframe.fastd.shift(1) + + # Slow Stoch + slowstoch = ta.STOCHF(dataframe, 50) + dataframe['slowfastd'] = slowstoch['fastd'] + dataframe['slowfastk'] = slowstoch['fastk'] + dataframe['slowfastk-previous'] = dataframe.slowfastk.shift(1) + dataframe['slowfastd-previous'] = dataframe.slowfastd.shift(1) + + # EMA - Exponential Moving Average + dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + + dataframe['mean-volume'] = dataframe['volume'].mean() + + 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['adx'] > 50) | + (dataframe['slowadx'] > 26) + ) & + (dataframe['cci'] < -100) & + ( + (dataframe['fastk-previous'] < 20) & + (dataframe['fastd-previous'] < 20) + ) & + ( + (dataframe['slowfastk-previous'] < 30) & + (dataframe['slowfastd-previous'] < 30) + ) & + (dataframe['fastk-previous'] < dataframe['fastd-previous']) & + (dataframe['fastk'] > dataframe['fastd']) & + (dataframe['mean-volume'] > 0.75) & + (dataframe['close'] > 0.00000100) + ), + '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['slowadx'] < 25) & + ((dataframe['fastk'] > 70) | (dataframe['fastd'] > 70)) & + (dataframe['fastk-previous'] < dataframe['fastd-previous']) & + (dataframe['close'] > dataframe['ema5']) + ), + 'sell'] = 1 + return dataframe diff --git a/Strategy005.json b/Strategy005.json new file mode 100644 index 0000000..074584d --- /dev/null +++ b/Strategy005.json @@ -0,0 +1,36 @@ +{ + "strategy_name": "Strategy005", + "params": { + "roi": { + "0": 0.05, + "20": 0.04, + "40": 0.03, + "80": 0.02, + "1440": 0.01 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.01, + "trailing_stop_positive_offset": 0.02, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_fastd": 7, + "buy_fishRsiNorma": 80, + "buy_rsi": 31, + "buy_volumeAVG": 119 + }, + "sell": { + "sell_fishRsiNorma": 30, + "sell_minusDI": 4, + "sell_rsi": 74, + "sell_trigger": "rsi-macd-minusdi" + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 18:45:24.449663+00:00" +} \ No newline at end of file diff --git a/Strategy005.py b/Strategy005.py new file mode 100644 index 0000000..7c23f28 --- /dev/null +++ b/Strategy005.py @@ -0,0 +1,185 @@ + +# --- Do not remove these libs --- +from freqtrade.strategy import IStrategy +from freqtrade.strategy import CategoricalParameter, IntParameter +from functools import reduce +from pandas import DataFrame +# -------------------------------- + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy # noqa + + +class Strategy005(IStrategy): + """ + Strategy 005 + author@: Gerald Lonlas + github@: https://github.com/freqtrade/freqtrade-strategies + + How to use it? + > python3 ./freqtrade/main.py -s Strategy005 + """ + INTERFACE_VERSION = 2 + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi" + minimal_roi = { + "1440": 0.01, + "80": 0.02, + "40": 0.03, + "20": 0.04, + "0": 0.05 + } + + # Optimal stoploss designed for the strategy + # This attribute will be overridden if the config file contains "stoploss" + stoploss = -1 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = 0.02 + + # run "populate_indicators" only for new candle + process_only_new_candles = False + + # Experimental settings (configuration will overide these if set) + use_sell_signal = True + sell_profit_only = True + ignore_roi_if_buy_signal = False + + # Optional order type mapping + order_types = { + 'buy': 'limit', + 'sell': 'limit', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + buy_volumeAVG = IntParameter(low=50, high=300, default=70, space='buy', optimize=True) + buy_rsi = IntParameter(low=1, high=100, default=30, space='buy', optimize=True) + buy_fastd = IntParameter(low=1, high=100, default=30, space='buy', optimize=True) + buy_fishRsiNorma = IntParameter(low=1, high=100, default=30, space='buy', optimize=True) + + sell_rsi = IntParameter(low=1, high=100, default=70, space='sell', optimize=True) + sell_minusDI = IntParameter(low=1, high=100, default=50, space='sell', optimize=True) + sell_fishRsiNorma = IntParameter(low=1, high=100, default=50, space='sell', optimize=True) + sell_trigger = CategoricalParameter(["rsi-macd-minusdi", "sar-fisherRsi"], + default=30, space='sell', optimize=True) + + # Buy hyperspace params: + buy_params = { + "buy_fastd": 1, + "buy_fishRsiNorma": 5, + "buy_rsi": 26, + "buy_volumeAVG": 150, + } + + # Sell hyperspace params: + sell_params = { + "sell_fishRsiNorma": 30, + "sell_minusDI": 4, + "sell_rsi": 74, + "sell_trigger": "rsi-macd-minusdi", + } + + 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. + """ + + # MACD + macd = ta.MACD(dataframe) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + + # Minus Directional Indicator / Movement + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) + rsi = 0.1 * (dataframe['rsi'] - 50) + dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) + # Inverse Fisher transform on RSI normalized, value [0.0, 100.0] (https://goo.gl/2JGGoy) + dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1) + + # Stoch fast + stoch_fast = ta.STOCHF(dataframe) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # Overlap Studies + # ------------------------------------ + + # SAR Parabol + dataframe['sar'] = ta.SAR(dataframe) + + # SMA - Simple Moving Average + dataframe['sma'] = ta.SMA(dataframe, timeperiod=40) + + 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[ + # Prod + ( + (dataframe['close'] > 0.00000200) & + (dataframe['volume'] > dataframe['volume'].rolling(self.buy_volumeAVG.value).mean() * 4) & + (dataframe['close'] < dataframe['sma']) & + (dataframe['fastd'] > dataframe['fastk']) & + (dataframe['rsi'] > self.buy_rsi.value) & + (dataframe['fastd'] > self.buy_fastd.value) & + (dataframe['fisher_rsi_norma'] < self.buy_fishRsiNorma.value) + ), + '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 + """ + + conditions = [] + if self.sell_trigger.value == 'rsi-macd-minusdi': + conditions.append(qtpylib.crossed_above(dataframe['rsi'], self.sell_rsi.value)) + conditions.append(dataframe['macd'] < 0) + conditions.append(dataframe['minus_di'] > self.sell_minusDI.value) + if self.sell_trigger.value == 'sar-fisherRsi': + conditions.append(dataframe['sar'] > dataframe['close']) + conditions.append(dataframe['fisher_rsi'] > self.sell_fishRsiNorma.value) + + if conditions: + dataframe.loc[reduce(lambda x, y: x & y, conditions), 'sell'] = 1 + + return dataframe diff --git a/StrategyJD.json b/StrategyJD.json new file mode 100644 index 0000000..7e0bf30 --- /dev/null +++ b/StrategyJD.json @@ -0,0 +1,29 @@ +{ + "strategy_name": "StrategyJD", + "params": { + "stoploss": { + "stoploss": -0.118 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_decalage": 12, + "buy_sma_percent": 0.98 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.391, + "142": 0.134, + "347": 0.067, + "818": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-09 15:16:01.241716+00:00" +} \ No newline at end of file diff --git a/StrategyJD.jsonPositive b/StrategyJD.jsonPositive new file mode 100644 index 0000000..7e0bf30 --- /dev/null +++ b/StrategyJD.jsonPositive @@ -0,0 +1,29 @@ +{ + "strategy_name": "StrategyJD", + "params": { + "stoploss": { + "stoploss": -0.118 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_decalage": 12, + "buy_sma_percent": 0.98 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.391, + "142": 0.134, + "347": 0.067, + "818": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-09 15:16:01.241716+00:00" +} \ No newline at end of file diff --git a/StrategyJD.py b/StrategyJD.py new file mode 100644 index 0000000..88e85c5 --- /dev/null +++ b/StrategyJD.py @@ -0,0 +1,282 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyJD(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=1, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + # def custom_sell(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() + # + # # Above 20% profit, sell when rsi < 80 + # if current_profit > 0.2: + # if last_candle['rsi'] < 80: + # return 'rsi_below_80' + # + # # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # dataframe["rolling"] = (100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling(5).mean() + # dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + # dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)), + (dataframe['msma10_3'] > 0.998) + ] + # GUARDS AND TRENDS + + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma_' + str(decalage)) + break + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_1.json b/StrategyJD_1.json new file mode 100644 index 0000000..cdaa38b --- /dev/null +++ b/StrategyJD_1.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyJD_1", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_decalage": 17 + }, + "sell": {}, + "protection": { + "n_percent": 5, + "percent_sell": -0.05 + }, + "roi": { + "0": 0.41700000000000004, + "153": 0.14200000000000002, + "212": 0.044, + "658": 0 + }, + "stoploss": { + "stoploss": -0.069 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-09 18:26:53.845529+00:00" +} \ No newline at end of file diff --git a/StrategyJD_1.py b/StrategyJD_1.py new file mode 100644 index 0000000..d461a6c --- /dev/null +++ b/StrategyJD_1.py @@ -0,0 +1,287 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyJD_1(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=1, space="buy") + + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + for n in range(1, 13): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # dataframe["rolling"] = (100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling(5).mean() + # dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + # dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)), + (dataframe['msma10_3'] > 0.998) + ] + # GUARDS AND TRENDS + + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma_' + str(decalage)) + break + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_2.json b/StrategyJD_2.json new file mode 100644 index 0000000..1bf7043 --- /dev/null +++ b/StrategyJD_2.json @@ -0,0 +1,30 @@ +{ + "strategy_name": "StrategyJD_2", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_decalage": 10, + "buy_rsi_max": 83, + "buy_rsi_min": 9 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.225, + "191": 0.126, + "423": 0.078, + "673": 0 + }, + "stoploss": { + "stoploss": -0.33 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-09 00:51:43.483560+00:00" +} \ No newline at end of file diff --git a/StrategyJD_2.py b/StrategyJD_2.py new file mode 100644 index 0000000..3e0b438 --- /dev/null +++ b/StrategyJD_2.py @@ -0,0 +1,340 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_2(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # buy_bollinger2 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # buy_bollinger3 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=1, space="buy") + # buy_decalage2 = IntParameter(1, 24, default=1, space="buy") + # buy_decalage3 = IntParameter(1, 24, default=1, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + # def custom_sell(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() + # + # # Above 20% profit, sell when rsi < 80 + # if current_profit > 0.2: + # if last_candle['rsi'] < 80: + # return 'rsi_below_80' + # + # # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + # informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = ta.SMA(informative, timeperiod=3) + # informative['sma5'] = ta.SMA(informative, timeperiod=5) + # informative['sma10'] = ta.SMA(informative, timeperiod=10) + # # informative['adx'] = ta.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)), + (dataframe['msma10_3'] > 0.998), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma1_' + str(decalage)) + break + + # for decalage2 in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + # conditions = [ + # (dataframe['bb_width'].shift(decalage2) >= self.buy_bollinger2.value), + # # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['close'].shift(decalage2) < dataframe['sma10'].shift(decalage2)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['rsi_1h'] < self.buy_rsi_min.value), + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) + # ) + # , + # ['buy', 'buy_tag']] = (1, 'buy_msma2_' + str(decalage2)) + # break + # + # for decalage3 in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + # conditions = [ + # (dataframe['bb_width'].shift(decalage3) >= self.buy_bollinger3.value), + # # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['close'].shift(decalage3) < dataframe['sma10'].shift(decalage3)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['rsi_1h'] > self.buy_rsi_max.value), + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) + # ) + # , + # ['buy', 'buy_tag']] = (1, 'buy_msma3_' + str(decalage2)) + # break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_3.json b/StrategyJD_3.json new file mode 100644 index 0000000..c5e3a76 --- /dev/null +++ b/StrategyJD_3.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyJD_3", + "params": { + "roi": { + "0": 0.225, + "191": 0.126, + "423": 0.078, + "673": 0 + }, + "stoploss": { + "stoploss": -0.33 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_decalage": 10, + "buy_rsi_max": 83, + "buy_rsi_min": 9 + }, + "sell": {}, + "protection": { + "n_percent": 2, + "percent_sell": -0.06 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-09 19:00:21.704495+00:00" +} \ No newline at end of file diff --git a/StrategyJD_3.py b/StrategyJD_3.py new file mode 100644 index 0000000..283fa95 --- /dev/null +++ b/StrategyJD_3.py @@ -0,0 +1,336 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_3(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=1, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * 1.01 + + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + # informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = ta.SMA(informative, timeperiod=3) + # informative['sma5'] = ta.SMA(informative, timeperiod=5) + # informative['sma10'] = ta.SMA(informative, timeperiod=10) + # # informative['adx'] = ta.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)), + (dataframe['msma10_3'] > 0.998), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma1_' + str(decalage)) + break + + # for decalage2 in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + # conditions = [ + # (dataframe['bb_width'].shift(decalage2) >= self.buy_bollinger2.value), + # # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['close'].shift(decalage2) < dataframe['sma10'].shift(decalage2)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['rsi_1h'] < self.buy_rsi_min.value), + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) + # ) + # , + # ['buy', 'buy_tag']] = (1, 'buy_msma2_' + str(decalage2)) + # break + # + # for decalage3 in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + # conditions = [ + # (dataframe['bb_width'].shift(decalage3) >= self.buy_bollinger3.value), + # # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['close'].shift(decalage3) < dataframe['sma10'].shift(decalage3)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['rsi_1h'] > self.buy_rsi_max.value), + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[ + # ( + # (reduce(lambda x, y: x & y, conditions)) + # ) + # , + # ['buy', 'buy_tag']] = (1, 'buy_msma3_' + str(decalage2)) + # break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_4.json b/StrategyJD_4.json new file mode 100644 index 0000000..58e150a --- /dev/null +++ b/StrategyJD_4.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyJD_4", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.04, + "buy_decalage": 4 + }, + "sell": {}, + "protection": { + "n_percent": 7, + "percent_sell": -0.08 + }, + "roi": { + "0": 0.627, + "151": 0.182, + "397": 0.041, + "657": 0 + }, + "stoploss": { + "stoploss": -0.033 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-11 21:11:06.341495+00:00" +} \ No newline at end of file diff --git a/StrategyJD_4.py b/StrategyJD_4.py new file mode 100644 index 0000000..33b900e --- /dev/null +++ b/StrategyJD_4.py @@ -0,0 +1,349 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_4(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + + # bollinger_rsi = {} + # for n in range(0, 11): + # bollinger_rsi[n] = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + + bollinger_rsi_01 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_02 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_03 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_04 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_05 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_06 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_07 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_08 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_09 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_10 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + bollinger_rsi_11 = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="protection") + + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=1, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + n_percent = IntParameter(1, 12, default=1, space="sell") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="sell") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + # informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = ta.SMA(informative, timeperiod=3) + # informative['sma5'] = ta.SMA(informative, timeperiod=5) + # informative['sma10'] = ta.SMA(informative, timeperiod=10) + # # informative['adx'] = ta.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for r_rsi_1h in range(0, 11): + value = 0 + if r_rsi_1h == 0: + value = self.bollinger_rsi_01.value + if r_rsi_1h == 1: + value = self.bollinger_rsi_02.value + if r_rsi_1h == 2: + value = self.bollinger_rsi_03.value + if r_rsi_1h == 3: + value = self.bollinger_rsi_04.value + if r_rsi_1h == 4: + value = self.bollinger_rsi_05.value + if r_rsi_1h == 5: + value = self.bollinger_rsi_06.value + if r_rsi_1h == 6: + value = self.bollinger_rsi_07.value + if r_rsi_1h == 7: + value = self.bollinger_rsi_08.value + if r_rsi_1h == 8: + value = self.bollinger_rsi_09.value + if r_rsi_1h == 9: + value = self.bollinger_rsi_10.value + if r_rsi_1h == 10: + value = self.bollinger_rsi_11.value + # if r_rsi_1h == 11: + # value = self.bollinger_rsi_02.value + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['r_rsi_1h'] == r_rsi_1h), + (dataframe['bb_width'].shift(decalage) >= value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)), + (dataframe['msma10_3'] > 0.998), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value) + # (dataframe['percent1'] > 0) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ), + ['buy', 'buy_tag']] = (1, 'buy_msma1_' + str(decalage)+ '_' + str(value)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_5.json b/StrategyJD_5.json new file mode 100644 index 0000000..d88a307 --- /dev/null +++ b/StrategyJD_5.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyJD_5", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 11, + "buy_min_max_n": 0.17, + "buy_rsi_max": 74, + "buy_rsi_min": 6 + }, + "sell": {}, + "protection": { + "n_percent": 6, + "percent_sell": -0.06 + }, + "roi": { + "0": 0.209, + "200": 0.158, + "453": 0.103, + "581": 0 + }, + "stoploss": { + "stoploss": -0.243 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-12 11:07:47.704622+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5.py b/StrategyJD_5.py new file mode 100644 index 0000000..8c25088 --- /dev/null +++ b/StrategyJD_5.py @@ -0,0 +1,303 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * 1.002 + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + # informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = ta.SMA(informative, timeperiod=3) + # informative['sma5'] = ta.SMA(informative, timeperiod=5) + # informative['sma10'] = ta.SMA(informative, timeperiod=10) + # # informative['adx'] = ta.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + # (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['msma10_3'] > 0.999) + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma1_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_5_2.json b/StrategyJD_5_2.json new file mode 100644 index 0000000..06be52e --- /dev/null +++ b/StrategyJD_5_2.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyJD_5_2", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 4, + "buy_min_max_n": 0.04, + "buy_rsi_max": 58, + "buy_rsi_min": 5 + }, + "sell": {}, + "protection": { + "n_percent": 5, + "percent_sell": -0.16 + }, + "roi": { + "0": 0.252, + "145": 0.21200000000000002, + "370": 0.096, + "831": 0 + }, + "stoploss": { + "stoploss": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-12 14:40:04.336207+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_2.py b/StrategyJD_5_2.py new file mode 100644 index 0000000..7ec902a --- /dev/null +++ b/StrategyJD_5_2.py @@ -0,0 +1,303 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_2(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * 1.002 + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = ta.MAX(informative['close'], timeperiod=3) + # informative["min3"] = ta.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = ta.SMA(informative, timeperiod=3) + # informative['sma5'] = ta.SMA(informative, timeperiod=5) + # informative['sma10'] = ta.SMA(informative, timeperiod=10) + # # informative['adx'] = ta.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + # (dataframe['bb_width'].shift(decalage) >= self.buy_bollinger.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n.value), + # (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)), + # (dataframe['msma10_3'] > 0.998), + # (dataframe['msma10_3'] > 0.999) + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[ + ( + (reduce(lambda x, y: x & y, conditions)) + ) + , + ['buy', 'buy_tag']] = (1, 'buy_msma1_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_5_3.json b/StrategyJD_5_3.json new file mode 100644 index 0000000..b839edf --- /dev/null +++ b/StrategyJD_5_3.json @@ -0,0 +1,44 @@ +{ + "strategy_name": "StrategyJD_5_3", + "params": { + "roi": { + "0": 0.402, + "191": 0.23, + "435": 0.078, + "711": 0 + }, + "stoploss": { + "stoploss": -0.243 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 1, + "buy_decalage2": 10, + "buy_decalage3": 22, + "buy_decalage4": 5, + "buy_min_max_n": 0.0, + "buy_min_max_n2": 0.17, + "buy_min_max_n3": 0.17, + "buy_min_max_n4": 0.09, + "buy_rsi_max": 67, + "buy_rsi_max2": 70, + "buy_rsi_min": 10, + "buy_rsi_min2": 18, + "buy_rsi_min_1d": 5, + "buy_rsi_min_1d2": 42, + "buy_rsi_min_1d3": 52 + }, + "sell": {}, + "protection": { + "n_percent": 6, + "percent_sell": -0.06 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-13 18:46:52.767429+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_3.py b/StrategyJD_5_3.py new file mode 100644 index 0000000..3402ab0 --- /dev/null +++ b/StrategyJD_5_3.py @@ -0,0 +1,346 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_3(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_decalage2 = IntParameter(1, 24, default=5, space="buy") + buy_decalage3 = IntParameter(1, 24, default=5, space="buy") + buy_decalage4 = IntParameter(1, 24, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n4 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + + buy_rsi_min_1d = IntParameter(0, 25, default=5, space="buy") + buy_rsi_min_1d2 = IntParameter(25, 50, default=15, space="buy") + buy_rsi_min_1d3 = IntParameter(50, 75, default=50, space="buy") + buy_rsi_min_1d4 = IntParameter(75, 100, default=75, space="buy") + + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + buy_rsi_min2 = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max2 = IntParameter(50, 100, default=60, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + # Between 2% and 10%, sell if EMA-long above EMA-short + # if 0.02 < current_profit < 0.1: + # if last_candle['ema100'] > last_candle['ema10']: + # return 'ema_long_below_80' + # + # # Sell any positions at a loss if they are held for more than one day. + # if current_profit < -0.20 and (current_time - trade.open_date_utc).days >= 3: + # return 'unclog' + + # def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + # proposed_stake: float, min_stake: float, max_stake: float, + # **kwargs) -> float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if dataframe['open'] < dataframe['sma100'] * 0.98: + # # if self.config['stake_amount'] == 'unlimited': + # # # Use entire available wallet during favorable conditions when in compounding mode. + # # return max_stake + # # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + # + # # Use default stake amount. + # return proposed_stake + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * 1.002 + dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['mema10_3'] = dataframe['ema10'] / dataframe['ema10'].shift(1) + # dataframe['mema10_5'] = dataframe['ema10'].rolling(5).mean() + + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['msma10_3'] = dataframe['sma10'] / dataframe['sma10'].shift(1) + + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + ################### INFORMATIVE 1d + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi'].div(10).round()) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # if (self.buy_min_max_n.value > self.buy_min_max_n2.value) | (self.buy_min_max_n2.value > self.buy_min_max_n3.value) | (self.buy_min_max_n3.value > self.buy_min_max_n4.value): + # return dataframe + + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < self.buy_rsi_min_1d.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d2.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d2.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d3.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage4.value - 2, self.buy_decalage4.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d3.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d4.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max200'] >= self.buy_min_max_n4.value), + (dataframe['rsi_1h'] > self.buy_rsi_min2.value), + (dataframe['rsi_1h'] < self.buy_rsi_max2.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyJD_5_4.json b/StrategyJD_5_4.json new file mode 100644 index 0000000..c979c96 --- /dev/null +++ b/StrategyJD_5_4.json @@ -0,0 +1,59 @@ +{ + "strategy_name": "StrategyJD_5_4", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.011, + "trailing_stop_positive_offset": 0.111, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_decalage": 5, + "buy_decalage2": 7, + "buy_decalage3": 17, + "buy_decalage4": 20, + "buy_min_max_n": 0.12, + "buy_min_max_n2": 0.14, + "buy_min_max_n3": 0.16, + "buy_min_max_n4": 0.0, + "buy_rsi_max": 51, + "buy_rsi_min": 3, + "buy_rsi_min_1d": 18, + "buy_rsi_min_1d2": 25, + "buy_rsi_min_1d3": 56, + "buy_rsi_min_1d4": 90, + "min_n": 11, + "min_p": 1.0, + "min_percent": 1.008, + "min_percent2": 1.006, + "min_percent3": 1.012, + "min_percent4": 1.018 + }, + "sell": { + "max_percent": 0.048, + "max_percent2": 0.018, + "max_percent3": 0.039, + "max_percent4": 0.003, + "max_profit": 0.0, + "max_profit2": 0.09, + "max_profit3": 0.07, + "max_profit4": 0.07, + "sell_h_RSI": 83, + "sell_h_RSI2": 72, + "sell_h_RSI2_percent": 0.017, + "sell_h_RSI3": 74 + }, + "protection": { + "n_percent": 1, + "percent_sell": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-15 14:27:47.977295+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_4.jsonNostoploss b/StrategyJD_5_4.jsonNostoploss new file mode 100644 index 0000000..b88fabc --- /dev/null +++ b/StrategyJD_5_4.jsonNostoploss @@ -0,0 +1,41 @@ +{ + "strategy_name": "StrategyJD_5_4", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 1, + "buy_decalage2": 9, + "buy_decalage3": 2, + "buy_decalage4": 8, + "buy_min_max_n": 0.14, + "buy_min_max_n2": 0.17, + "buy_min_max_n3": 0.07, + "buy_min_max_n4": 0.16, + "buy_rsi_max": 53, + "buy_rsi_min": 23, + "buy_rsi_min_1d": 24, + "buy_rsi_min_1d2": 50, + "buy_rsi_min_1d3": 57, + "min_n": 13, + "min_p": 1.006 + }, + "sell": {}, + "protection": { + "n_percent": 1, + "percent_sell": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-13 21:03:59.051913+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_4.py b/StrategyJD_5_4.py new file mode 100644 index 0000000..d7c7959 --- /dev/null +++ b/StrategyJD_5_4.py @@ -0,0 +1,326 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_4(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_decalage2 = IntParameter(1, 24, default=5, space="buy") + buy_decalage3 = IntParameter(1, 24, default=5, space="buy") + buy_decalage4 = IntParameter(1, 24, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n4 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + + buy_rsi_min_1d = IntParameter(0, 25, default=5, space="buy") + buy_rsi_min_1d2 = IntParameter(25, 50, default=15, space="buy") + buy_rsi_min_1d3 = IntParameter(50, 75, default=50, space="buy") + buy_rsi_min_1d4 = IntParameter(75, 100, default=75, space="buy") + + min_percent = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent2 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent3 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent4 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent4 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit4 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + # sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + # + # sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + # buy_rsi_min2 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max2 = IntParameter(50, 100, default=60, space="buy") + + min_n = IntParameter(0, 24, default=15, space="buy") + min_p = DecimalParameter(1, 1.01, decimals=3, default=1.002, space="buy") + + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + n_percent2 = IntParameter(1, 12, default=1, space="protection") + percent_sell2 = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + n_percent3 = IntParameter(1, 12, default=1, space="protection") + percent_sell3 = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + n_percent4 = IntParameter(1, 12, default=1, space="protection") + percent_sell4 = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d.value): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + else: + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d2.value): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + if last_candle['percent' + str(self.n_percent2.value)] < self.percent_sell2.value: + return 'sell_lost_percent' + str(self.n_percent2.value) + else: + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d3.value): + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + if last_candle['percent' + str(self.n_percent3.value)] < self.percent_sell3.value: + return 'sell_lost_percent' + str(self.n_percent3.value) + else: + max_percent = self.max_percent4.value + max_profit = self.max_profit4.value + if last_candle['percent' + str(self.n_percent4.value)] < self.percent_sell4.value: + return 'sell_lost_percent' + str(self.n_percent4.value) + + if (current_profit > max_profit) & ( + (last_candle['percent1'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_h_RSI2_percent.value): + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): + return 'h_over_rsi_max' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * self.min_percent.value + dataframe['min200_002'] = dataframe['min200'] * self.min_percent2.value + dataframe['min200_003'] = dataframe['min200'] * self.min_percent3.value + dataframe['min200_004'] = dataframe['min200'] * self.min_percent4.value + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['min_n_p'] = dataframe['min_n'] * self.min_p.value + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + for n in range(1, 5): + informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < self.buy_rsi_min_1d.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d2.value), + (dataframe['close'].shift(decalage) < dataframe['min200_002'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d2.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d3.value), + (dataframe['close'].shift(decalage) < dataframe['min200_003'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + break + + for decalage in range(self.buy_decalage4.value - 2, self.buy_decalage4.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d3.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d4.value), + (dataframe['close'].shift(decalage) < dataframe['min200_004'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n4.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyJD_5_5.json b/StrategyJD_5_5.json new file mode 100644 index 0000000..086c023 --- /dev/null +++ b/StrategyJD_5_5.json @@ -0,0 +1,59 @@ +{ + "strategy_name": "StrategyJD_5_5", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 5, + "buy_decalage2": 7, + "buy_decalage3": 17, + "buy_decalage4": 20, + "buy_min_max_n": 0.12, + "buy_min_max_n2": 0.14, + "buy_min_max_n3": 0.16, + "buy_min_max_n4": 0.0, + "buy_rsi_max": 51, + "buy_rsi_min": 3, + "buy_rsi_min_1d": 18, + "buy_rsi_min_1d2": 25, + "buy_rsi_min_1d3": 56, + "buy_rsi_min_1d4": 90, + "min_n": 11, + "min_p": 1.0, + "min_percent": 1.008, + "min_percent2": 1.006, + "min_percent3": 1.012, + "min_percent4": 1.018 + }, + "sell": { + "max_percent": 0.004, + "max_percent2": 0.006, + "max_percent3": 0.0, + "max_percent4": 0.038, + "max_profit": 0.06, + "max_profit2": 0.05, + "max_profit3": 0.0, + "max_profit4": 0.01, + "sell_h_RSI": 79, + "sell_h_RSI2": 90, + "sell_h_RSI2_percent": 0.005, + "sell_h_RSI3": 84 + }, + "protection": { + "n_percent": 1, + "percent_sell": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-15 16:27:30.204760+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_5.py b/StrategyJD_5_5.py new file mode 100644 index 0000000..6e4585c --- /dev/null +++ b/StrategyJD_5_5.py @@ -0,0 +1,314 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_5(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_decalage2 = IntParameter(1, 24, default=5, space="buy") + buy_decalage3 = IntParameter(1, 24, default=5, space="buy") + buy_decalage4 = IntParameter(1, 24, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n4 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + + buy_rsi_min_1d = IntParameter(0, 25, default=5, space="buy") + buy_rsi_min_1d2 = IntParameter(25, 50, default=15, space="buy") + buy_rsi_min_1d3 = IntParameter(50, 75, default=50, space="buy") + buy_rsi_min_1d4 = IntParameter(75, 100, default=75, space="buy") + + min_percent = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent2 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent3 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent4 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent4 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit4 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + # sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + # + # sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + # buy_rsi_min2 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max2 = IntParameter(50, 100, default=60, space="buy") + + min_n = IntParameter(0, 24, default=15, space="buy") + min_p = DecimalParameter(1, 1.01, decimals=3, default=1.002, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d.value): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + else: + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d2.value): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + else: + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d3.value): + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + else: + max_percent = self.max_percent4.value + max_profit = self.max_profit4.value + + if (current_profit > max_profit) & ( + (last_candle['percent1'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_h_RSI2_percent.value): + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): + return 'h_over_rsi_max' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * self.min_percent.value + dataframe['min200_002'] = dataframe['min200'] * self.min_percent2.value + dataframe['min200_003'] = dataframe['min200'] * self.min_percent3.value + dataframe['min200_004'] = dataframe['min200'] * self.min_percent4.value + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['min_n_p'] = dataframe['min_n'] * self.min_p.value + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + # for n in range(1, 5): + # informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < self.buy_rsi_min_1d.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d2.value), + (dataframe['close'].shift(decalage) < dataframe['min200_002'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d2.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d3.value), + (dataframe['close'].shift(decalage) < dataframe['min200_003'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + break + + for decalage in range(self.buy_decalage4.value - 2, self.buy_decalage4.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d3.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d4.value), + (dataframe['close'].shift(decalage) < dataframe['min200_004'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n4.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyJD_5_6.json b/StrategyJD_5_6.json new file mode 100644 index 0000000..1439264 --- /dev/null +++ b/StrategyJD_5_6.json @@ -0,0 +1,53 @@ +{ + "strategy_name": "StrategyJD_5_6", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 5, + "buy_decalage2": 7, + "buy_decalage3": 17, + "buy_min_max_n": 0.12, + "buy_min_max_n2": 0.14, + "buy_min_max_n3": 0.16, + "buy_rsi_max": 55, + "buy_rsi_min": 3, + "buy_rsi_min_1d": 18, + "buy_rsi_min_1d2": 25, + "buy_rsi_min_1d3": 56, + "min_n": 11, + "min_p": 1.0, + "min_percent": 1.008, + "min_percent2": 1.010, + "min_percent3": 1.012 + }, + "sell": { + "max_percent": 0.045, + "max_percent2": 0.01, + "max_percent3": 0.004, + "max_profit": 0.09, + "max_profit2": 0.09, + "max_profit3": 0.0, + "sell_RSI": 73, + "sell_RSI2": 84, + "sell_RSI2_percent": 0.003, + "sell_RSI3": 73 + }, + "protection": { + "n_percent": 1, + "percent_sell": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-16 17:52:27.040594+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_6.py b/StrategyJD_5_6.py new file mode 100644 index 0000000..f6ca370 --- /dev/null +++ b/StrategyJD_5_6.py @@ -0,0 +1,331 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_6(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(1, 24, default=5, space="buy") + buy_decalage2 = IntParameter(1, 24, default=5, space="buy") + buy_decalage3 = IntParameter(1, 24, default=5, space="buy") + # buy_decalage4 = IntParameter(1, 24, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + # buy_min_max_n4 = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + + buy_rsi_min_1d = IntParameter(0, 20, default=5, space="buy") + buy_rsi_min_1d2 = IntParameter(20, 35, default=30, space="buy") + buy_rsi_min_1d3 = IntParameter(35, 50, default=45, space="buy") + # buy_rsi_min_1d4 = IntParameter(50, 70, default=60, space="buy") + + min_percent = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent2 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + min_percent3 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + # min_percent4 = DecimalParameter(1, 1.02, decimals=3, default=1.002, space='buy') + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + # max_percent4 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + # max_profit4 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + # sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + # + # sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_RSI = IntParameter(70, 98, default=88, space='sell') + sell_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + # buy_rsi_min2 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max2 = IntParameter(50, 100, default=60, space="buy") + # buy_rsi_min3 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max3 = IntParameter(50, 100, default=60, space="buy") + # buy_rsi_min4 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max4 = IntParameter(50, 100, default=60, space="buy") + + min_n = IntParameter(0, 24, default=15, space="buy") + min_p = DecimalParameter(1, 1.01, decimals=3, default=1.002, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + "main_plot": { + "bb_lowerband": { + "color": "white" + }, + "bb_upperband": { + "color": "white" + }, + "min200": { + "color": "yellow" + }, + "min200_001": { + "color": "yellow" + }, + "max200": { + "color": "yellow", + "type": "line" + } + }, + "subplots": { + "BB": { + "bb_width": { + "color": "white" + } + }, + "Percent": { + "min_max200": { + "color": "#c046bb", + "type": "line" + } + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + + number = 0 + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d.value): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + number = 1 + else: + if (last_candle['rsi_1h'] < self.buy_rsi_min_1d2.value): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + number = 2 + else: + # if (last_candle['rsi_1h'] < self.buy_rsi_min_1d3.value): + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + number = 3 + # else: + # max_percent = self.max_percent4.value + # max_profit = self.max_profit4.value + # number = 4 + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent_' + str(number) + + if (current_profit > max_profit) & ( + (last_candle['percent1'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick_' + str(number) + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): + return 'h_over_rsi_' + str(number) + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_RSI2_percent.value): + return 'h_over_rsi_2_' + str(number) + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): + return 'h_over_rsi_max_' + str(number) + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * self.min_percent.value + dataframe['min200_002'] = dataframe['min200'] * self.min_percent2.value + dataframe['min200_003'] = dataframe['min200'] * self.min_percent3.value + # dataframe['min200_004'] = dataframe['min200'] * self.min_percent4.value + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['min_n_p'] = dataframe['min_n'] * self.min_p.value + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + # for n in range(1, 5): + # informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < self.buy_rsi_min_1d.value), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d2.value), + (dataframe['close'].shift(decalage) < dataframe['min200_002'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= self.buy_rsi_min_1d2.value), + (dataframe['rsi_1h'] < self.buy_rsi_min_1d3.value), + (dataframe['close'].shift(decalage) < dataframe['min200_003'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > self.buy_rsi_min.value), + (dataframe['rsi_1h'] < self.buy_rsi_max.value), + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + break + + # for decalage in range(self.buy_decalage4.value - 2, self.buy_decalage4.value): + # conditions = [ + # (dataframe['rsi_1h'] >= self.buy_rsi_min_1d3.value), + # (dataframe['rsi_1h'] < self.buy_rsi_min_1d4.value), + # (dataframe['close'].shift(decalage) < dataframe['min200_004'].shift(decalage)), + # (dataframe['min_max_n'] >= self.buy_min_max_n4.value), + # (dataframe['rsi_1h'] > self.buy_rsi_min.value), + # (dataframe['rsi_1h'] < self.buy_rsi_max.value), + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + # ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage)) + # break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyJD_5_7.json b/StrategyJD_5_7.json new file mode 100644 index 0000000..d20c875 --- /dev/null +++ b/StrategyJD_5_7.json @@ -0,0 +1,49 @@ +{ + "strategy_name": "StrategyJD_5_7", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage": 3, + "buy_decalage2": 8, + "buy_decalage3": 19, + "buy_min_max_n": 0.12, + "buy_min_max_n2": 0.11, + "buy_min_max_n3": 0.14, + "buy_mrsi3": -0.1, + "min_n": 11, + "min_p": 1.006, + "min_percent": 1.014, + "min_percent2": 1.006, + "min_percent3": 1.006 + }, + "sell": { + "max_percent": 0.004, + "max_percent2": 0.006, + "max_percent3": 0.0, + "max_profit": 0.06, + "max_profit2": 0.05, + "max_profit3": 0.0, + "sell_h_RSI": 79, + "sell_h_RSI2": 90, + "sell_h_RSI2_percent": 0.005, + "sell_h_RSI3": 84 + }, + "protection": { + "n_percent": 1, + "percent_sell": -0.08 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-17 13:07:40.696464+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_7.py b/StrategyJD_5_7.py new file mode 100644 index 0000000..cb6960d --- /dev/null +++ b/StrategyJD_5_7.py @@ -0,0 +1,295 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_7(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(3, 10, default=5, space="buy") + buy_decalage2 = IntParameter(5, 15, default=5, space="buy") + buy_decalage3 = IntParameter(10, 20, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0.06, 0.14, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0.06, 0.14, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0.06, 0.14, decimals=2, default=0.05, space='buy') + + # buy_rsi_min_1d = IntParameter(0, 25, default=5, space="buy") + # buy_rsi_min_1d2 = IntParameter(25, 50, default=15, space="buy") + # buy_rsi_min_1d3 = IntParameter(50, 75, default=50, space="buy") + + min_percent = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + min_percent2 = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + min_percent3 = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + # sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + # + # sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + + # buy_rsi_min = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max = IntParameter(50, 100, default=60, space="buy") + buy_mrsi3 = DecimalParameter(-0.1, 0.1, decimals=2, default=0, space="buy") + + # buy_rsi_min2 = IntParameter(0, 50, default=25, space="buy") + # buy_rsi_max2 = IntParameter(50, 100, default=60, space="buy") + + min_n = IntParameter(0, 24, default=15, space="buy") + min_p = DecimalParameter(1, 1.01, decimals=3, default=1.002, space="buy") + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + if (last_candle['rsi_1h'] < 18): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + else: + if (last_candle['rsi_1h'] < 25): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + else: + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + + if (current_profit > max_profit) & ( + (last_candle['percent1'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_h_RSI2_percent.value): + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): + return 'h_over_rsi_max' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_001'] = dataframe['min200'] * self.min_percent.value + dataframe['min200_002'] = dataframe['min200'] * self.min_percent2.value + dataframe['min200_003'] = dataframe['min200'] * self.min_percent3.value + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=self.min_n.value * 12) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['min_n_p'] = dataframe['min_n'] * self.min_p.value + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative["mrsi3"] = informative["rsi"].pct_change(3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + # for n in range(1, 5): + # informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < 18), + (dataframe['close'].shift(decalage) < dataframe['min200_001'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= 18), + (dataframe['rsi_1h'] < 25), + (dataframe['close'].shift(decalage) < dataframe['min200_002'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= 25), + (dataframe['rsi_1h'] < 56), + (dataframe['close'].shift(decalage) < dataframe['min200_003'].shift(decalage)), + (dataframe['min_max_n'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyJD_5_8.json b/StrategyJD_5_8.json new file mode 100644 index 0000000..587ff1e --- /dev/null +++ b/StrategyJD_5_8.json @@ -0,0 +1,45 @@ +{ + "strategy_name": "StrategyJD_5_8", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_min_max_n": 0.27, + "buy_min_max_n2": 0.08, + "buy_min_max_n3": 0.06, + "buy_mrsi3": -0.07, + "min_n": 3, + "min_percent": 1.01, + "min_percent2": 1.004, + "min_percent3": 1.008 + }, + "sell": { + "max_percent": 0.032, + "max_percent2": 0.019, + "max_percent3": 0.024, + "max_profit": 0.1, + "max_profit2": 0.07, + "max_profit3": 0.04, + "sell_h_RSI": 91, + "sell_h_RSI2": 96, + "sell_h_RSI2_percent": 0.019, + "sell_h_RSI3": 92 + }, + "protection": { + "n_percent": 5, + "percent_sell": -0.13 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-17 18:41:11.974567+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_8.py b/StrategyJD_5_8.py new file mode 100644 index 0000000..0cffffa --- /dev/null +++ b/StrategyJD_5_8.py @@ -0,0 +1,290 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_8(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + #buy_msma_10 = DecimalParameter(0.997, 1.020, decimals=3, default=0.998, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + buy_decalage = IntParameter(3, 10, default=5, space="buy") + buy_decalage2 = IntParameter(5, 15, default=5, space="buy") + buy_decalage3 = IntParameter(10, 20, default=5, space="buy") + + buy_min_max_n = DecimalParameter(0.06, 0.30, decimals=2, default=0.05, space='buy') + buy_min_max_n2 = DecimalParameter(0.06, 0.14, decimals=2, default=0.05, space='buy') + buy_min_max_n3 = DecimalParameter(0.06, 0.14, decimals=2, default=0.05, space='buy') + + # buy_rsi_min_1d = IntParameter(0, 25, default=5, space="buy") + # buy_rsi_min_1d2 = IntParameter(25, 50, default=15, space="buy") + # buy_rsi_min_1d3 = IntParameter(50, 75, default=50, space="buy") + + min_percent = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + min_percent2 = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + min_percent3 = DecimalParameter(1.005, 1.015, decimals=3, default=1.002, space='buy') + + buy_mrsi3 = DecimalParameter(-0.1, 0.1, decimals=2, default=0, space="buy") + + min_n = IntParameter(0, 24, default=15, space="buy") + # min_p = DecimalParameter(1, 1.01, decimals=3, default=1.002, space="buy") + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + # sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + # sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + # + # sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.2, -0.01, decimals=2, default=-0.08, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'min200': {'color': 'yellow'}, + 'min200_001': {'color': 'yellow'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + + if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + return 'sell_lost_percent' + str(self.n_percent.value) + + if (last_candle['rsi_1h'] < 18): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + else: + if (last_candle['rsi_1h'] < 25): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + else: + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + + if (current_profit > max_profit) & ( + (last_candle['percent1'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_h_RSI2_percent.value): + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): + return 'h_over_rsi_max' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs = [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=self.min_n.value * 24) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=self.min_n.value * 24) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + # dataframe['min_n_p'] = dataframe['min_n'] * self.min_p.value + dataframe['minn_1'] = dataframe['min_n'] * self.min_percent.value + dataframe['minn_2'] = dataframe['min_n'] * self.min_percent2.value + dataframe['minn_3'] = dataframe['min_n'] * self.min_percent3.value + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + # 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["bb_percent"] = ( + # (dataframe["close"] - dataframe["bb_lowerband"]) / + # (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + # ) + # dataframe["bb_width"] = ( + # (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + # ) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + informative["mrsi3"] = informative["rsi"].pct_change(3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + # for n in range(1, 5): + # informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + for decalage in range(self.buy_decalage.value - 2, self.buy_decalage.value): + conditions = [ + (dataframe['rsi_1h'] < 18), + (dataframe['close'] < dataframe['minn_1']), + (dataframe['min_max_n'] >= self.buy_min_max_n.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + break + + for decalage in range(self.buy_decalage2.value - 2, self.buy_decalage2.value): + conditions = [ + (dataframe['rsi_1h'] >= 18), + (dataframe['rsi_1h'] < 25), + (dataframe['close'] < dataframe['minn_2']), + (dataframe['min_max_n'] >= self.buy_min_max_n2.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + break + + for decalage in range(self.buy_decalage3.value - 2, self.buy_decalage3.value): + conditions = [ + (dataframe['rsi_1h'] >= 25), + (dataframe['rsi_1h'] < 56), + (dataframe['close'] < dataframe['minn_3']), + (dataframe['min_max_n'] >= self.buy_min_max_n3.value), + (dataframe['rsi_1h'] > 0), + (dataframe['rsi_1h'] < 51), + (dataframe['mrsi3_1h'] > self.buy_mrsi3.value) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + break + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyJD_5_9.json b/StrategyJD_5_9.json new file mode 100644 index 0000000..e84b659 --- /dev/null +++ b/StrategyJD_5_9.json @@ -0,0 +1,43 @@ +{ + "strategy_name": "StrategyJD_5_9", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_decalage4": 1, + "min_percent4": 7, + "rapport_min_n": 14 + }, + "sell": { + "max_percent": 0.041, + "max_percent2": 0.032, + "max_percent3": 0.013, + "max_profit": 0.09, + "max_profit2": 0.1, + "max_profit3": 0.06, + "sell_h_RSI": 82, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 72 + }, + "protection": { + "hours_sell": 16, + "n_percent": 7, + "percent_sell": -0.07, + "percent_sell_sma5_1d": -0.07, + "percent_sell_stop": -0.7 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-21 09:43:15.542215+00:00" +} \ No newline at end of file diff --git a/StrategyJD_5_9.py b/StrategyJD_5_9.py new file mode 100644 index 0000000..2573060 --- /dev/null +++ b/StrategyJD_5_9.py @@ -0,0 +1,301 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from freqtrade.strategy.strategy_helper import merge_informative_pair + + +# This class is a sample. Feel free to customize it. +class StrategyJD_5_9(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + buy_decalage4 = IntParameter(1, 10, default=5, space="buy") + + min_percent4 = IntParameter(1, 20, default=10, space='buy') + # buy_mrsi3 = DecimalParameter(-0.1, 0.1, decimals=2, default=0, space="buy") + + rapport_min_n = IntParameter(1, 20, default=10, space='buy') + + min_n = 16 + + max_percent = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent2 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + max_percent3 = DecimalParameter(0, 0.05, decimals=3, default=0.005, space='sell') + + max_profit = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit2 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + max_profit3 = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + n_percent = IntParameter(1, 12, default=1, space="protection") + percent_sell = DecimalParameter(-0.1, -0.01, decimals=2, default=-0.08, space="protection") + percent_sell_stop = DecimalParameter(-0.8, -0.1, decimals=1, default=-0.8, space="protection") + percent_sell_sma5_1d = DecimalParameter(-0.1, 0, decimals=2, default=0, space="protection") + hours_sell = IntParameter(5, 48, default=24, space="protection") + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + lim_0 = 10 + lim_1 = 18 + lim_2 = 25 + lim_3 = 51 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + "main_plot": { + "bb_lowerband": { + "color": "white" + }, + "bb_upperband": { + "color": "white" + }, + "min200": { + "color": "yellow" + }, + "max200": { + "color": "yellow" + }, + "min_n": { + "color": "#600e82" + }, + "max_n": { + "color": "#600e82" + }, + "min5_1d": { + "color": "#6aa123", + }, + "max5_1d": { + "color": "red" + }, + "max3_1d": { + "color": "blue" + }, + "close_1d": { + "color": "green" + }, + "close_1M": { + "color": "cyan" + }, + "min_n_1d": { + "color": "pink" + }, + "max_n_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "black" + } + }, + "subplots": { + "Rsi": { + "rsi_1h": { + "color": "blue" + }, + "rsi_1d": { + "color": "red" + }, + "rsi": { + "color": "green" + }, + }, + # "Percent": { + # "min_max200": { + # "color": "#c046bb" + # } + # } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-2].squeeze() + + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + hours = minutes / 60 + + if (last_candle['sma5_diff_1d'] < self.percent_sell_sma5_1d.value) & (current_profit < -0.05): + return 'sell_sma5_1d' + + if (current_profit < self.percent_sell_stop.value) & (hours >= self.hours_sell.value) & (last_candle['percent_1h'] <= -0.05): + return 'sell_stop' + + # if (last_candle['percent1'] < -0.005) & (last_candle['max200'] == previous_previous_last_candle['max200']) & (minutes > 30): + # return 'sell_percent1' + # + # if (last_candle['percent3'] < -0.005) & (last_candle['percent1'] < 0) \ + # & (previous_last_candle['percent1'] < 0) & (previous_previous_last_candle['percent1'] < 0) & (minutes > 30): + # return 'sell_percent3' + + #if last_candle['percent' + str(self.n_percent.value)] < self.percent_sell.value: + # return 'sell_lost_percent_' + str(self.n_percent.value) + + if (last_candle['rsi_1h'] < self.lim_1): + max_percent = self.max_percent.value + max_profit = self.max_profit.value + else: + if (last_candle['rsi_1h'] < self.lim_2): + max_percent = self.max_percent2.value + max_profit = self.max_profit2.value + else: + max_percent = self.max_percent3.value + max_profit = self.max_profit3.value + + if (current_profit > max_profit) & ( + #(last_candle['percent1'] < -max_percent) | + (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + #& (last_candle['close'] > last_candle['max3_1d']): + return 'h_percent_quick' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent1'] < - self.sell_h_RSI2_percent.value): + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max3_1d']): + return 'h_over_rsi_max' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '1M') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # print(self.min_percent.value, self.min_percent2.value, self.min_percent3.value, + # self.buy_decalage.value, self.buy_decalage2.value, self.buy_decalage3.value, + # ) + dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200) + period = int(self.min_n * 24) + dataframe['min_n'] = ta.MIN(dataframe['close'], timeperiod=period) + dataframe['max_n'] = ta.MAX(dataframe['close'], timeperiod=period) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + for n in range(1, 25): + dataframe["percent" + str(n)] = dataframe['close'].pct_change(n) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = ta.RSI(informative) + informative["rsi3"] = ta.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].pct_change(3) + informative['r_rsi'] = (informative['rsi3'].div(10).round()) + informative['percent'] = informative['close'].pct_change(1) + # for n in range(1, 5): + # informative["percent" + str(n)] = informative['close'].pct_change(n) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + ################### INFORMATIVE 1d + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = ta.RSI(informative, period=5) + informative['min5'] = ta.MIN(informative['close'], timeperiod=5) + informative['max3'] = ta.MAX(informative['close'], timeperiod=3) + informative['max5'] = ta.MAX(informative['close'], timeperiod=5) + informative['sma5'] = ta.SMA(informative['close'], timeperiod=5) + informative['min_n'] = ta.MIN(informative['close'], timeperiod=14) + informative['max_n'] = ta.MAX(informative['close'], timeperiod=14) + informative['min_max_n'] = (informative['max_n'] - informative['min_n']) / informative['min_n'] + informative['percent'] = informative['close'].pct_change(1) + informative['sma5_diff'] = informative['sma5'] - informative['sma5'].shift(1) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ################### INFORMATIVE 1M + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1M") + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1M", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + (dataframe['close'] <= dataframe['min_n_1d']), # * (1 + (dataframe['min_max_n_1d'] / self.min_percent3.value))), + (dataframe['close'] <= dataframe['min_n'] * (1 + (dataframe['min_max_n'] / self.min_percent4.value))), + (dataframe['min_n'].shift(self.buy_decalage4.value) == dataframe['min_n']), + (dataframe['min_n_1d'] / dataframe['min_n'] > 1 + self.rapport_min_n.value / 100) + ] + # GUARDS AND TRENDS + if conditions: + dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + ['buy', 'buy_tag']] = (1, 'buy_4') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/StrategyPierrick.py b/StrategyPierrick.py new file mode 100644 index 0000000..a2b1cc9 --- /dev/null +++ b/StrategyPierrick.py @@ -0,0 +1,139 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.065) + #& (dataframe['rsi'] < 45) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick2.jsonOLD b/StrategyPierrick2.jsonOLD new file mode 100644 index 0000000..cf5277d --- /dev/null +++ b/StrategyPierrick2.jsonOLD @@ -0,0 +1,28 @@ +{ + "strategy_name": "StrategyPierrick2", + "params": { + "buy": { + "buy_bollinger": 0.04, + "buy_sma_percent": 0.93 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.237, + "19": 0.065, + "65": 0.026, + "185": 0 + }, + "stoploss": { + "stoploss": -0.327 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.116, + "trailing_stop_positive_offset": 0.15000000000000002, + "trailing_only_offset_is_reached": true + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-18 21:32:34.141258+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick2.py b/StrategyPierrick2.py new file mode 100644 index 0000000..4883184 --- /dev/null +++ b/StrategyPierrick2.py @@ -0,0 +1,272 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from functools import reduce + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick2(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + "0": 1, + # "600": 0.12, + # "1200": 0.08, + # "2400": 0.06, + # "3600": 0.04, + # "7289": 0 + } + + # Stoploss: + stoploss = -1 + # Buy hypers + timeframe = '4h' + + # Trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.15 + trailing_stop_positive_offset = 0.20 + trailing_only_offset_is_reached = True + + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + #print("last_candle", last_candle) + #print("previous_last_candle", previous_last_candle) + + count = 0 + for coin, balance in self.wallets.get_all_balances().items(): + count = count + 1 + # print(coin, " ", balance) + # print("count=", count) + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + # ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + if (current_profit > 0) \ + & (previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < - (current_profit / 4))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma10_desc' + + # if (current_profit > 0) \ + # & (last_candle['percent'] < -0.02): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_percent_loss' + + #if (current_profit > 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # & (last_candle['percent'] < 0): + # print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + # if 0.05 < current_profit < 1: + # if ( + # (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + # (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # # ) | ( + # # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + # ): + # # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + # + # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'profit_3h_sma10_desc' + # + # if (0 < current_profit < 0.1) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + # print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'profit_5h_sma20_desc' + + # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6): + # self.lock_pair(pair, until=current_time + timedelta(hours=10)) + # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate, + # "count=", count, "max=", self.config['max_open_trades']) + # return 'stop_short_loss' + + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + # Bollinger Bands - Weighted (EMA based instead of SMA) + weighted_bollinger = qtpylib.weighted_bollinger_bands( + qtpylib.typical_price(dataframe), window=20, stds=2 + ) + dataframe["wbb_upperband"] = weighted_bollinger["upper"] + dataframe["wbb_lowerband"] = weighted_bollinger["lower"] + dataframe["wbb_middleband"] = weighted_bollinger["mid"] + dataframe["wbb_percent"] = ( + (dataframe["close"] - dataframe["wbb_lowerband"]) / + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) + ) + dataframe["wbb_width"] = ( + (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"] + ) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & (dataframe['bb_width'] >= 0.065) + #& (dataframe['rsi'] < 45) + & (dataframe['volume'] * dataframe['close'] / 1000 >= 100) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick22.py b/StrategyPierrick22.py new file mode 100644 index 0000000..7d99d71 --- /dev/null +++ b/StrategyPierrick22.py @@ -0,0 +1,156 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick22(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ((dataframe['bb_width'] >= 0.08) & (dataframe['close'].shift(20) / dataframe['close'] >= 1.03)) + ) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick23.py b/StrategyPierrick23.py new file mode 100644 index 0000000..571e8fe --- /dev/null +++ b/StrategyPierrick23.py @@ -0,0 +1,159 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick23(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.10, + "60": 0.05, + "120": 0.03, + "180": 0.015, + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ((dataframe['bb_width'] >= 0.08) & (dataframe['close'].shift(20) / dataframe['close'] >= 1.03)) + ) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick3.py b/StrategyPierrick3.py new file mode 100644 index 0000000..26d5612 --- /dev/null +++ b/StrategyPierrick3.py @@ -0,0 +1,180 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick3(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.02, True, False) + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + # & (dataframe['close'] <= dataframe['sma500']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick31.py b/StrategyPierrick31.py new file mode 100644 index 0000000..ef2b345 --- /dev/null +++ b/StrategyPierrick31.py @@ -0,0 +1,196 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick31(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Baisse depuis 20 cycles + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + condition = np.where(value >= 1.02, True, False) + + # Baisse dans les 20% inférieur + horizon = int(12 * 60 / 5) + pmin = dataframe['min'].shift(horizon) + pmax = dataframe['max'].shift(horizon) + pmoy = (dataframe['max'] - dataframe['min']) / (pmax - pmin) + # print("pmoy=", pmoy) + for k, v in pmoy.iteritems(): + # print(k, v) + value = v + condition2 = np.where(value <= 0.8, True, False) + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition & condition2 + ) + ) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick32.py b/StrategyPierrick32.py new file mode 100644 index 0000000..c29e382 --- /dev/null +++ b/StrategyPierrick32.py @@ -0,0 +1,177 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick32(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # Baisse depuis 20 cycles + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + condition = np.where(value >= 1.02, True, False) + + # Baisse dans les 20% inférieur + horizon = int(4 * 60 / 5) + pmin = dataframe['min'].shift(horizon) + pmax = dataframe['max'].shift(horizon) + pmoy = (dataframe['max'] - dataframe['min']) / (pmax - pmin) + # print("pmoy=", pmoy) + for k, v in pmoy.iteritems(): + # print(k, v) + value = v + condition2 = np.where(value <= 0.8, True, False) + + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition & condition2 + ) + ) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick4.py b/StrategyPierrick4.py new file mode 100644 index 0000000..ecea40b --- /dev/null +++ b/StrategyPierrick4.py @@ -0,0 +1,166 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4(IStrategy): + + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + + # ROI table: + minimal_roi = { + #"0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 #0.015 + trailing_only_offset_is_reached = True + + #max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # MACD + #macd = ta.MACD(dataframe) + #dataframe['macd'] = macd['macd'] + #dataframe['macdsignal'] = macd['macdsignal'] + #dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + #dataframe['rsi'] = ta.RSI(dataframe) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.04, True, False) + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe + diff --git a/StrategyPierrick41.py b/StrategyPierrick41.py new file mode 100644 index 0000000..18eb352 --- /dev/null +++ b/StrategyPierrick41.py @@ -0,0 +1,207 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.04, True, False) + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + (dataframe['volume'] > 0) & + ( + (dataframe['bb_width'] >= 0.095) | + ((dataframe['bb_width'] >= 0.04) & condition) + & (dataframe['close'] <= dataframe['sma200_95']) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick411.json b/StrategyPierrick411.json new file mode 100644 index 0000000..0f14c34 --- /dev/null +++ b/StrategyPierrick411.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.99, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} diff --git a/StrategyPierrick411.jsonMaxDrawDownHyperOptLoss b/StrategyPierrick411.jsonMaxDrawDownHyperOptLoss new file mode 100644 index 0000000..1c90cb0 --- /dev/null +++ b/StrategyPierrick411.jsonMaxDrawDownHyperOptLoss @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": true, + "buy_bollinger_3": 0.07, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": true, + "buy_volume": 13.5, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 18:56:50.185120+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonOLD2 b/StrategyPierrick411.jsonOLD2 new file mode 100644 index 0000000..1487f67 --- /dev/null +++ b/StrategyPierrick411.jsonOLD2 @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.0, + "buy_bollinger_2_enabled": false, + "buy_bollinger_3": 0.08, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.97, + "buy_sma_percent_enabled": false, + "buy_volume": 42.0, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-04 21:37:54.391956+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonOld b/StrategyPierrick411.jsonOld new file mode 100644 index 0000000..bf080e1 --- /dev/null +++ b/StrategyPierrick411.jsonOld @@ -0,0 +1,27 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.08, + "buy_bollinger_2": 0.04, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-04 16:23:57.580987+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonOnlyProfitHyperOptLoss b/StrategyPierrick411.jsonOnlyProfitHyperOptLoss new file mode 100644 index 0000000..d8517e5 --- /dev/null +++ b/StrategyPierrick411.jsonOnlyProfitHyperOptLoss @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.04, + "buy_bollinger_2": 0.0, + "buy_bollinger_2_enabled": true, + "buy_bollinger_3": 0.04, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 1.05, + "buy_sma_percent_enabled": true, + "buy_volume": 37.9, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 17:11:37.461801+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonSharpeHyperOptLoss b/StrategyPierrick411.jsonSharpeHyperOptLoss new file mode 100644 index 0000000..58fa0d1 --- /dev/null +++ b/StrategyPierrick411.jsonSharpeHyperOptLoss @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.11, + "buy_bollinger_2": 0.0, + "buy_bollinger_2_enabled": false, + "buy_bollinger_3": 0.07, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 40.3, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 17:31:26.224609+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonSharpeHyperOptLossDaily b/StrategyPierrick411.jsonSharpeHyperOptLossDaily new file mode 100644 index 0000000..8676d45 --- /dev/null +++ b/StrategyPierrick411.jsonSharpeHyperOptLossDaily @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.06, + "buy_bollinger_2": 0.02, + "buy_bollinger_2_enabled": false, + "buy_bollinger_3": 0.06, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 1.02, + "buy_sma_percent_enabled": false, + "buy_volume": 14.7, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 17:53:59.162189+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonShortTradeDurHyperOptLoss b/StrategyPierrick411.jsonShortTradeDurHyperOptLoss new file mode 100644 index 0000000..170c744 --- /dev/null +++ b/StrategyPierrick411.jsonShortTradeDurHyperOptLoss @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.12, + "buy_bollinger_2": 0.07, + "buy_bollinger_2_enabled": false, + "buy_bollinger_3": 0.02, + "buy_bollinger_3_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": true, + "buy_volume": 10.5, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 16:38:40.768689+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonSortinoHyperOptLoss b/StrategyPierrick411.jsonSortinoHyperOptLoss new file mode 100644 index 0000000..95ffdbf --- /dev/null +++ b/StrategyPierrick411.jsonSortinoHyperOptLoss @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.07, + "buy_bollinger_2": 0.02, + "buy_bollinger_2_enabled": true, + "buy_bollinger_3": 0.07, + "buy_bollinger_3_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.95, + "buy_sma_percent_enabled": false, + "buy_volume": 7.1, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 18:12:23.363449+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.jsonSortinoHyperOptLossDaily b/StrategyPierrick411.jsonSortinoHyperOptLossDaily new file mode 100644 index 0000000..57faef8 --- /dev/null +++ b/StrategyPierrick411.jsonSortinoHyperOptLossDaily @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick411", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.04, + "buy_bollinger_2_enabled": true, + "buy_bollinger_3": 0.06, + "buy_bollinger_3_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.96, + "buy_sma_percent_enabled": true, + "buy_volume": 11.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 18:27:26.631033+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411.py b/StrategyPierrick411.py new file mode 100644 index 0000000..38fbc0d --- /dev/null +++ b/StrategyPierrick411.py @@ -0,0 +1,228 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick411(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = (100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling(5).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['close'] < dataframe['sma100'] * self.buy_sma_percent.value) + ] + # GUARDS AND TRENDS + + 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: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4111.json b/StrategyPierrick4111.json new file mode 100644 index 0000000..b60d84a --- /dev/null +++ b/StrategyPierrick4111.json @@ -0,0 +1,42 @@ +{ + "strategy_name": "StrategyPierrick4111", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_baisse_bollinger": 0.07, + "buy_baisse_bollinger_2": 0.05, + "buy_baisse_bollinger_2_enabled": true, + "buy_baisse_bollinger_enabled": true, + "buy_baisse_sma_percent": 0.99, + "buy_baisse_sma_percent_enabled": true, + "buy_baisse_volume": 44.7, + "buy_baisse_volume_enabled": true, + "buy_hausse_bollinger": 0.05, + "buy_hausse_bollinger_2": 0.0, + "buy_hausse_bollinger_2_enabled": false, + "buy_hausse_bollinger_enabled": false, + "buy_hausse_sma_percent": 1.05, + "buy_hausse_sma_percent_enabled": true, + "buy_hausse_volume": 12.7, + "buy_hausse_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.092, + "29": 0.059, + "63": 0.036, + "182": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 20:42:50.719031+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4111.jsonOLD2 b/StrategyPierrick4111.jsonOLD2 new file mode 100644 index 0000000..a523722 --- /dev/null +++ b/StrategyPierrick4111.jsonOLD2 @@ -0,0 +1,39 @@ +{ + "strategy_name": "StrategyPierrick4111", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_baisse_bollinger": 0.08, + "buy_baisse_bollinger_2": 0.03, + "buy_baisse_bollinger_2_enabled": true, + "buy_baisse_bollinger_enabled": true, + "buy_baisse_sma_percent": 1.0, + "buy_baisse_sma_percent_enabled": true, + "buy_baisse_volume": 32.0, + "buy_baisse_volume_enabled": false, + "buy_hausse_bollinger": 0.12, + "buy_hausse_bollinger_2": 0.01, + "buy_hausse_bollinger_2_enabled": true, + "buy_hausse_bollinger_enabled": true, + "buy_hausse_sma_percent": 1.01, + "buy_hausse_sma_percent_enabled": true, + "buy_hausse_volume": 12.7, + "buy_hausse_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-06 21:26:35.306929+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4111.py b/StrategyPierrick4111.py new file mode 100644 index 0000000..1056094 --- /dev/null +++ b/StrategyPierrick4111.py @@ -0,0 +1,327 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4111(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_hausse_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_hausse_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième h_condition bollinger avec h_condition sma200 + buy_hausse_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_hausse_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_hausse_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_hausse_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_hausse_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_hausse_volume_enabled = BooleanParameter(default=True, space="buy") + + # valeur de bbwidth pour démarrer + buy_baisse_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_baisse_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième h_condition bollinger avec h_condition sma200 + buy_baisse_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_baisse_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_baisse_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_baisse_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_baisse_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_baisse_volume_enabled = BooleanParameter(default=True, space="buy") + + # buy_hausse_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_hausse_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_hausse_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_hausse_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = 0.03 + trailing_stop = True + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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_hausse_signal = False + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + h_condition1 = np.where(value >= 1.04, True, False) + + h_conditions = [] + # GUARDS AND TRENDS + if self.buy_hausse_bollinger_enabled.value: + h_conditions.append(dataframe['bb_width'] >= self.buy_hausse_bollinger.value) + + h_conditions2 = [] + if self.buy_hausse_bollinger_2_enabled.value: + h_conditions2.append(dataframe['bb_width'] >= self.buy_hausse_bollinger_2.value) + + h_conditions_volume = [] + h_condition_volume = True + if self.buy_hausse_volume_enabled.value: + h_conditions_volume.append(dataframe['volume'] >= self.buy_hausse_volume.value * 1000) + if h_conditions_volume: + h_condition_volume = np.where(h_conditions_volume, True, False) + + h_condition2 = False + if h_conditions2: + h_condition2 = reduce(lambda x, y: x & y, h_conditions2) & h_condition1 + + h_condition_sma = False + h_conditions_sma = [] + if self.buy_hausse_sma_percent_enabled.value: + #h_conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_hausse_sma_percent.value) + h_conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_hausse_sma_percent.value) + if h_conditions_sma: + h_condition_sma = reduce(lambda x, y: x & y, h_conditions_sma) + + b_condition1 = np.where(value >= 1.04, True, False) + + b_conditions = [] + # GUARDS AND TRENDS + if self.buy_baisse_bollinger_enabled.value: + b_conditions.append(dataframe['bb_width'] >= self.buy_baisse_bollinger.value) + + b_conditions2 = [] + if self.buy_baisse_bollinger_2_enabled.value: + b_conditions2.append(dataframe['bb_width'] >= self.buy_baisse_bollinger_2.value) + + b_conditions_volume = [] + b_condition_volume = True + if self.buy_baisse_volume_enabled.value: + b_conditions_volume.append(dataframe['volume'] >= self.buy_baisse_volume.value * 1000) + if b_conditions_volume: + b_condition_volume = np.where(b_conditions_volume, True, False) + + b_condition2 = False + if b_conditions2: + b_condition2 = reduce(lambda x, y: x & y, b_conditions2) & b_condition1 + + b_condition_sma = False + b_conditions_sma = [] + if self.buy_baisse_sma_percent_enabled.value: + #b_conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_baisse_sma_percent.value) + b_conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_baisse_sma_percent.value) + if b_conditions_sma: + b_condition_sma = reduce(lambda x, y: x & y, b_conditions_sma) + + p = dataframe['sma500'].shift(60) - dataframe['sma500'] + for k, v in p.iteritems(): + # print(k, v) + value = v + hausse = np.where(value < 0, True, False) + + if hausse: + if h_conditions: + dataframe.loc[ + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + h_condition_volume & + ( + ( + reduce(lambda x, y: x & y, h_conditions) | + (h_condition2 & h_condition_sma) + ) + ) + ), + 'buy'] = 1 + else: + if b_conditions: + dataframe.loc[ + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + b_condition_volume & + ( + ( + reduce(lambda x, y: x & y, b_conditions) | + (b_condition2 & b_condition_sma) + ) + ) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(1) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.015) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4112.json b/StrategyPierrick4112.json new file mode 100644 index 0000000..22c9839 --- /dev/null +++ b/StrategyPierrick4112.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4112", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} diff --git a/StrategyPierrick4112.py b/StrategyPierrick4112.py new file mode 100644 index 0000000..5220803 --- /dev/null +++ b/StrategyPierrick4112.py @@ -0,0 +1,288 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4112(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = IntParameter(0, 50, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + buy_candel_percent = DecimalParameter(1.02, 1.10, decimals=2, default=1.04, space="buy") + + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "Pct": { + 'percent': {'color': 'white'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe[ + 'sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + if conditions: + dataframe.loc[ + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + condition_volume & + (reduce(lambda x, y: x & y, conditions)) #| (condition2 & condition_sma)) + ) | ( + # condition2 & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.04) & + # (dataframe['bb_width'] < 0.2) + (dataframe['sma100'].shift(4) < dataframe['sma100'] * 1.01) & + (dataframe['sma100'].shift(4) > dataframe['sma100'] * 0.99) + # ) | ( + # ( + # (dataframe['percent'] + # + dataframe['percent'].shift(1) + # + dataframe['percent'].shift(2) + # + dataframe['percent'].shift(3) + # + dataframe['percent'].shift(4) > 1.04) & + # (dataframe['close'] > dataframe['bb_upperband']) + # ) & ( + # dataframe['close'] > dataframe['open'].shift(2) * 1.04 + # ) + ) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4113.json b/StrategyPierrick4113.json new file mode 100644 index 0000000..49e6da8 --- /dev/null +++ b/StrategyPierrick4113.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4113", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.04, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4113.py b/StrategyPierrick4113.py new file mode 100644 index 0000000..e4b52a3 --- /dev/null +++ b/StrategyPierrick4113.py @@ -0,0 +1,281 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4113(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe[ + 'sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + if conditions: + dataframe.loc[ + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + condition_volume & + (reduce(lambda x, y: x & y, conditions) | (condition2 & condition_sma)) + ) | ( + (dataframe['close'] > dataframe['bb_upperband']) & + ( + (dataframe['close'] > dataframe['open'] * 1.04) | + (((dataframe['close'] - dataframe['bb_upperband']) / dataframe['bb_upperband']) >= 0.025) + ) & + # (dataframe['bb_width'] < 0.2) + (dataframe['sma100'].shift(4) < dataframe['sma100'] * 1.01) & + (dataframe['sma100'].shift(4) > dataframe['sma100'] * 0.99) + # (dataframe['close'] < dataframe['open'] * 1.06) + # ) | ( + # ( + # (dataframe['close'] > dataframe['bb_upperband']) & + # (dataframe['close'].shift(1) > dataframe['bb_upperband'].shift(1)) & + # (dataframe['close'].shift(2) > dataframe['bb_upperband'].shift(2)) + # # (dataframe['bb_width'] < 0.12) + # ) & ( + # dataframe['close'] > dataframe['open'].shift(2) * 1.04 + # ) + ) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4114.json b/StrategyPierrick4114.json new file mode 100644 index 0000000..1e50e07 --- /dev/null +++ b/StrategyPierrick4114.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4114", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.07, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 1.05, + "buy_sma_percent_enabled": false, + "buy_volume": 14.0, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + "stoploss": { + "stoploss": -0.31 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-11 13:07:34.278116+00:00" +} diff --git a/StrategyPierrick4114.py b/StrategyPierrick4114.py new file mode 100644 index 0000000..7467372 --- /dev/null +++ b/StrategyPierrick4114.py @@ -0,0 +1,264 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4114(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.065, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] / dataframe['bb_width'].shift(5) >= 1.5) #self.buy_bollinger_2.value) + # conditions2.append(dataframe['close'] <= dataframe['sma100'] * 0.99) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + if conditions: + dataframe.loc[ + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + condition_volume & + (reduce(lambda x, y: x & y, conditions) | (condition2 & condition_sma)) + # ) | ( + ) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4115.json b/StrategyPierrick4115.json new file mode 100644 index 0000000..5e59e5a --- /dev/null +++ b/StrategyPierrick4115.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4115", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.05, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-11 20:27:50.805367+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4115.jsonOLD b/StrategyPierrick4115.jsonOLD new file mode 100644 index 0000000..daf984f --- /dev/null +++ b/StrategyPierrick4115.jsonOLD @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4115", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.05, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} diff --git a/StrategyPierrick4115.py b/StrategyPierrick4115.py new file mode 100644 index 0000000..a0e34ee --- /dev/null +++ b/StrategyPierrick4115.py @@ -0,0 +1,282 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4115(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = IntParameter(0, 50, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + buy_candel_percent = DecimalParameter(1.02, 1.10, decimals=2, default=1.04, space="buy") + buy_candel_sma_percent = DecimalParameter(0.97, 1.04, decimals=2, default=0.99, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "Pct": { + 'percent': {'color': 'white'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # condition1 = np.where(value >= 1.04, True, False) + + conditions_bb_1 = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions_bb_1.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + condition1 = False + if conditions_bb_1: + condition1 = reduce(lambda x, y: x & y, conditions_bb_1) + + conditions2_bb_2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2_bb_2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + # conditions2_bb_2.append(dataframe['bb_width'] >= 0.03) + + # conditions2_bb_2.append(dataframe['bb_width'] <= 0.1) + condition2 = False + if conditions2_bb_2: + condition2 = reduce(lambda x, y: x & y, conditions2_bb_2) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe[ + 'sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + condition_volume & + condition1 + ) | ( + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.04) & + (dataframe['close'] < dataframe['open'].shift(4) * 1.06) & + (dataframe['close'].shift(4) < dataframe['sma100'].shift(4) * 1.04) + ) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ) | ( + (dataframe['close'] * 1.04 < dataframe['open']) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4116.json b/StrategyPierrick4116.json new file mode 100644 index 0000000..55f79ab --- /dev/null +++ b/StrategyPierrick4116.json @@ -0,0 +1,33 @@ +{ + "strategy_name": "StrategyPierrick4116", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.06, + "buy_bollinger_2": 0.06, + "buy_candel_bb1": 2, + "buy_candel_percent": 1.05, + "buy_volume": 33 + }, + "sell": { + "sell_candel_percent": 1.1 + }, + "protection": {}, + "roi": { + "0": 0.256, + "29": 0.076, + "52": 0.031, + "76": 0 + }, + "stoploss": { + "stoploss": -0.057 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-14 23:21:44.054656+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4116.jsonOLD b/StrategyPierrick4116.jsonOLD new file mode 100644 index 0000000..ce4da9f --- /dev/null +++ b/StrategyPierrick4116.jsonOLD @@ -0,0 +1,36 @@ +{ + "strategy_name": "StrategyPierrick4116", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.03, + "buy_bollinger_2": 0.02, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_candel_percent": 1.02, + "buy_candel_sma_percent": 1.03, + "buy_sma_percent": 1.02, + "buy_sma_percent_enabled": true, + "buy_volume": 24, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.122, + "34": 0.092, + "62": 0.032, + "85": 0 + }, + "stoploss": { + "stoploss": -0.306 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-14 19:35:12.845988+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4116.py b/StrategyPierrick4116.py new file mode 100644 index 0000000..c6806c6 --- /dev/null +++ b/StrategyPierrick4116.py @@ -0,0 +1,255 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4116(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_candel_bb1 = IntParameter(0, 10, default=5, space="buy") + + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # volume à atteindre + buy_volume = IntParameter(0, 50, default=0, space="buy") + + buy_candel_percent = DecimalParameter(1.00, 1.10, decimals=2, default=1.04, space="buy") + sell_candel_percent = DecimalParameter(1.0, 1.10, decimals=2, default=1.04, space="sell") + + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma10': {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + # 'rsi': {'color': '#c58893'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "Pct": { + 'percent': {'color': 'white'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # condition1 = np.where(value >= 1.04, True, False) + + conditions_bb_1 = [] + # GUARDS AND TRENDS + conditions_bb_1.append(dataframe['bb_width'] >= self.buy_bollinger.value) + conditions_bb_1.append(dataframe['volume'] >= self.buy_volume.value * 1000) + conditions_bb_1.append(dataframe['close'] < dataframe['bb_lowerband']) + conditions_bb_1.append( + (dataframe['open'] - dataframe['bb_lowerband']) / (dataframe['bb_lowerband'] - dataframe['close']) > self.buy_candel_bb1.value + ) + conditions_bb_1.append(dataframe['percent'] > -0.03) + condition1 = reduce(lambda x, y: x & y, conditions_bb_1) + + conditions2_bb_2 = [] + conditions2_bb_2.append(dataframe['bb_width'] <= self.buy_bollinger_2.value) + conditions2_bb_2.append(dataframe['close'] > dataframe['open'] * self.buy_candel_percent.value) + conditions2_bb_2.append(dataframe['close'] < dataframe['bb_upperband']) + condition2 = reduce(lambda x, y: x & y, conditions2_bb_2) + + dataframe.loc[ + ( + condition1 + ) | ( + False & + (dataframe['bb_width'] > 0.065) & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'].shift(1) < dataframe['bb_upperband'].shift(1)) & + (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) > dataframe['open'].shift(2)) & + (dataframe['close'].shift(3) > dataframe['open'].shift(3)) & + (dataframe['close'] < dataframe['open'].shift(3) * 1.03) & + (dataframe['sma10'].shift(1) < dataframe['sma10'] * 1.01) & + (dataframe['sma10'].shift(1) > dataframe['sma10'] * 0.99) + ) | ( + condition2 & + # (dataframe['close'] > dataframe['open'] * 1.04) & + # (dataframe['close'] <= dataframe['open'] * 1.05) & + (dataframe['close'] > dataframe['sma10']) & + (dataframe['open'] < dataframe['sma10']) & + (dataframe['sma100'].shift(4) < dataframe['sma100'] * 1.01) & + (dataframe['sma100'].shift(4) > dataframe['sma100'] * 0.99) + # (dataframe['sma100'].shift(1) <= dataframe['sma100']) + ) | ( + False & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.02) & + (dataframe['close'] > dataframe['sma100']) & + (dataframe['open'] < dataframe['sma100']) & + (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) > dataframe['open'].shift(2)) + ) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions_sell = [] + # GUARDS AND TRENDS + conditions_sell.append(dataframe['close'] < dataframe['open']) + conditions_sell.append(dataframe['close'] < dataframe['bb_lowerband']) + conditions_sell.append(dataframe['close'].shift(1) < dataframe['open'].shift(1)) + conditions_sell.append(dataframe['close'].shift(2) < dataframe['open'].shift(2)) + conditions_sell.append(dataframe['close'] * self.sell_candel_percent.value < dataframe['open'].shift(2)) + condition1 = reduce(lambda x, y: x & y, conditions_sell) + + dataframe.loc[condition1, 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4117.json b/StrategyPierrick4117.json new file mode 100644 index 0000000..075a25b --- /dev/null +++ b/StrategyPierrick4117.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4117", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.05, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": false + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.02, + "30": 0.015, + "60": 0.01, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-11 20:27:50.805367+00:00" +} diff --git a/StrategyPierrick4117.py b/StrategyPierrick4117.py new file mode 100644 index 0000000..136af21 --- /dev/null +++ b/StrategyPierrick4117.py @@ -0,0 +1,319 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +from functools import reduce +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from numpy.lib import math + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4117(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = IntParameter(0, 50, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + buy_candel_percent = DecimalParameter(1.02, 1.10, decimals=2, default=1.04, space="buy") + buy_candel_sma_percent = DecimalParameter(0.97, 1.04, decimals=2, default=0.99, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma10': {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + # 'rsi': {'color': '#c58893'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "Pct": { + 'percent': {'color': 'white'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + #dataframe['min'] = ta.MIN(dataframe) + #dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # condition1 = np.where(value >= 1.04, True, False) + + conditions_bb_1 = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + dataframe['bb_width'] < 0.12, + dataframe['volume'] >= self.buy_volume.value * 1000, + dataframe['close'] < dataframe['bb_lowerband']] + condition1 = reduce(lambda x, y: x & y, conditions_bb_1) + + dataframe.loc[ + ( + False & condition1 + ) | ( + False & + (dataframe['bb_width'] > 0.065) & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'].shift(1) < dataframe['bb_upperband'].shift(1)) & + (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) > dataframe['open'].shift(2)) & + (dataframe['close'].shift(3) > dataframe['open'].shift(3)) & + (dataframe['close'] < dataframe['open'].shift(3) * 1.03) & + (dataframe['sma10'].shift(1) < dataframe['sma10'] * 1.01) & + (dataframe['sma10'].shift(1) > dataframe['sma10'] * 0.99) + ) | ( + # (dataframe['bb_width'] >= 0.065) & + # (dataframe['bb_width'] <= 0.15) & + (dataframe['sma10'] < dataframe['sma100']) & + (dataframe['sma10'] / dataframe['sma50'] > 1.008) & + (dataframe['sma10'] / dataframe['sma50'] < 1.012) & + (dataframe['close'] > dataframe['bb_upperband']) + # (dataframe['close'] < dataframe['open'] * 1.025) & + # (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) > dataframe['open'].shift(2)) & + # (dataframe['close'].shift(1) <= dataframe['bb_upperband'].shift(1)) & + # (dataframe['close'].shift(2) <= dataframe['bb_upperband'].shift(2)) & + # (dataframe['sma100'].shift(4) < dataframe['sma100'] * 1.01) & + # (dataframe['sma100'].shift(4) > dataframe['sma100'] * 0.99) & + # (dataframe['sma100'].shift(1) <= dataframe['sma100']) + ) | ( + False & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.02) & + (dataframe['close'] > dataframe['sma100']) & + (dataframe['open'] < dataframe['sma100']) & + (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) > dataframe['open'].shift(2)) + # ) | ( + # (dataframe['close'] > dataframe['bb_upperband']) & + # ((dataframe['percent'] + # + dataframe['percent'].shift(1) + # + dataframe['percent'].shift(2) + # + dataframe['percent'].shift(3)) > 0.015) & + # (dataframe['bb_width'] >= 0.03) & + # (dataframe['sma100'].shift(4) < dataframe['sma100'] * 1.01) & + # (dataframe['sma100'].shift(4) > dataframe['sma100'] * 0.99) + # ) | ( + # ( + # (dataframe['bb_width'] < 0.2) & + # # (dataframe['percent'] > 0.02) & + # ((dataframe['percent'] + # + dataframe['percent'].shift(1) + # + dataframe['percent'].shift(2) + # + dataframe['percent'].shift(3)) > 0.015) & + # (dataframe['close'] > dataframe['bb_upperband']) + # # dataframe['bb_width'] >= 0.04 + # ) + ) + , + 'buy'] = 1 + # else: + # if conditions2_bb_2: + # dataframe.loc[ + # ( + # (dataframe['close'] > dataframe['bb_upperband']) & + # reduce(lambda x, y: x & y, + # (dataframe['close'] > dataframe['open'] * self.buy_candel_percent.value)) & + # # (dataframe['bb_width'] < 0.2) + # reduce(lambda x, y: x & y, + # (dataframe['sma100'].shift(4) < dataframe[ + # 'sma100'] * self.buy_candel_sma_percent.value + 0.02)) & + # reduce(lambda x, y: x & y, + # (dataframe['sma100'].shift(4) > dataframe[ + # 'sma100'] * self.buy_candel_sma_percent.value)) + # ) + # , 'buy'] = 1 + # else: + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) + & ( + (dataframe['close'] < dataframe['bb_lowerband']) # & + # (dataframe['close'] < dataframe['sma10']) + ) + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + # 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ) | ( + (dataframe['close'] * 1.04 < dataframe['open']) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4118.json b/StrategyPierrick4118.json new file mode 100644 index 0000000..1693d91 --- /dev/null +++ b/StrategyPierrick4118.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyPierrick4118", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.119, + "buy_candel_percent": 0.001, + "buy_volume": 17 + }, + "sell": { + "sell_candel_percent": 1.1 + }, + "protection": {}, + "roi": { + "0": 0.146, + "31": 0.042, + "78": 0.021, + "186": 0 + }, + "stoploss": { + "stoploss": -0.337 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-16 19:58:16.082610+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4118.jsonOnlyProfitHyperOptLoss b/StrategyPierrick4118.jsonOnlyProfitHyperOptLoss new file mode 100644 index 0000000..1693d91 --- /dev/null +++ b/StrategyPierrick4118.jsonOnlyProfitHyperOptLoss @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyPierrick4118", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.119, + "buy_candel_percent": 0.001, + "buy_volume": 17 + }, + "sell": { + "sell_candel_percent": 1.1 + }, + "protection": {}, + "roi": { + "0": 0.146, + "31": 0.042, + "78": 0.021, + "186": 0 + }, + "stoploss": { + "stoploss": -0.337 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-16 19:58:16.082610+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4118.jsonStrategyPierrick4118.json b/StrategyPierrick4118.jsonStrategyPierrick4118.json new file mode 100644 index 0000000..5d7957a --- /dev/null +++ b/StrategyPierrick4118.jsonStrategyPierrick4118.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyPierrick4118", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.125, + "buy_candel_percent": 0.001, + "buy_volume": 38 + }, + "sell": { + "sell_candel_percent": 1.05 + }, + "protection": {}, + "roi": { + "0": 0.22000000000000003, + "35": 0.083, + "91": 0.017, + "133": 0 + }, + "stoploss": { + "stoploss": -0.321 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-16 19:41:29.563783+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4118.py b/StrategyPierrick4118.py new file mode 100644 index 0000000..d951711 --- /dev/null +++ b/StrategyPierrick4118.py @@ -0,0 +1,250 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4118(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.005, 0.125, decimals=3, default=0.03, space="buy") + + # volume à atteindre + buy_volume = IntParameter(0, 50, default=0, space="buy") + + buy_candel_percent = DecimalParameter(0.001, 0.01, decimals=3, default=0.006, space="buy") + sell_candel_percent = DecimalParameter(1.0, 1.10, decimals=2, default=1.04, space="sell") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'green'}, + 'max': {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + # 'rsi': {'color': '#c58893'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "Pct": { + 'percent': {'color': 'white'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions_bb_1 = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + dataframe['volume'] >= self.buy_volume.value * 1000, + dataframe['percent'].shift(3) >= self.buy_candel_percent.value + ] + condition1 = reduce(lambda x, y: x & y, conditions_bb_1) + # dataframe.loc[ + # ( + # condition1 & + # (dataframe['min'] == dataframe['min'].shift(1)) & + # (dataframe['min'].shift(1) == dataframe['min'].shift(2)) & + # # courant est positif + # (dataframe['open'].shift(2) < dataframe['close'].shift(2)) & + # # previous cut BB + # (dataframe['close'].shift(3) < dataframe['bb_lowerband'].shift(3)) & + # # min + # (dataframe['min'].shift(2) * 1.001 >= dataframe['open'].shift(2)) + # ), 'buy'] = 1 + dataframe.loc[ + ( + condition1 & + (dataframe['min'] == dataframe['min'].shift(1)) & + (dataframe['min'].shift(1) == dataframe['min'].shift(2)) & + (dataframe['min'].shift(2) == dataframe['min'].shift(3)) & + # courant est positif + (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & + # previous cut BB + (dataframe['close'].shift(4) < dataframe['bb_lowerband'].shift(4)) & + # min + (dataframe['min'].shift(3) * 1.001 >= dataframe['open'].shift(3)) + ), 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions_sell = [] + # GUARDS AND TRENDS + conditions_sell.append(dataframe['close'] < dataframe['open']) + conditions_sell.append(dataframe['close'] < dataframe['bb_lowerband']) + conditions_sell.append(dataframe['close'].shift(1) < dataframe['open'].shift(1)) + conditions_sell.append(dataframe['close'].shift(2) < dataframe['open'].shift(2)) + #conditions_sell.append(dataframe['close'] * self.sell_candel_percent.value < dataframe['open'].shift(2)) + conditions_sell.append((((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02)) + condition1 = reduce(lambda x, y: x & y, conditions_sell) + + # (qtpylib.crossed_above(dataframe['close'], dataframe['ema800'])) & + + dataframe.loc[condition1, 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4119.json b/StrategyPierrick4119.json new file mode 100644 index 0000000..5c2305e --- /dev/null +++ b/StrategyPierrick4119.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4119", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} diff --git a/StrategyPierrick4119.py b/StrategyPierrick4119.py new file mode 100644 index 0000000..9f254b4 --- /dev/null +++ b/StrategyPierrick4119.py @@ -0,0 +1,281 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4119(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'green'}, + 'max': {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + condition1 = reduce(lambda x, y: x & y, conditions) + + conditions_bb_1 = [ + dataframe['bb_width'] >= 0.119, # self.buy_bollinger.value, + dataframe['volume'] >= 17000, #self.buy_volume.value * 1000, + dataframe['percent'].shift(3) >= 0.001 #self.buy_candel_percent.value + ] + condition_bb = reduce(lambda x, y: x & y, conditions_bb_1) + + + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + condition_volume & + (condition1 | (condition2 & condition_sma)) + ) | ( + condition_bb & + (dataframe['min'] == dataframe['min'].shift(1)) & + (dataframe['min'].shift(1) == dataframe['min'].shift(2)) & + (dataframe['min'].shift(2) == dataframe['min'].shift(3)) & + # courant est positif + (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & + # previous cut BB + (dataframe['close'].shift(4) < dataframe['bb_lowerband'].shift(4)) & + # min + (dataframe['min'].shift(3) * 1.001 >= dataframe['open'].shift(3)) + ), 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick411_02.json b/StrategyPierrick411_02.json new file mode 100644 index 0000000..bfc7627 --- /dev/null +++ b/StrategyPierrick411_02.json @@ -0,0 +1,28 @@ +{ + "strategy_name": "StrategyPierrick411_02", + "params": { + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.01, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.08, + "buy_sma_percent": 1.05 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.11, + "13": 0.055, + "51": 0.034, + "141": 0 + }, + "stoploss": { + "stoploss": -0.329 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-21 18:22:30.332701+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick411_02.py b/StrategyPierrick411_02.py new file mode 100644 index 0000000..a7116d4 --- /dev/null +++ b/StrategyPierrick411_02.py @@ -0,0 +1,246 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick411_02(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma10': {'color': 'yellow'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + # def custom_sell(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() + # previous_last_candle = dataframe.iloc[-2].squeeze() + # # print(last_candle) + # if current_profit > 0.05: + # if previous_last_candle['sma50'] > last_candle['sma50']: + # return 'ema_long_below_80' + # else: + # if current_profit > 0.005: + # if previous_last_candle['sma20'] > last_candle['sma20'] and ( + # current_time - trade.open_date_utc).seconds >= 3200: + # return 'ema_long_below_80' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 5).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['close'] < dataframe['sma100'] * self.buy_sma_percent.value) + ] + # GUARDS AND TRENDS + + 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: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick411_03.py b/StrategyPierrick411_03.py new file mode 100644 index 0000000..9cc3cac --- /dev/null +++ b/StrategyPierrick411_03.py @@ -0,0 +1,228 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick411(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = (100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling(5).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['close'] < dataframe['sma100'] * self.buy_sma_percent.value) + ] + # GUARDS AND TRENDS + + 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: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick412.json b/StrategyPierrick412.json new file mode 100644 index 0000000..5bd8a62 --- /dev/null +++ b/StrategyPierrick412.json @@ -0,0 +1,38 @@ +{ + "strategy_name": "StrategyPierrick412", + "params": { + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.12, + "buy_bollinger_2": 0.04, + "buy_bollinger_2_enabled": true, + "buy_bollinger_enabled": true, + "buy_candel": 0.07, + "buy_candel_enabled": true, + "buy_cross": 1.0, + "buy_cross_enabled": true, + "buy_sma_percent": 1.05, + "buy_sma_percent_enabled": false, + "buy_volume": 11.6, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-06 19:04:44.234113+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick412.jsonOLD b/StrategyPierrick412.jsonOLD new file mode 100644 index 0000000..6d7a1cf --- /dev/null +++ b/StrategyPierrick412.jsonOLD @@ -0,0 +1,37 @@ +{ + "strategy_name": "StrategyPierrick412", + "params": { + "roi": { + "0": 0.5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.04, + "buy_bollinger_2": 0.06, + "buy_bollinger_2_enabled": false, + "buy_bollinger_3": 0.04, + "buy_bollinger_3_enabled": true, + "buy_bollinger_enabled": true, + "buy_candel": 0.06, + "buy_candel_enabled": true, + "buy_cross": 1.1, + "buy_cross_enabled": true, + "buy_sma_percent": 0.96, + "buy_sma_percent_enabled": true, + "buy_volume": 7.3, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-05 14:52:48.625435+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick412.py b/StrategyPierrick412.py new file mode 100644 index 0000000..2064a77 --- /dev/null +++ b/StrategyPierrick412.py @@ -0,0 +1,282 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick412(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + # Valeur maxi de la chandelle qui coupe la bande du bas + buy_candel = DecimalParameter(0, 0.10, decimals=2, default=0, space="buy") + buy_candel_enabled = BooleanParameter(default=True, space="buy") + + buy_cross = DecimalParameter(0.8, 1.2, decimals=1, default=1, space="buy") + buy_cross_enabled = BooleanParameter(default=True, space="buy") + + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + #conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + condition_candel = True + conditions_candel = [] + if self.buy_candel_enabled.value: + conditions_candel.append((dataframe['open'] - dataframe['close']) / dataframe['close'] <= self.buy_candel.value) + if conditions_candel: + condition_candel = reduce(lambda x, y: x & y, conditions_candel) + + condition_cross = True + conditions_cross = [] + if self.buy_cross_enabled.value: + conditions_cross.append(dataframe['close'] < dataframe['bb_lowerband'] * self.buy_cross.value) + if conditions_cross: + condition_cross = reduce(lambda x, y: x & y, conditions_cross) + + if conditions: + dataframe.loc[ + ( + condition_cross & + condition_candel & + condition_volume & + ( + ( + reduce(lambda x, y: x & y, conditions) | + (condition2 & condition_sma) + ) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(1) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.015) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4120.json b/StrategyPierrick4120.json new file mode 100644 index 0000000..2eb5854 --- /dev/null +++ b/StrategyPierrick4120.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4120", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.09, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-07 21:14:40.877512+00:00" +} diff --git a/StrategyPierrick4120.py b/StrategyPierrick4120.py new file mode 100644 index 0000000..7fef8c1 --- /dev/null +++ b/StrategyPierrick4120.py @@ -0,0 +1,281 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4120(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -0.1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'green'}, + 'max': {'color': 'yellow'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'rolling': {'color': 'white'}, + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = (100 * (dataframe["close"].shift(3) - dataframe["bb_lowerband"].shift(3)) / dataframe["bb_lowerband"].shift(3)).rolling(20).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=20) + + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # count = 0 + # for i in range(20): + # print("i=", i, " count=", count) + # c = [(dataframe['close'].shift(i) <= dataframe['bb_lowerband'].shift(i))] + # value = reduce(lambda x, y: x & y, c) + + # for k, v in value.iteritems(): + # print("i=", i, " count=", count, " v=", v) + # if v: + # count = count + 1 + # for i in range(20): + # print("i=", i) + # a = 1 if bool(dataframe['close'].shift(i) <= dataframe['bb_lowerband'].shift(i)) else 0 + # print(a) + + conditions_bb_1 = [ + (dataframe['close'].shift(2) < dataframe['bb_lowerband'].shift(2)), + (dataframe['bb_width'].shift(2) >= 0.09), # & (dataframe['rolling'] < 2)) + (dataframe['volume'].shift(2) >= self.buy_volume.value * 1000), + (dataframe['open'] < dataframe['close']) + # ( + # (dataframe['bb_width'] >= 0.119) | + # (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & + # ((dataframe['bb_width'].shift(3) >= 0.0) & (dataframe['bb_rolling'].shift(3) < 1)) + + # ((dataframe['bb_width'] >= 0.08) & (dataframe['rolling'] < 2)) + # ((dataframe['bb_width'] >= 0.03) & (count >= 6)) | + # ( + # (dataframe['bb_width'] >= self.buy_bollinger_2.value) & + # (dataframe['close'] / dataframe['min'] <= self.buy_min.value) + # ) + # ), # self.buy_bollinger.value, + # dataframe['volume'] >= self.buy_volume.value * 1000, + # dataframe['percent'].shift(3) >= self.buy_percent.value + ] + condition_bb = reduce(lambda x, y: x & y, conditions_bb_1) + conditions_bb_2 = [ + (dataframe['close'].shift(3) < dataframe['bb_lowerband'].shift(3)), + (dataframe['bb_width'].shift(3) >= 0.09), # & (dataframe['rolling'] < 2)) + (dataframe['volume'].shift(3) >= self.buy_volume.value * 1000), + (dataframe['open'] < dataframe['close']) + ] + condition_bb2 = reduce(lambda x, y: x & y, conditions_bb_2) + + dataframe.loc[ + ( + (condition_bb | condition_bb2) & + (dataframe['min'] == dataframe['min'].shift(1)) & + (dataframe['min'].shift(1) == dataframe['min'].shift(2)) & + (dataframe['min'].shift(2) == dataframe['min'].shift(3)) + # # courant est positif + # (dataframe['open'].shift(3) < dataframe['close'].shift(3)) & + # # previous cut BB + # (dataframe['close'].shift(4) < dataframe['bb_lowerband'].shift(4)) + # min + # (dataframe['min'].shift(3) * 1.001 >= dataframe['open'].shift(3)) + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4121.jsonOLD b/StrategyPierrick4121.jsonOLD new file mode 100644 index 0000000..130c178 --- /dev/null +++ b/StrategyPierrick4121.jsonOLD @@ -0,0 +1,34 @@ +{ + "strategy_name": "StrategyPierrick4121", + "params": { + "stoploss": { + "stoploss": -1 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_bollinger": 0.12, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 18.9, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-18 12:33:59.714495+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4121.py b/StrategyPierrick4121.py new file mode 100644 index 0000000..906b7b8 --- /dev/null +++ b/StrategyPierrick4121.py @@ -0,0 +1,286 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4121(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.05, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + # 'sma500': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + # print(last_candle) + # Above 20% profit, sell when rsi < 80 + if (last_candle['bb_upperband'] > last_candle['max']) & (previous_last_candle['sma20'] > last_candle['sma20']): + return 'over_bb_band' + + # # Between 2% and 10%, sell if EMA-long above EMA-short + if 0.05 < current_profit < 0.1: + if previous_last_candle['sma20'] > last_candle['sma20'] and (current_time - trade.open_date_utc).seconds >= 3600 * 3: + return 'profit_3h' + + # Sell any positions at a loss if they are held for more than one day. + if 0.1 > current_profit > 0.0 and previous_last_candle['sma20'] > last_candle['sma20'] \ + and (current_time - trade.open_date_utc).seconds >= 3600 * 5: + return 'profit_5h' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # condition_bb_rolling = [ + # (dataframe['bb_width'].shift(3) >= self.buy_bollinger.value), + # (dataframe['volume'].shift(3) * dataframe['close'] / 1000 >= 100), # self.buy_volume.value * 1000), + # (dataframe['open'] < dataframe['close']), + # (dataframe['open'] * 1.02 < dataframe['close']), + # # (dataframe['close'] <= dataframe['sma100'] * 1.01), + # (dataframe['close'].shift(1) <= dataframe['bb_lowerband'].shift(1)) | + # (dataframe['close'].shift(2) <= dataframe['bb_lowerband'].shift(2)) | + # (dataframe['close'].shift(3) <= dataframe['bb_lowerband'].shift(3)), + # ] + # condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + # + # condition_bb_rolling_inf = [ + # (dataframe['bb_width'] >= 0.04), + # (dataframe['volume'] * dataframe['close'] / 1000 >= 100), #>= self.buy_volume.value * 1000), + # (dataframe['open'] < dataframe['close']), + # (dataframe['open'] * 1.02 < dataframe['close']), + # # (dataframe['close'] <= dataframe['min'] * 1.01), + # (dataframe['close'] * 1.04) <= dataframe['sma100'], + # (dataframe['close'].shift(1) <= dataframe['bb_lowerband'].shift(1)) + # ] + # condition_bb_rolling_inf2 = reduce(lambda x, y: x & y, condition_bb_rolling_inf) + + condition_bb_rolling = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + # (dataframe['open'] < dataframe['close']), + (dataframe['bb_rolling_min'].shift(5) <= -6), + (dataframe['bb_rolling_min'].shift(5) == dataframe['bb_rolling'].shift(5)), + # (dataframe['sma100'].shift(1) <= dataframe['sma100']), + (dataframe['close'].shift(5) < dataframe['min'].shift(5) + ( + dataframe['max'].shift(5) - dataframe['min'].shift(5)) / 3), + (dataframe['min'].shift(5) == dataframe['min']) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + dataframe.loc[ + ( + condition_bb_rolling2 # | condition_bb_rolling_inf2 + + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41211.py b/StrategyPierrick41211.py new file mode 100644 index 0000000..1a553a7 --- /dev/null +++ b/StrategyPierrick41211.py @@ -0,0 +1,281 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41211(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma500': {'color': 'pink'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + # print(last_candle) + if (current_profit > 0) \ + & (last_candle['bb_upperband'] > last_candle['max']) \ + & (previous_last_candle['sma20'] > last_candle['sma20']): + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['close'] < last_candle['open']) \ + & (previous_last_candle['bb_upperband'] < previous_last_candle['close']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + # & (previous_last_candle['sma100'] > last_candle['sma100']) \ + return 'close_over_bb_band_sma100_desc' + + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + return 'profit_3h_sma10_desc' + + if (0.1 > current_profit > 0.0) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + step = 3 + bb_rolling_max = -6 + condition_bb_rolling = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) == dataframe['bb_rolling'].shift(step)), + # (dataframe['sma100'].shift(1) <= dataframe['sma100']), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + # conditions = [ + # dataframe['bb_width'] >= 0.09, #self.buy_bollinger.value, + # (dataframe['close'] < dataframe['bb_lowerband']), + # (dataframe['close'] < dataframe['sma100'] * 0.99) #self.buy_sma_percent.value) + # ] + + dataframe.loc[ + ( + condition_bb_rolling2 #| (reduce(lambda x, y: x & y, conditions)) + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41212.py b/StrategyPierrick41212.py new file mode 100644 index 0000000..7cf164e --- /dev/null +++ b/StrategyPierrick41212.py @@ -0,0 +1,338 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41212(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma500': {'color': 'pink'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']): + # & (last_candle['bb_upperband'] > last_candle['max']) \ + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + # if (current_profit > 0) \ + # & (last_candle['close'] < last_candle['open']) \ + # & (previous_last_candle['bb_upperband'] < previous_last_candle['close']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / last_candle['sma10'] < 0.1): + # # & (previous_last_candle['sma100'] > last_candle['sma100']) \ + # print("close_over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'close_over_bb_band_sma10_desc' + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + step = self.buy_step.value + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + # (100 * (dataframe['sma100'].shift(12) - dataframe['sma100']) / dataframe['sma100']) < 0.1, + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) == dataframe['bb_rolling'].shift(step)), + # (dataframe['sma100'].shift(1) <= dataframe['sma100']), + #(100 * ((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe['sma20']) < 0.1), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + conditions = [ + dataframe['bb_width'] >= 0.065, #self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']) + ] + + dataframe.loc[ + ( + ( + condition_bb_rolling2 + # | (reduce(lambda x, y: x & y, conditions)) + ) & ( + dataframe['volume'] > 0 + ) + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41213.py b/StrategyPierrick41213.py new file mode 100644 index 0000000..d942ad4 --- /dev/null +++ b/StrategyPierrick41213.py @@ -0,0 +1,347 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41213(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma500': {'color': 'pink'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']): + # & (last_candle['bb_upperband'] > last_candle['max']) \ + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 80): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # if (current_profit > 0) \ + # & (last_candle['close'] < last_candle['open']) \ + # & (previous_last_candle['bb_upperband'] < previous_last_candle['close']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / last_candle['sma10'] < 0.1): + # # & (previous_last_candle['sma100'] > last_candle['sma100']) \ + # print("close_over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'close_over_bb_band_sma10_desc' + + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + # if (current_profit < -0.025) \ + # & (previous_last_candle['sma20'] > last_candle['sma20']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 3): + # print("stop_loss_3h", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_3h' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + step = self.buy_step.value + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + # (100 * (dataframe['sma100'].shift(12) - dataframe['sma100']) / dataframe['sma100']) < 0.1, + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) == dataframe['bb_rolling'].shift(step)), + # (100 * ((dataframe['sma100'].shift(12) - dataframe['sma100']) / dataframe['sma100']) < 0.25), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['rsi'] <= 35) + + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + conditions = [ + dataframe['bb_width'] >= 0.065, #self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['rsi'] <= 35) + ] + + dataframe.loc[ + ( + ( + # condition_bb_rolling2 + (reduce(lambda x, y: x & y, conditions)) + ) & ( + dataframe['volume'] > 0 + ) + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41214.py b/StrategyPierrick41214.py new file mode 100644 index 0000000..a353c40 --- /dev/null +++ b/StrategyPierrick41214.py @@ -0,0 +1,359 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41214(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma500': {'color': 'pink'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + # if (current_profit > 0) \ + # & (last_candle['close'] < last_candle['open']) \ + # & (previous_last_candle['bb_upperband'] < previous_last_candle['close']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma10'] - last_candle['sma10']) / last_candle['sma10'] < 0.1): + # # & (previous_last_candle['sma100'] > last_candle['sma100']) \ + # print("close_over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'close_over_bb_band_sma10_desc' + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + step = 1 + else: + if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + step = 2 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + # (100 * (dataframe['sma100'].shift(12) - dataframe['sma100']) / dataframe['sma100']) < 0.1, + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) == dataframe['bb_rolling'].shift(step)), + # (dataframe['sma100'].shift(1) <= dataframe['sma100']), + # (100 * ((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe['sma20']) < 0.1), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + # (dataframe['rsi'].shift(step) <= 32) + + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + conditions = [ + dataframe['bb_width'] >= 0.065, # self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']) + ] + + dataframe.loc[ + ( + ( + condition_bb_rolling2 + # | (reduce(lambda x, y: x & y, conditions)) + ) & ( + dataframe['volume'] > 0 + ) + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41215.py b/StrategyPierrick41215.py new file mode 100644 index 0000000..7ab9fcf --- /dev/null +++ b/StrategyPierrick41215.py @@ -0,0 +1,311 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41215(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + # if current_candle['bb_width'] > 0.05: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + step = 5 + else: + if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + step = 4 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling = [ + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) == dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] > 0) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + dataframe.loc[condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41216.py b/StrategyPierrick41216.py new file mode 100644 index 0000000..b813aee --- /dev/null +++ b/StrategyPierrick41216.py @@ -0,0 +1,323 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41216(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.065: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.045: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + ) | ( + (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + # step = 5 + # else: + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + # step = 4 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling = [ + (dataframe['bb_width'] >= 0.035), + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] > 0) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling) + + dataframe.loc[condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41217.py b/StrategyPierrick41217.py new file mode 100644 index 0000000..3a2431e --- /dev/null +++ b/StrategyPierrick41217.py @@ -0,0 +1,350 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41217(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 1 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.065: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.045: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + # step = 5 + # else: + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + # step = 4 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling_1 = [ + (dataframe['bb_width'] >= 0.035), + # (dataframe['close'] > dataframe['open']), + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + # (dataframe['rsi'] <= 30) + ] + condition_bb_rolling1 = reduce(lambda x, y: x & y, condition_bb_rolling_1) + step = 2 + condition_bb_rolling_2 = [ + (dataframe['bb_width'] >= 0.04), + (dataframe['close'] < dataframe['sma10']), + ((dataframe['close'] > dataframe['open']) | (dataframe['percent'] > -0.01)), + # (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + # (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + (dataframe['rsi'] <= 30) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling_2) + + dataframe.loc[ + condition_bb_rolling1 | + condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41218.py b/StrategyPierrick41218.py new file mode 100644 index 0000000..89d7d6d --- /dev/null +++ b/StrategyPierrick41218.py @@ -0,0 +1,349 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime, timezone, timedelta + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41218(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.065: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.045: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=6)) + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + ((current_time - trade.open_date_utc).seconds >= 3600 * 3) & + (last_candle['percent'] < 0) & (last_candle['percent5'] < 0) & + (last_candle['close'] < last_candle['bb_width']) + ): + # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=2)) + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate, ' percent5=', last_candle['percent5']) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5)\ + & (last_candle['percent'] < 0) & (last_candle['percent5'] < 0) \ + & (last_candle['close'] < last_candle['bb_width']): + # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=3)) + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate, + "percent5=", abs(last_candle['percent5'])) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + # step = 5 + # else: + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + # step = 4 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling_1 = [ + (dataframe['bb_width'] >= 0.035), + # (dataframe['close'] > dataframe['open']), + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + # (dataframe['rsi'] <= 30) + ] + condition_bb_rolling1 = reduce(lambda x, y: x & y, condition_bb_rolling_1) + step = 2 + condition_bb_rolling_2 = [ + (dataframe['bb_width'] >= 0.04), + # (dataframe['percent5'] >= 0.01), + (dataframe['close'] < dataframe['sma10']), + ((dataframe['close'] > dataframe['open']) | (dataframe['percent'] > -0.01)), + # (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + # (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + (dataframe['rsi'] <= 30) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling_2) + + dataframe.loc[ + condition_bb_rolling1 | + condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41219.py b/StrategyPierrick41219.py new file mode 100644 index 0000000..9993de0 --- /dev/null +++ b/StrategyPierrick41219.py @@ -0,0 +1,378 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime, timezone, timedelta + +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +from freqtrade.persistence import Trade +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41219(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.065: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.045: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.025) \ + # & (last_candle['percent'] < 0) \ + # & ((current_time - trade.open_date_utc).seconds <= 1800): + # print("stop_quick_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_quick_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 79): + self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=6)) + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 0.1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10']) & + ((current_time - trade.open_date_utc).seconds >= 3600 * 3) & + (last_candle['percent'] < 0) & + (abs(last_candle['percent5']) > current_profit / 5) + ): + # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=2)) + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate, ' percent5=', last_candle['percent5']) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5)\ + & (last_candle['percent'] < 0) \ + & (abs(last_candle['percent5']) > current_profit / 5): + # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=3)) + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + # if (-0.01 < current_profit < 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 10): + # # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=3)) + # print("stop_wait_10h", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_wait_10h' + # + # if (-0.02 < current_profit < -0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + # # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=3)) + # print("stop_wait_5h", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_wait_5h' + # + # if (current_profit < -0.02) : + # self.lock_pair(pair, until=datetime.now(timezone.utc) + timedelta(hours=3)) + # print("stop_big_loss", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_big_loss' + + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # if self.config['runmode'].value in ('live', 'dry_run'): + # trades = Trade.get_trades([Trade.pair == metadata['pair'], + # Trade.open_date > datetime.utcnow() - timedelta(days=1), + # Trade.is_open.is_(False), + # ]).order_by(Trade.close_date).all() + # # Summarize profit for this pair. + # print("Trades=", trades) + # curdayprofit = sum(trade.close_profit for trade in trades) + + step = self.buy_step.value + # if reduce(lambda x, y: x & y, dataframe['bb_width'] > 0.065): + # step = 1 + # else: + # if reduce(lambda x, y: x & y, dataframe['bb_width'] > 0.045): + # step = 2 + + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling_1 = [ + (dataframe['bb_width'] >= 0.025), + # (dataframe['close'] > dataframe['open']), + (dataframe['close'] < dataframe['sma10']), + (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + # (dataframe['rsi'] <= 30) + ] + condition_bb_rolling1 = reduce(lambda x, y: x & y, condition_bb_rolling_1) + step = 2 + condition_bb_rolling_2 = [ + (dataframe['bb_width'] >= 0.04), + # (dataframe['percent5'] >= 0.01), + (dataframe['close'] < dataframe['sma10']), + ((dataframe['close'] > dataframe['open']) | (dataframe['percent'] > -0.01)), + # (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + # (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + (dataframe['rsi'] <= 30) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling_2) + + dataframe.loc[ + condition_bb_rolling1 | + condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ) | ( + # (dataframe['close'] * 1.04 < dataframe['open']) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4122.json b/StrategyPierrick4122.json new file mode 100644 index 0000000..f2b59f5 --- /dev/null +++ b/StrategyPierrick4122.json @@ -0,0 +1,31 @@ +{ + "strategy_name": "StrategyPierrick4122", + "params": { + "buy": { + "buy_bollinger": 0.04, + "buy_bollinger_max": 0.03, + "buy_bollinger_min": 0.02, + "buy_sma100": 0.96, + "buy_volume": 14.2 + }, + "sell": {}, + "protection": {}, + "roi": { + "0": 0.11399999999999999, + "40": 0.08299999999999999, + "54": 0.04, + "64": 0 + }, + "stoploss": { + "stoploss": -0.191 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.062, + "trailing_stop_positive_offset": 0.10400000000000001, + "trailing_only_offset_is_reached": false + } + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-19 18:19:33.181406+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick4122.py b/StrategyPierrick4122.py new file mode 100644 index 0000000..2e80860 --- /dev/null +++ b/StrategyPierrick4122.py @@ -0,0 +1,289 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4122(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.09, space="buy") + + buy_bollinger_min = DecimalParameter(0.0, 0.06, decimals=2, default=0.02, space="buy") + buy_bollinger_max = DecimalParameter(0.02, 0.09, decimals=2, default=0.04, space="buy") + + buy_sma100 = DecimalParameter(0.94, 1.2, decimals=2, default=1.0, space="buy") + + + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -0.1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + # 'sma500': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe["rolling"] = (100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling(5).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=5) + + # print(dataframe["rolling"].tolist()) + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + condition_bb_rolling_1 = [ + (dataframe['bb_width'].shift(3) >= self.buy_bollinger.value), + (dataframe['volume'].shift(3) * dataframe['close'] / 1000 >= 100), # self.buy_volume.value * 1000), + (dataframe['open'] < dataframe['close']), + (dataframe['open'] * 1.02 < dataframe['close']), + # (dataframe['close'] <= dataframe['sma100'] * 1.01), + (dataframe['close'].shift(1) <= dataframe['bb_lowerband'].shift(1)) | + (dataframe['close'].shift(2) <= dataframe['bb_lowerband'].shift(2)) | + (dataframe['close'].shift(3) <= dataframe['bb_lowerband'].shift(3)), + ] + condition_bb_rolling1 = reduce(lambda x, y: x & y, condition_bb_rolling_1) + condition_bb_rolling_2 = [ + # En dessous de la moyenne 100 + (dataframe['open'] < dataframe['sma100'] * self.buy_sma100.value), + # Sma 10 monte + (dataframe['sma10'] > dataframe['sma10'].shift(2)), + # Chandelle courante et précédente positives + (dataframe['open'] < dataframe['close']), + (dataframe['open'].shift(1) < dataframe['close'].shift(1)), + # 3/6 chandelles précédentes sur bbwidth pincée + (dataframe['bb_width'].shift(2) > self.buy_bollinger_min.value), + (dataframe['bb_width'].shift(4) > self.buy_bollinger_min.value), + (dataframe['bb_width'].shift(6) > self.buy_bollinger_min.value), + (dataframe['bb_width'].shift(2) < self.buy_bollinger_max.value), + (dataframe['bb_width'].shift(4) < self.buy_bollinger_max.value), + (dataframe['bb_width'].shift(6) < self.buy_bollinger_max.value), + # (dataframe['open'] * 1.02 < dataframe['close']), + # (dataframe['open'].shift(1) * 1.02 < dataframe['close'].shift(1)), + # hausse courante et précédente < 2% + (dataframe['percent'] < 0.02), + (dataframe['percent'].shift(1) < 0.015), + # Chandelle courante et précédente frôle upperband + (dataframe['close'] <= dataframe['bb_upperband']), + (dataframe['close'] * 1.002 >= dataframe['bb_upperband']), + (dataframe['close'].shift(1) <= dataframe['bb_upperband'].shift(1)), + (dataframe['close'].shift(1) * 1.002 >= dataframe['bb_upperband'].shift(1)), + + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling_2) + + condition_bb_rolling_inf = [ + False, + (dataframe['bb_width'] >= 0.04), + (dataframe['volume'] * dataframe['close'] / 1000 >= 100), #>= self.buy_volume.value * 1000), + (dataframe['open'] < dataframe['close']), + (dataframe['open'] * 1.02 < dataframe['close']), + # (dataframe['close'] <= dataframe['min'] * 1.01), + (dataframe['close'] * 1.04) <= dataframe['sma100'], + (dataframe['close'].shift(1) <= dataframe['bb_lowerband'].shift(1)) + ] + condition_bb_rolling_inf2 = reduce(lambda x, y: x & y, condition_bb_rolling_inf) + + dataframe.loc[ + ( + # condition_bb_rolling1 + condition_bb_rolling2 + # condition_bb_rolling_inf2 + ), 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41220.py b/StrategyPierrick41220.py new file mode 100644 index 0000000..32b9788 --- /dev/null +++ b/StrategyPierrick41220.py @@ -0,0 +1,410 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime, timezone, timedelta + +import numpy +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41220(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.065, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'min20': {'color': 'pink'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + 'bb_min': {'color': 'red'}, + }, + # "ADX": { + # 'adx': {'color': 'white'}, + # 'minus_dm': {'color': 'blue'}, + # 'plus_dm': {'color': 'red'} + # }, + "Rsi": { + 'rsi': {'color': 'pink'}, + 'rsi3': {'color': 'blue'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'}, + "percent20": {'color': 'blue'}, + "pente": {'color': 'yellow'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.065: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.045: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + dataframe["rsi3"] = (dataframe['rsi']).rolling(3).mean() + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + + dataframe['pente'] = ((dataframe['sma20'] - dataframe['sma20'].shift(1)) / dataframe['sma20'].shift(1)) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + + # # Stoch + # stoch = ta.STOCH(dataframe) + # dataframe['slowk'] = stoch['slowk'] + # + # # Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy) + # rsi = 0.1 * (dataframe['rsi'] - 50) + # dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1) + # + # # SAR Parabol + # dataframe['sar'] = ta.SAR(dataframe) + # + # # Hammer: values [0, 100] + # dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + step = self.buy_step.value + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.015): + # step = 5 + # else: + # if reduce(lambda x, y: x & y, dataframe['bb_width'] < 0.03): + # step = 4 + bb_rolling_max = self.buy_rolling.value + condition_bb_rolling_1 = [ + (dataframe['bb_width'] >= 0.035), + # (dataframe['close'] > dataframe['open']), + (dataframe['close'] < dataframe['sma10']), + # (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + # (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + # (dataframe['rsi'] <= 30) + ] + condition_bb_rolling1 = reduce(lambda x, y: x & y, condition_bb_rolling_1) + step = 2 + condition_bb_rolling_2 = [ + (dataframe['bb_width'] >= 0.04), + (dataframe['close'] < dataframe['sma10']), + ((dataframe['close'] > dataframe['open']) | (dataframe['percent'] > -0.01)), + # (dataframe['bb_rolling_min'].shift(step) <= bb_rolling_max), + # (dataframe['bb_rolling_min'].shift(step) >= dataframe['bb_rolling'].shift(step)), + (dataframe['close'].shift(step) < dataframe['min'].shift(step) + ( + dataframe['max'].shift(step) - dataframe['min'].shift(step)) / 3), + (dataframe['min'].shift(step) == dataframe['min']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + (dataframe['rsi'] <= 30) + ] + condition_bb_rolling2 = reduce(lambda x, y: x & y, condition_bb_rolling_2) + + dataframe.loc[ + condition_bb_rolling1 | + condition_bb_rolling2, 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + condition_sell_1 = [ + (dataframe['close'] < dataframe['open']), + (dataframe['close'].shift(1) < dataframe['open'].shift(1)), + (dataframe['close'].shift(2) < dataframe['open'].shift(2)), + (dataframe['close'] < dataframe['bb_lowerband']), + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02), + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + (dataframe['rsi'] <= 40) + ] + condition_sell1 = reduce(lambda x, y: x & y, condition_sell_1) + # condition = np.where(condition_sell1, 'True', 'False') + # if bool(condition_sell_1): + # # print('condition_sell1=', condition_sell1) + # self.lock_pair(metadata['pair'], until=datetime.now(timezone.utc) + timedelta(hours=3)) + + dataframe.loc[ + ( + condition_sell1 + # ) | ( + # (dataframe['close'] < dataframe['bb_lowerband']) & + # StrategyHelperLocal.red_candles(dataframe) & + # (dataframe['percent5'] < -0.04) + ), 'sell'] = 1 + + return dataframe + + +class StrategyHelperLocal: + @staticmethod + def red_candles(dataframe, shift=0): + """ + evaluates if we are having 8 red candles in a row + :param self: + :param dataframe: + :param shift: shift the pattern by n + :return: + """ + return ( + (dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) & + (dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) & + (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) & + (dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) & + (dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift)) & + (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) & + (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) & + (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) + + ) diff --git a/StrategyPierrick41221.py b/StrategyPierrick41221.py new file mode 100644 index 0000000..0ef5de8 --- /dev/null +++ b/StrategyPierrick41221.py @@ -0,0 +1,453 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41221(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.00, 0.18, decimals=2, default=0.075, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + # buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + # buy_min = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # buy_percent = DecimalParameter(1, 1.1, decimals=2, default=1.01, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=18, space="buy") + + buy_step = IntParameter(1, 8, default=3, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + "0": 100 + # "0": 0.015, + # "5": 0.01, + # "10": 0.005, + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '1m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'green'}, + 'bb_min': {'color': 'red'}, + }, + "Volume": { + 'volume5': {'color': 'yellow'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + trades = list() + + # buy_base = DecimalParameter(0, 0.2, decimals=2, default=0.10, space='buy') + # buy_diff = DecimalParameter(0, 0.2, decimals=2, default=0.20, space='buy') + # + # buy_rsi = IntParameter(20, 80, default=42, space='buy') + # buy_rsi_max = IntParameter(60, 90, default=60, space='buy') + # + # buy_rsi_1h = IntParameter(20, 80, default=72, space='buy') + # buy_rsi_max_1h = IntParameter(60, 80, default=72, space='buy') + # + # buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + # + # buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + # buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + # buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy') + # + # buy_0_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + # buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + # buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy') + # + # buy_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy') + # buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy') + # buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy') + # + # buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy') + # buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy') + # + # buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy') + # buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy') + # buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy') + # + # buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + # buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + # buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy') + # + # buy_b_real = DecimalParameter(0.001, 0.999, decimals=4, default=0.11908, space='buy') + # buy_b_cat = CategoricalParameter([">R", "=R", "R", "=R", " 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_5'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max200_5'] = (dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['volume5'] = dataframe["volume"].rolling(5).mean() + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + # (dataframe['close'] < dataframe['bb_lowerband']), + # (dataframe['close'] < dataframe['sma100'] * 0.99) #self.buy_sma_percent.value) + # ] + conditions_vol = [] + conditions_vol.append(dataframe['percent5'] > 0) #self.buy_bollinger.value, + conditions_vol.append(dataframe['percent'].shift(1) > 0) + conditions_vol.append(dataframe['percent'] > 2 * dataframe['percent'].shift(1)) + conditions_vol.append(dataframe['close'] > dataframe['open']) + # conditions_vol.append(dataframe['bb_width'] > dataframe['bb_width'].shift(3) * 2) + + for decalage in range(5, 10): + conditions_vol.append(dataframe['bb_width'].shift(decalage) <= dataframe['bb_width'].shift(decalage - 1)) + # conditions_vol.append(-0.002 <= dataframe['percent'].shift(decalage)) + # conditions_vol.append(dataframe['percent'].shift(decalage) <= 0.002) + + for decalage in range(2, 5): + conditions_vol.append(dataframe['volume5'].shift(decalage) <= dataframe['volume5'].shift(decalage - 1)) + conditions_vol.append(dataframe['percent'].shift(decalage) <= dataframe['percent'].shift(decalage - 1)) + + # GUARDS AND TRENDS + + dataframe.loc[ + ( + # (reduce(lambda x, y: x & y, conditions)) + (reduce(lambda x, y: x & y, conditions_vol)) + ) + , + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] < dataframe['open']) & + # (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + # (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + # (dataframe['close'] < dataframe['bb_lowerband']) & + # (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) & + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + # ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41222.py b/StrategyPierrick41222.py new file mode 100644 index 0000000..ae47a8a --- /dev/null +++ b/StrategyPierrick41222.py @@ -0,0 +1,312 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41222(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.97, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'green'}, + 'bb_min': {'color': 'red'}, + }, + "Volume": { + 'volume5': {'color': 'yellow'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.012: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.09: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + dataframe['volume5'] = dataframe["volume"].rolling(5).mean() + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['close'] < dataframe['sma100'] * self.buy_sma_percent.value) + ] + # GUARDS AND TRENDS + + 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: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick41223.py b/StrategyPierrick41223.py new file mode 100644 index 0000000..eb3b2e3 --- /dev/null +++ b/StrategyPierrick41223.py @@ -0,0 +1,355 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +from datetime import datetime + +import numpy +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick41223(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.07, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.99, space="buy") + buy_rolling = IntParameter(-20, 0, default=-6, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = False + trailing_stop_positive = 0.02 + trailing_stop_positive_offset = 0.0275 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'red'}, + 'bb_upperband': {'color': 'green'}, + 'sma100': {'color': 'blue'}, + 'sma10': {'color': 'yellow'}, + 'min': {'color': 'white'}, + 'max': {'color': 'white'}, + 'sma20': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'green'}, + 'bb_min': {'color': 'red'}, + }, + "Volume": { + 'volume5': {'color': 'yellow'}, + }, + "Rsi": { + 'rsi': {'color': 'pink'}, + }, + "rolling": { + 'bb_rolling': {'color': '#87e470'}, + "bb_rolling_min": {'color': '#ac3e2a'} + }, + "percent": { + "percent": {'color': 'green'}, + "percent5": {'color': 'red'} + } + } + } + + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 5 + }, + { + "method": "MaxDrawdown", + "lookback_period_candles": 48, + "trade_limit": 20, + "stop_duration_candles": 4, + "max_allowed_drawdown": 0.2 + }, + { + "method": "StoplossGuard", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "only_per_pair": False + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 6, + "trade_limit": 2, + "stop_duration_candles": 60, + "required_profit": 0.02 + }, + { + "method": "LowProfitPairs", + "lookback_period_candles": 24, + "trade_limit": 4, + "stop_duration_candles": 2, + "required_profit": 0.01 + } + ] + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + + # print("proposed_stake=", proposed_stake, " max_stake=", max_stake) + if current_candle['bb_width'] > 0.012: + print("use more stake", pair, " ", proposed_stake * 2) + return min(max_stake, proposed_stake * 2) + + if current_candle['bb_width'] > 0.09: + print("use more stake", pair, " ", proposed_stake * 1.5) + return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + # (last_candle['percent5'] < -0.005) \ + # if (0 < current_profit < 0.005) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2): + # # & (previous_last_candle['sma10'] > last_candle['sma10']): + # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=", + # last_candle['percent5']) + # return 'too_small_gain' + + # if (current_profit < -0.05) \ + # & ((current_time - trade.open_date_utc).days >= 3): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'stop_loss_profit' + + # if (current_profit > 0.02) \ + # & (last_candle['percent'] < 0.01) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'lost_half_profit' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \ + & (previous_5_candle['sma20'] > last_candle['sma20']) \ + & (last_candle['percent'] < 0) \ + & (last_candle['percent5'] < 0): + print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_bb_band_sma20_desc' + + if (current_profit > 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & (last_candle['rsi'] > 75): + print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + # description trade + # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00) + # print(last_candle) + if 0.05 < current_profit < 1: + if ( + (previous_last_candle['sma10'] > last_candle['sma10'] * 1.005) & + (current_time - trade.open_date_utc).seconds >= 3600 * 3 + # ) | ( + # (current_time - trade.open_date_utc).seconds >= 3600 * 6 + ): + # self.lock_pair(pair, until=current_time + timedelta(hours=3)) + + print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_3h_sma10_desc' + + if (0 < current_profit < 0.1) \ + & (previous_last_candle['sma20'] > last_candle['sma20']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600 * 5): + print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'profit_5h_sma20_desc' + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # # Plus Directional Indicator / Movement + # dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + # dataframe['plus_di'] = ta.PLUS_DI(dataframe) + # + # # Minus Directional Indicator / Movement + # dataframe['adx'] = ta.ADX(dataframe) + # dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + # dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + # dataframe['min'] = ta.MIN(dataframe) + # dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + # dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + # dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + # dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + # dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + # dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200) + dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20) + + dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200) + dataframe['max_min'] = dataframe['max'] / dataframe['min'] + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + dataframe['volume5'] = dataframe["volume"].rolling(5).mean() + + dataframe["rolling"] = ( + 100 * (dataframe["close"] - dataframe["bb_lowerband"]) / dataframe["bb_lowerband"]).rolling( + 3).mean() + dataframe["bb_rolling"] = dataframe["rolling"] / dataframe["bb_width"] + dataframe['bb_rolling_min'] = ta.MIN(dataframe['bb_rolling'], timeperiod=10) + dataframe['bb_buy'] = (dataframe['min'] + (dataframe['max'] - dataframe['min']) / 3) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [ + # dataframe['bb_width'] >= self.buy_bollinger.value, + (dataframe['close'] < dataframe['bb_lowerband']), + (dataframe['close'] <= dataframe['min']), + (dataframe['close'] < dataframe['sma100'] * self.buy_sma_percent.value), + (dataframe['bb_rolling'] <= self.buy_rolling.value), + # (dataframe['bb_rolling_min'] >= dataframe['bb_rolling']), + (dataframe['volume'] * dataframe['close'] / 1000 > 100), + (dataframe['rsi'] < 27) + ] + # GUARDS AND TRENDS + + 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: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick413.json b/StrategyPierrick413.json new file mode 100644 index 0000000..061f110 --- /dev/null +++ b/StrategyPierrick413.json @@ -0,0 +1,37 @@ +{ + "strategy_name": "StrategyPierrick413", + "params": { + "roi": { + "0": 0.096, + "30": 0.049, + "60": 0.032, + "120": 0 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.001, + "trailing_stop_positive_offset": 0.0175, + "trailing_only_offset_is_reached": true + }, + "buy": { + "buy_adx": 8, + "buy_bollinger": 0.08, + "buy_bollinger_2": 0.08, + "buy_bollinger_2_enabled": false, + "buy_bollinger_enabled": true, + "buy_plusdi": 0.7251500178901511, + "buy_rsi": 37, + "buy_sma_percent": 0.98, + "buy_sma_percent_enabled": false, + "buy_volume": 21.4, + "buy_volume_enabled": true + }, + "sell": {}, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2021-12-08 19:24:09.461327+00:00" +} \ No newline at end of file diff --git a/StrategyPierrick413.py b/StrategyPierrick413.py new file mode 100644 index 0000000..0fd9250 --- /dev/null +++ b/StrategyPierrick413.py @@ -0,0 +1,267 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter, RealParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick413(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + buy_bollinger = DecimalParameter(0.025, 0.125, decimals=2, default=0.095, space="buy") + buy_bollinger_enabled = BooleanParameter(default=True, space="buy") + # Valeur de la deuxième condition bollinger avec condition sma200 + buy_bollinger_2 = DecimalParameter(0.0, 0.08, decimals=2, default=0.04, space="buy") + buy_bollinger_2_enabled = BooleanParameter(default=True, space="buy") + # pourcentage sma à dépasser + buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.098, space="buy") + buy_sma_percent_enabled = BooleanParameter(default=True, space="buy") + # volume à atteindre + buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + buy_volume_enabled = BooleanParameter(default=True, space="buy") + + buy_rsi = IntParameter([0, 50], default=30, space='buy') + buy_adx = IntParameter([0, 100], default=50, space='buy') + buy_plusdi = RealParameter(low=0, high=1, default=0.5, space='buy') + + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition1 = np.where(value >= 1.04, True, False) + + conditions = [] + # GUARDS AND TRENDS + if self.buy_bollinger_enabled.value: + conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + + conditions2 = [] + if self.buy_bollinger_2_enabled.value: + conditions2.append(dataframe['bb_width'] >= self.buy_bollinger_2.value) + + conditions_volume = [] + condition_volume = True + if self.buy_volume_enabled.value: + conditions_volume.append(dataframe['volume'] >= self.buy_volume.value * 1000) + if conditions_volume: + condition_volume = np.where(conditions_volume, True, False) + + condition2 = False + if conditions2: + condition2 = reduce(lambda x, y: x & y, conditions2) & condition1 + + condition_sma = False + conditions_sma = [] + if self.buy_sma_percent_enabled.value: + # conditions_sma.append(dataframe['close'] <= dataframe['sma200'] * self.buy_sma_percent.value) + conditions_sma.append((dataframe['sma100'].shift(36) - dataframe['sma100']) / dataframe['sma100'] > self.buy_sma_percent.value) + if conditions_sma: + condition_sma = reduce(lambda x, y: x & y, conditions_sma) + + if conditions: + dataframe.loc[ + ( + ( + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) < 0.025) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (reduce(lambda x, y: x & y, conditions) | (condition2 & condition_sma)) & + (dataframe['rsi'] < self.buy_rsi.value) & + (dataframe['adx'] > self.buy_adx.value) & + (dataframe['plus_di'] > self.buy_plusdi.value) + ) + ) & + condition_volume, + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(1) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.015) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick415.py b/StrategyPierrick415.py new file mode 100644 index 0000000..4a1f898 --- /dev/null +++ b/StrategyPierrick415.py @@ -0,0 +1,231 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick415(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.05, 0.14, decimals=2, default=0.095, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.98, space="buy") + # volume à atteindre + # buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + + # buy_close = DecimalParameter(0.95, 1.05, decimals=2, default=0, space="buy") + # buy_sma = IntParameter(1, 40, default=10, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # conditions = [] + # conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + # + # if conditions: + dataframe.loc[ + ( + # (dataframe['open'] <= dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.04) + # (dataframe['sma100'] < dataframe['sma500']) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick4151.py b/StrategyPierrick4151.py new file mode 100644 index 0000000..cdf2fae --- /dev/null +++ b/StrategyPierrick4151.py @@ -0,0 +1,231 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick4151(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.05, 0.14, decimals=2, default=0.095, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.98, space="buy") + # volume à atteindre + # buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + + # buy_close = DecimalParameter(0.95, 1.05, decimals=2, default=0, space="buy") + # buy_sma = IntParameter(1, 40, default=10, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # conditions = [] + # conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + # + # if conditions: + dataframe.loc[ + ( + # (dataframe['open'] <= dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.04) + # (dataframe['open'] <= dataframe['sma100']) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick416.py b/StrategyPierrick416.py new file mode 100644 index 0000000..dcd1ee3 --- /dev/null +++ b/StrategyPierrick416.py @@ -0,0 +1,236 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from freqtrade.strategy.parameters import DecimalParameter, BooleanParameter, IntParameter +from pandas import DataFrame +import math +from functools import reduce + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick416(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # valeur de bbwidth pour démarrer + # buy_bollinger = DecimalParameter(0.05, 0.14, decimals=2, default=0.095, space="buy") + # pourcentage sma à dépasser + # buy_sma_percent = DecimalParameter(0.95, 1.05, decimals=2, default=0.98, space="buy") + # volume à atteindre + # buy_volume = DecimalParameter(0, 50, decimals=1, default=0, space="buy") + + # buy_close = DecimalParameter(0.95, 1.05, decimals=2, default=0, space="buy") + # buy_sma = IntParameter(1, 40, default=10, space="buy") + + # buy_rsi = IntParameter(20, 40, default=30, space="buy") + # buy_adx_enabled = BooleanParameter(default=True, space="buy") + # buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy") + # buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy") + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + 'rsi': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "ADX": { + 'adx': {'color': 'white'}, + 'minus_dm': {'color': 'blue'}, + 'plus_dm': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['adx'] = ta.ADX(dataframe) + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # # Aroon, Aroon Oscillator + # aroon = ta.AROON(dataframe) + # dataframe['aroonup'] = aroon['aroonup'] + # dataframe['aroondown'] = aroon['aroondown'] + # dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + # dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + # dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + # dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + # conditions = [] + # conditions.append(dataframe['bb_width'] >= self.buy_bollinger.value) + # + # if conditions: + dataframe.loc[ + ( + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'] > dataframe['open'] * 1.04) + # (dataframe['bb_width'] >= dataframe['bb_width'].shift(4)) + ) | ( + (dataframe['close'] > dataframe['bb_upperband']) & + (dataframe['close'].shift(1) > dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) > dataframe['open'].shift(2)) + # (dataframe['bb_width'] >= dataframe['bb_width'].shift(4)) + # (dataframe['close'] > dataframe['open'].shift(2) * 1.04) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] < dataframe['open']) & + (dataframe['close'].shift(1) < dataframe['open'].shift(1)) & + (dataframe['close'].shift(2) < dataframe['open'].shift(2)) & + (dataframe['close'] < dataframe['bb_lowerband']) & + (((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe[ + 'bb_lowerband']) >= 0.02) + # (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025) + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick42.py b/StrategyPierrick42.py new file mode 100644 index 0000000..fdd950c --- /dev/null +++ b/StrategyPierrick42.py @@ -0,0 +1,189 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick42(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.04, True, False) + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.065) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (dataframe['close'] <= dataframe['sma200_95']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick43.py b/StrategyPierrick43.py new file mode 100644 index 0000000..09813e5 --- /dev/null +++ b/StrategyPierrick43.py @@ -0,0 +1,189 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick43(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.005 + trailing_stop_positive_offset = 0.02 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'} + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.04, True, False) + dataframe.loc[ + ( + ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (dataframe['close'] <= dataframe['sma200_95']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick44.py b/StrategyPierrick44.py new file mode 100644 index 0000000..ee86eb5 --- /dev/null +++ b/StrategyPierrick44.py @@ -0,0 +1,229 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick44(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + + condition = np.where(value >= 1.04, True, False) + p = 100 * ((dataframe['sma500'] - dataframe['sma500'].shift(60)) / dataframe['sma500']) + # for k, v in p.iteritems(): + # # print(k, v) + # value = v + # hausse = np.where(value >= 0.1, True, False) + # print("hausse=", hausse, "value=", value) + dataframe.loc[ + ( + ( + # hausse & + ( + (dataframe['close'] < dataframe['bb_lowerband']) | + (dataframe['close'].shift(1) < dataframe['bb_lowerband'].shift(1)) | + (dataframe['close'].shift(2) < dataframe['bb_lowerband'].shift(2)) | + (dataframe['close'].shift(3) < dataframe['bb_lowerband'].shift(3)) | + (dataframe['close'].shift(4) < dataframe['bb_lowerband'].shift(4)) | + (dataframe['close'].shift(5) < dataframe['bb_lowerband'].shift(5)) | + (dataframe['close'].shift(6) < dataframe['bb_lowerband'].shift(6)) | + (dataframe['close'].shift(7) < dataframe['bb_lowerband'].shift(7)) + ) + & (dataframe['bb_width'] >= 0.065) + & (dataframe['bb_upperband'] < dataframe['bb_upperband'].shift(1)) + # & ( + # ((dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_lowerband'] >= 0.4) + # # ( + # # (dataframe['bb_width'] >= 0.04) & condition + # # ) + # ) + # & (dataframe['close'] <= dataframe['sma200_98']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick5.py b/StrategyPierrick5.py new file mode 100644 index 0000000..dacadc5 --- /dev/null +++ b/StrategyPierrick5.py @@ -0,0 +1,222 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick5(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + condition = np.where(value >= 1.04, True, False) + + p = dataframe['sma100'].shift(100) - dataframe['sma100'] + for k, v in p.iteritems(): + # print(k, v) + value = v + hausse = np.where(value < 0, True, False) + dataframe.loc[ + ( + ( + hausse & + (dataframe['close'] < dataframe['bb_lowerband']) & + (dataframe['bb_width'] >= 0.065) & + (dataframe['volume'] > 0) + ) | ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (not hausse) + & (dataframe['close'] <= dataframe['sma200_95']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick51.py b/StrategyPierrick51.py new file mode 100644 index 0000000..1bd2943 --- /dev/null +++ b/StrategyPierrick51.py @@ -0,0 +1,222 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick51(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + condition = np.where(value >= 1.04, True, False) + + p = dataframe['sma100'].shift(60) - dataframe['sma100'] + for k, v in p.iteritems(): + # print(k, v) + value = v + hausse = np.where(value < 0, True, False) + dataframe.loc[ + ( + ( + hausse & + (dataframe['close'] < dataframe['bb_lowerband']) & + (dataframe['bb_width'] >= 0.065) & + (dataframe['volume'] > 0) + ) | ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (not hausse) + & (dataframe['close'] <= dataframe['sma200_95']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/StrategyPierrick52.py b/StrategyPierrick52.py new file mode 100644 index 0000000..929e468 --- /dev/null +++ b/StrategyPierrick52.py @@ -0,0 +1,222 @@ +# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +import math + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +# This class is a sample. Feel free to customize it. +class StrategyPierrick52(IStrategy): + # Strategy interface version - allow new iterations of the strategy interface. + # Check the documentation or the Sample strategy to get the latest version. + INTERFACE_VERSION = 2 + + # ROI table: + minimal_roi = { + # "0": 0.015 + "0": 0.5 + } + + # Stoploss: + stoploss = -1 + trailing_stop = True + trailing_stop_positive = 0.001 + trailing_stop_positive_offset = 0.0175 # 0.015 + trailing_only_offset_is_reached = True + + # max_open_trades = 3 + + # Optimal ticker interval for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'bb_lowerband': {'color': 'white'}, + 'bb_upperband': {'color': 'white'}, + 'sma100': {'color': 'green'}, + 'sma500': {'color': 'blue'}, + 'sma500_97': {'color': 'gray'}, + 'sma200_98': {'color': 'yellow'}, + 'sma200_95': {'color': 'cyan'}, + # 'volatility_dcp': {'color': '#c58893'} + + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "BB": { + 'bb_width': {'color': 'white'}, + }, + "Aaron": { + 'aroonup': {'color': 'blue'}, + 'aroondown': {'color': 'red'} + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # MACD + # macd = ta.MACD(dataframe) + # dataframe['macd'] = macd['macd'] + # dataframe['macdsignal'] = macd['macdsignal'] + # dataframe['macdhist'] = macd['macdhist'] + + # # Plus Directional Indicator / Movement + dataframe['plus_dm'] = ta.PLUS_DM(dataframe) + dataframe['plus_di'] = ta.PLUS_DI(dataframe) + + # Minus Directional Indicator / Movement + dataframe['minus_dm'] = ta.MINUS_DM(dataframe) + dataframe['minus_di'] = ta.MINUS_DI(dataframe) + + dataframe['min'] = ta.MIN(dataframe) + dataframe['max'] = ta.MAX(dataframe) + + # Aroon, Aroon Oscillator + aroon = ta.AROON(dataframe) + dataframe['aroonup'] = aroon['aroonup'] + dataframe['aroondown'] = aroon['aroondown'] + dataframe['aroonosc'] = ta.AROONOSC(dataframe) + + # RSI + # dataframe['rsi'] = ta.RSI(dataframe) + + # # EMA - Exponential Moving Average + # dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3) + # dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + # dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + # dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21) + # dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50) + dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100) + + # # SMA - Simple Moving Average + # dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3) + # dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10) + # dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21) + # dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100) + dataframe['sma200'] = ta.SMA(dataframe, timeperiod=200) + dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95 + dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98 + dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500) + dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9 + dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95 + dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2 + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + # 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 + # ) + + # dataframe['bb_lower_reg'] = dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + value = 0 + p = dataframe['close'].shift(20) / dataframe['close'] + for k, v in p.iteritems(): + # print(k, v) + value = v + condition = np.where(value >= 1.04, True, False) + + p = dataframe['sma100'].shift(30) - dataframe['sma100'] + for k, v in p.iteritems(): + # print(k, v) + value = v + hausse = np.where(value < 0, True, False) + dataframe.loc[ + ( + ( + hausse & + (dataframe['close'] < dataframe['bb_lowerband']) & + (dataframe['bb_width'] >= 0.065) & + (dataframe['volume'] > 0) + ) | ( + (dataframe['close'] < dataframe['bb_lowerband']) + & ( + (dataframe['bb_width'] >= 0.095) | + ( + (dataframe['bb_width'] >= 0.04) & condition + ) + ) + & (not hausse) + & (dataframe['close'] <= dataframe['sma200_95']) + & (dataframe['volume'] > 0) + ) + ), + 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + + ), + + 'sell'] = 1 + return dataframe diff --git a/Supertrend.py b/Supertrend.py new file mode 100644 index 0000000..cfc0679 --- /dev/null +++ b/Supertrend.py @@ -0,0 +1,177 @@ +""" +Supertrend strategy: +* Description: Generate a 3 supertrend indicators for 'buy' strategies & 3 supertrend indicators for 'sell' strategies + Buys if the 3 'buy' indicators are 'up' + Sells if the 3 'sell' indicators are 'down' +* Author: @juankysoriano (Juan Carlos Soriano) +* github: https://github.com/juankysoriano/ + +*** NOTE: This Supertrend strategy is just one of many possible strategies using `Supertrend` as indicator. It should on any case used at your own risk. + It comes with at least a couple of caveats: + 1. The implementation for the `supertrend` indicator is based on the following discussion: https://github.com/freqtrade/freqtrade-strategies/issues/30 . Concretelly https://github.com/freqtrade/freqtrade-strategies/issues/30#issuecomment-853042401 + 2. The implementation for `supertrend` on this strategy is not validated; meaning this that is not proven to match the results by the paper where it was originally introduced or any other trusted academic resources +""" + +import logging +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy.parameters import IntParameter +from pandas import DataFrame +import talib.abstract as ta +import numpy as np + +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] + }) diff --git a/Swing-High-To-Sky.py b/Swing-High-To-Sky.py new file mode 100644 index 0000000..c2d1444 --- /dev/null +++ b/Swing-High-To-Sky.py @@ -0,0 +1,110 @@ +""" +author = "Kevin Ossenbrück" +copyright = "Free For Use" +credits = ["Bloom Trading, Mohsen Hassan"] +license = "MIT" +version = "1.0" +maintainer = "Kevin Ossenbrück" +email = "kevin.ossenbrueck@pm.de" +status = "Live" +""" + +from freqtrade.strategy import IStrategy +from freqtrade.strategy import IntParameter +from functools import reduce +from pandas import DataFrame + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy + + + +# CCI timerperiods and values +cciBuyTP = 72 +cciBuyVal = -175 +cciSellTP = 66 +cciSellVal = -106 + +# RSI timeperiods and values +rsiBuyTP = 36 +rsiBuyVal = 90 +rsiSellTP = 45 +rsiSellVal = 88 + + +class SwingHighToSky(IStrategy): + INTERFACE_VERSION = 2 + + timeframe = '15m' + + stoploss = -0.34338 + + minimal_roi = {"0": 0.27058, "33": 0.0853, "64": 0.04093, "244": 0} + + buy_cci = IntParameter(low=-200, high=200, default=100, space='buy', optimize=True) + buy_cciTime = IntParameter(low=10, high=80, default=20, space='buy', optimize=True) + buy_rsi = IntParameter(low=10, high=90, default=30, space='buy', optimize=True) + buy_rsiTime = IntParameter(low=10, high=80, default=26, space='buy', optimize=True) + + sell_cci = IntParameter(low=-200, high=200, default=100, space='sell', optimize=True) + sell_cciTime = IntParameter(low=10, high=80, default=20, space='sell', optimize=True) + sell_rsi = IntParameter(low=10, high=90, default=30, space='sell', optimize=True) + sell_rsiTime = IntParameter(low=10, high=80, default=26, space='sell', optimize=True) + + # Buy hyperspace params: + buy_params = { + "buy_cci": -175, + "buy_cciTime": 72, + "buy_rsi": 90, + "buy_rsiTime": 36, + } + + # Sell hyperspace params: + sell_params = { + "sell_cci": -106, + "sell_cciTime": 66, + "sell_rsi": 88, + "sell_rsiTime": 45, + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + for val in self.buy_cciTime.range: + dataframe[f'cci-{val}'] = ta.CCI(dataframe, timeperiod=val) + + for val in self.sell_cciTime.range: + dataframe[f'cci-sell-{val}'] = ta.CCI(dataframe, timeperiod=val) + + for val in self.buy_rsiTime.range: + dataframe[f'rsi-{val}'] = ta.RSI(dataframe, timeperiod=val) + + for val in self.sell_rsiTime.range: + dataframe[f'rsi-sell-{val}'] = ta.RSI(dataframe, timeperiod=val) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe[f'cci-{self.buy_cciTime.value}'] < self.buy_cci.value) & + (dataframe[f'rsi-{self.buy_rsiTime.value}'] < self.buy_rsi.value) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe[f'cci-sell-{self.sell_cciTime.value}'] > self.sell_cci.value) & + (dataframe[f'rsi-sell-{self.sell_rsiTime.value}'] > self.sell_rsi.value) + ), + 'sell'] = 1 + + return dataframe diff --git a/TheForce.py b/TheForce.py new file mode 100644 index 0000000..e02c59d --- /dev/null +++ b/TheForce.py @@ -0,0 +1,188 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import IStrategy + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class TheForce(IStrategy): + + INTERFACE_VERSION = 2 + + minimal_roi = { + "30": 0.005, + "15": 0.01, + "0": 0.012 + } + + stoploss = -0.015 + + # Trailing stoploss + trailing_stop = False + # trailing_only_offset_is_reached = False + # trailing_stop_positive = 0.01 + # trailing_stop_positive_offset = 0.0 # Disabled / not configured + + # Optimal timeframe for the strategy. + timeframe = '15m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + + 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) : + """ + 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 + # ------------------------------------ + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe,5,3,3) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + stoch_rsi = ta.STOCHRSI(dataframe) + dataframe['fastd_rsi'] = stoch_rsi['fastd'] + dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe,12,26,1) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # # EMA - Exponential Moving Average + + dataframe['ema5c'] = ta.EMA(dataframe['close'], timeperiod=5) + dataframe['ema5o'] = ta.EMA(dataframe['open'], timeperiod=5) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) : + """ + 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.loc[ + ( + ( + (dataframe['fastk'] >= 20) & (dataframe['fastk'] <= 80) + & + (dataframe['fastd'] >= 20) & (dataframe['fastd'] <= 80) + ) + & + ( + (dataframe['macd'] > dataframe['macd'].shift(1)) + & + (dataframe['macdsignal'] > dataframe['macdsignal'].shift(1)) + ) + & + ( + (dataframe['close'] > dataframe['close'].shift(1)) + ) + & + ( + (dataframe['ema5c'] >= dataframe['ema5o']) + ) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) : + """ + Based on TA indicators, populates the sell 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.loc[ + ( + ( + (dataframe['fastk'] <= 80) + & + (dataframe['fastd'] <= 80) + ) + & + ( + (dataframe['macd'] < dataframe['macd'].shift(1)) + & + (dataframe['macdsignal'] < dataframe['macdsignal'].shift(1)) + ) + & + ( + (dataframe['ema5c'] < dataframe['ema5o']) + ) + + ), + 'sell'] = 1 + return dataframe diff --git a/TheForce_1.py b/TheForce_1.py new file mode 100644 index 0000000..928f07b --- /dev/null +++ b/TheForce_1.py @@ -0,0 +1,188 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy import IStrategy + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class TheForce_1(IStrategy): + + INTERFACE_VERSION = 2 + + minimal_roi = { + "30": 0.005, + "15": 0.01, + "0": 0.012 + } + + stoploss = -0.015 + + # Trailing stoploss + trailing_stop = False + # trailing_only_offset_is_reached = False + # trailing_stop_positive = 0.01 + # trailing_stop_positive_offset = 0.0 # Disabled / not configured + + # Optimal timeframe for the strategy. + timeframe = '5m' + + # 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 = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'tema': {}, + 'sar': {'color': 'white'}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "MACD": { + 'macd': {'color': 'blue'}, + 'macdsignal': {'color': 'orange'}, + }, + "RSI": { + 'rsi': {'color': 'red'}, + } + } + } + + 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) : + """ + 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 + # ------------------------------------ + + # Stochastic Fast + stoch_fast = ta.STOCHF(dataframe,5,3,3) + dataframe['fastd'] = stoch_fast['fastd'] + dataframe['fastk'] = stoch_fast['fastk'] + + # # Stochastic RSI + stoch_rsi = ta.STOCHRSI(dataframe) + dataframe['fastd_rsi'] = stoch_rsi['fastd'] + dataframe['fastk_rsi'] = stoch_rsi['fastk'] + + # MACD + macd = ta.MACD(dataframe,12,26,1) + dataframe['macd'] = macd['macd'] + dataframe['macdsignal'] = macd['macdsignal'] + dataframe['macdhist'] = macd['macdhist'] + + # # EMA - Exponential Moving Average + + dataframe['ema5c'] = ta.EMA(dataframe['close'], timeperiod=5) + dataframe['ema5o'] = ta.EMA(dataframe['open'], timeperiod=5) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) : + """ + 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.loc[ + ( + ( + (dataframe['fastk'] >= 20) & (dataframe['fastk'] <= 80) + & + (dataframe['fastd'] >= 20) & (dataframe['fastd'] <= 80) + ) + & + ( + (dataframe['macd'] > dataframe['macd'].shift(1)) + & + (dataframe['macdsignal'] > dataframe['macdsignal'].shift(1)) + ) + & + ( + (dataframe['close'] > dataframe['close'].shift(1)) + ) + & + ( + (dataframe['ema5c'] >= dataframe['ema5o']) + ) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) : + """ + Based on TA indicators, populates the sell 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.loc[ + ( + ( + (dataframe['fastk'] <= 80) + & + (dataframe['fastd'] <= 80) + ) + & + ( + (dataframe['macd'] < dataframe['macd'].shift(1)) + & + (dataframe['macdsignal'] < dataframe['macdsignal'].shift(1)) + ) + & + ( + (dataframe['ema5c'] < dataframe['ema5o']) + ) + + ), + 'sell'] = 1 + return dataframe diff --git a/Zeus.json b/Zeus.json new file mode 100644 index 0000000..c3c5223 --- /dev/null +++ b/Zeus.json @@ -0,0 +1,34 @@ +{ + "strategy_name": "Zeus", + "params": { + "stoploss": { + "stoploss": -1.0 + }, + "buy": { + "buy_bb_lowerband": 1.02, + "buy_bb_width": 0.09, + "buy_cat": "R", "=R", "R", "=R", " DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_real.value + OPR = self.buy_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] > self.buy_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_bb_width.value) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_real.value + # OPR = self.sell_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_10(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", " 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + # dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + # dataframe['high'], + # dataframe['low'], + # window1=9, + # window2=26, + # visual=False, + # fillna=False + # ) + # KST = ta.trend.KSTIndicator( + # close=dataframe['close'], + # roc1=10, + # roc2=15, + # roc3=20, + # roc4=30, + # window1=10, + # window2=10, + # window3=10, + # window4=15, + # nsig=9, + # fillna=False + # ) + # + # dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_5'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max200_5'] = (dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma10xpct+'] = dataframe['sma10'] * 1.0075 + dataframe['sma10xpct-'] = dataframe['sma10'] * 0.9925 + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # + # dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + # dataframe['min1.1'] = 1.01 * dataframe['min'] + + # dataframe['sar'] = talib.SAR(dataframe) + # # Normalization + # tib = dataframe['trend_ichimoku_base'] + # dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + # tkd = dataframe['trend_kst_diff'] + # dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'].shift(1) <= dataframe['bb_lowerband']) + & (dataframe['open'] <= dataframe['close']) + ), ['buy', 'buy_tag']] = (1, 'buy_lowerband') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['close'] >= dataframe['bb_upperband']) + # ), + # 'sell'] = 1 + return dataframe diff --git a/Zeus_2.json b/Zeus_2.json new file mode 100644 index 0000000..9fec29d --- /dev/null +++ b/Zeus_2.json @@ -0,0 +1,54 @@ +{ + "strategy_name": "Zeus_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_bb_lowerband": 1.02, + "buy_bb_width": 0.15, + "buy_cat": "R", "=R", "R", "=R", " expected_profit) & (last_candle['pct_change_1_1d'] < 0): + # return "exp_profit_down" + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change.value and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + # informative_pairs = [(pair, "5m") for pair in pairs] + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5); + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_real.value + OPR = self.buy_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_real.value + # OPR = self.sell_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "R", + "buy_pct": 0.008, + "buy_pct_1": -0.18, + "buy_pct_3": -0.09, + "buy_pct_5": -0.14, + "buy_real": 0.0919 + }, + "sell": { + "profit_no_change": false, + "profit_old_sma10": false, + "profit_over_rsi": false, + "profit_quick_gain": true, + "profit_quick_gain_3": false, + "profit_quick_lost": false, + "profit_short_loss": true, + "profit_sma10": false, + "profit_sma20": false, + "profit_sma5": false, + "profit_very_old_sma10": true, + "sell_RSI": 79, + "sell_RSI2": 82, + "sell_RSI2_percent": 0.006, + "sell_RSI3": 70, + "sell_candels": 43, + "sell_percent": 0.02, + "sell_percent3": 0.013, + "sell_profit_no_change": 0.015, + "sell_profit_percent10": 0.0, + "sell_too_old_day": 2, + "sell_too_old_percent": 0.013 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-02 15:57:05.428547+00:00" +} \ No newline at end of file diff --git a/Zeus_2_1.py b/Zeus_2_1.py new file mode 100644 index 0000000..fe86110 --- /dev/null +++ b/Zeus_2_1.py @@ -0,0 +1,356 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class Zeus_2_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_params = { + "buy_cat": "R", "=R", "R", "=R", " expected_profit) & (last_candle['pct_change_1_1d'] < 0): + # return "exp_profit_down" + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change.value and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + # informative_pairs = [(pair, "5m") for pair in pairs] + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5); + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['sar'] = talib.SAR(dataframe) + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_real.value + OPR = self.buy_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_real.value + # OPR = self.sell_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "R", "=R", "R", "=R", " expected_profit) & (last_candle['pct_change_1_1d'] < 0): + # return "exp_profit_down" + + if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_no_change.value and (current_profit > self.sell_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value): + return "quick_gain_param" + + if self.profit_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \ + (last_candle['percent'] < - self.sell_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + # Assign tf to each pair so they can be downloaded and cached for strategy. + # informative_pairs = [(pair, "5m") for pair in pairs] + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1w') for pair in pairs] + + # Optionally Add additional "static" pairs + # informative_pairs = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5); + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['sar'] = talib.SAR(dataframe) + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_real.value + OPR = self.buy_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_pct_3.value) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_real.value + # OPR = self.sell_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "R", "=R", "R", "=R", " expected_profit) & (last_candle['pct_change_1_1d'] < 0): + # return "exp_profit_down" + + if (current_profit >= - self.sell_b_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_b_too_old_day.value)\ + & ((current_time - trade.open_date_utc).days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_b_too_old_day.value * 2)\ + & ((current_time - trade.open_date_utc).days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5); + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " self.buy_b_pct_1.value) + & (dataframe['pct_change_3_1d'] > self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + , + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_b_real.value + # OPR = self.sell_b_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.001, + "sell_b_profit_percent10": 0.0016, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 17:09:52.289232+00:00" +} \ No newline at end of file diff --git a/Zeus_4.jsonFirst b/Zeus_4.jsonFirst new file mode 100644 index 0000000..36eadf3 --- /dev/null +++ b/Zeus_4.jsonFirst @@ -0,0 +1,85 @@ +{ + "strategy_name": "Zeus_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_h_bb_lowerband": 1.04, + "buy_h_bb_width": 0.09, + "buy_h_cat": ">R", + "buy_h_pct": 0.008, + "buy_h_pct_1": -0.18, + "buy_h_pct_3": -0.09, + "buy_h_pct_5": -0.14, + "buy_h_real": 0.0919, + + "buy_b_bb_lowerband": 1.02, + "buy_b_bb_width": 0.15, + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", "= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + else: + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5); + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == " 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + + & (dataframe['volume10'] * dataframe['close'] / 1000 >= 10) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # conditions = [] + # IND = 'trend_kst_diff' + # REAL = self.sell_h_real.value + # OPR = self.sell_h_cat.value + # DFIND = dataframe[IND] + # # print(DFIND.mean()) + # + # if OPR == ">R": + # conditions.append(DFIND > REAL) + # elif OPR == "=R": + # conditions.append(np.isclose(DFIND, REAL)) + # elif OPR == "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_5.py b/Zeus_5.py new file mode 100644 index 0000000..de03d98 --- /dev/null +++ b/Zeus_5.py @@ -0,0 +1,1121 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class Zeus_5(IStrategy): + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + info_previous_5_candle = informative.iloc[-5].squeeze() + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + btc_previous_5_candle = btc.iloc[-5].squeeze() + + # if self.stop_buy_for_all is True: + # if (btc_last_candle['percent20'] > 0) & (btc_last_candle['min200'] == btc_previous_5_candle['min200']): # self.btc_allow_to_buy.value: + # self.stop_buy_for_all = False + # logger.info("1 - BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + # else: + # logger.info("1 - BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + # return False + + # if self.stop_buying.get(pair, None) is None: + # print("enable buying tag", pair) + # self.stop_buying[pair] = False + # + # if self.stop_buying[pair] is True: + # if (info_last_candle['min200'] == info_previous_5_candle['min200']): + # # if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + # logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + # self.stop_buying[pair] = False + # + # if self.stop_buying[pair]: + # allow_to_buy = False + # logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + # else: + # logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + minutes = (current_time - trade.open_date_utc).seconds / 60 + days = (current_time - trade.open_date_utc).days + candels_past = int(minutes / 5) + + positive = 0 + negative = 0 + if (candels_past > 12) & (candels_past <= 24): + # print(trade.pair, trade.open_rate, candels_past, minutes, (current_time - trade.open_date_utc).seconds) + sum_percent = 0 + for candel in range(0, candels_past): + df = dataframe.iloc[candel - candels_past].squeeze() + rate = (df['close'] - trade.open_rate) / trade.open_rate + if df['percent'] < 0: + negative = negative + 1 + else: + positive = positive + 1 + sum_percent = sum_percent + df['percent'] + # print(candels_past - candel, df['date'], rate, df['percent'], sum_percent) + # print(trade.pair, "positive=", positive, "negative=", negative, "pourcent=", + # positive / (positive + negative), + # "sum_percent=", sum_percent) + ###### + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + # if ( + # (btc_last_candle['percent'] < -0.02) | (btc_last_candle['percent5'] < -0.04)) & (current_profit > -0.03): + # self.stop_buy_for_all = True + # return "btc_fall" + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma10xpct+'] = dataframe['sma10'] * 1.015 + dataframe['sma10xpct-'] = dataframe['sma10'] * 0.985 + + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / 4)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + # test = dataframe['trend_ichimoku_base'].tail(200) + # dataframe['trend_ichimoku_base_2'] = (test - test.min()) / (test.max() - test.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + # test = dataframe.copy().tail(200) + # test[buy_crossed_indicator0] = gene_calculator(test, buy_crossed_indicator0) + # test[buy_indicator0] = gene_calculator(test, buy_indicator0) + # dataframe["cond2"] = test[buy_indicator0].div(test[buy_crossed_indicator0]) + + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) # self.buy_h_pct_5.value) + # & (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) # self.buy_b_pct_5.value) + # & (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + # if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + # & (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + # & (dataframe['percent_4h'] > 0) + # & (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + # if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) # self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + # if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + #  & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + # & (dataframe['percent_4h'] > 0) + # & (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + & (dataframe['percent'].shift(1) > -0.003) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + # (dataframe['min_max50'] >= 0.03) + # & (dataframe['bb_width'] >= 0.02) + (dataframe['cond1'].shift(2) <= 0.75) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 72) + & (dataframe['close'] < dataframe['min50'] * 1.006) + & (dataframe['min_max_close'] > 2) + # & (dataframe['volume'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent'] > -0.003) + # & (dataframe['percent'].shift(1) > -0.003) + # & (dataframe['percent5'] > -0.003) + # & (dataframe['min200'].shift(2) <= dataframe['min200']) + # & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006) & (last_candle['min_max_close'] > 2) + # print(reduce(lambda x, y: x & y, condition)) + if (0 < count_of_buys <= self.max_dca_orders) & (current_profit < -0.15) & (condition): + try: + print(last_candle['cond1'],last_candle['bb_width'],last_candle['rsi'],last_candle['close'],last_candle['percent5'], + last_candle['trend_ichimoku_base']) + # This returns first order stake size + stake_amount = self.config['stake_amount'] * (count_of_buys + 1) # filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * 1.5 #pow(2, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + "---------------------") + print("count_of_buys = " + str(count_of_buys)) + print("stake_amount = " + str(stake_amount)) + return stake_amount + except Exception as exception: + print("exception") + return None + return None diff --git a/Zeus_5_1.json b/Zeus_5_1.json new file mode 100644 index 0000000..e7a9551 --- /dev/null +++ b/Zeus_5_1.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_5_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.08, + "buy_rsi": 70, + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01, + "sell_rsi5_1h": 41 + }, + "protection": { + "btc_allow_to_buy": 0.0, + "btc_fall_1": -0.03, + "btc_fall_3": -0.06, + "btc_fall_5": -0.09, + "btc_sell_all_profit": -0.42 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_5_1.py b/Zeus_5_1.py new file mode 100644 index 0000000..443bc82 --- /dev/null +++ b/Zeus_5_1.py @@ -0,0 +1,1072 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_5_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " None: + inf_tf = '5m' + pairs = self.dp.current_whitelist() + print("Calcul des pairs informatives") + for pairname in pairs: + self.stop_buying[pairname] = True + print("Fin Calcul des pairs informatives") + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buy_for_all is True: + if info_last_candle['pct_change_1_1d'] > self.btc_allow_to_buy.value: + self.stop_buy_for_all = False + logger.info("1 -BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + else: + logger.info("1 -BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + return False + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + # if (info_last_candle['rsi_1h'] < self.protection_RSI_enable.value) & (self.stop_buying[pair] is True): + # print("Enable buying", pair) + # self.stop_buying[pair] = False + + # if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] > 20) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']) \ + # & (info_last_candle['max_rsi_1h'] < 50): + # print("2 - Enable buying", pair, info_last_candle['date'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + if self.stop_buying[pair] is True: + if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + # , (info_last_candle['trend_ichimoku_base'], + # (info_last_candle['close'] < info_last_candle['sma10']), + # (info_previous_last_candle['sma10'], info_last_candle['sma10']))) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (self.stop_buy_for_all is True) & (current_profit < self.btc_sell_all_profit.value): + return "btc_fall" + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if self.stop_buying[pair] is False: + if (last_candle['rsi5'] < 16): + logger.info("0 - Disable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = True + if (current_profit > 0): + return "stop_buying" + + if self.stop_buying[pair] is True: + if (last_candle['rsi5'] > 20) & (last_candle['percent10'] > 0): + logger.info("1 - Enable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + # print("1 - Enable buying ", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = False + + + if (days < 10) & ((btc_last_candle['percent5'] < self.btc_fall_5.value) | (btc_last_candle['percent3'] < self.btc_fall_3.value) | ( + btc_last_candle['percent'] < self.btc_fall_1.value)): + self.stop_buy_for_all = True + return "btc_fall" + + max_percent = last_candle['bb_width'] / 4 #0.005 + max_profit = last_candle['bb_width'] * 3 / 4 # 0.015 + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > max_profit) & ((last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / 4)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + # dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + # dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + # dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + # dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = True + #if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['cond1'] <= 1) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma20']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['min'] * 1.005) + # & (dataframe['moy200_12'] == dataframe['min200']) + # & (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'] >= -0.005) + # + # ), ['buy', 'buy_tag']] = (1, 'buy_near_m50') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + # & (dataframe['close'] < dataframe['min50'] * 1.01) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + # (dataframe['min_max50'] >= 0.03) + # & (dataframe['bb_width'] >= 0.02) + (dataframe['cond1'].shift(2) <= 1.2) + & (dataframe['rsi'] < 72) + & (dataframe['close'] < dataframe['min50'] * 1.005) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_5_2.ALGOjson b/Zeus_5_2.ALGOjson new file mode 100644 index 0000000..768b7b1 --- /dev/null +++ b/Zeus_5_2.ALGOjson @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_5_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_0_distance": 0.09, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.51, + "buy_2_bb_lower_5": 0.28, + "buy_2_distance": 0.1, + "buy_2_percent20": -0.1, + "buy_3_bb_lower_5": 0.19, + "buy_3_distance": 0.01, + "buy_3_percent20": -0.1, + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.15, + "buy_b_cat": ">R", + "buy_b_pct": 0.002, + "buy_b_pct_1": 0.2, + "buy_b_pct_3": -0.19, + "buy_b_pct_5": 0.1, + "buy_b_real": 0.243, + "buy_b_sma": "sma5_1d", + "buy_b_sma_close": "sma5_1d", + "buy_base": 0.2, + "buy_decalage0": 7, + "buy_decalage2": 7, + "buy_decalage3": 6, + "buy_decalage_deb_0": 0, + "buy_decalage_deb_2": 2, + "buy_decalage_deb_3": 3, + "buy_h_bb_lowerband": 1.04, + "buy_h_bb_width": 0.15, + "buy_h_cat": "=R", + "buy_h_pct": 0.015, + "buy_h_pct_1": 0.16, + "buy_h_pct_3": 0.19, + "buy_h_pct_5": 0.17, + "buy_h_real": 0.9762, + "buy_h_sma": "sma10_1d", + "buy_h_sma_close": "sma3_1d", + "buy_min_horizon": 70, + "buy_real_num0": 0.51, + "buy_real_num1": 0.55, + "buy_real_num2": 1.35, + "buy_rsi": 37, + "decalage_b": 3, + "decalage_h": 3 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 5, + "protection_lost_percent": 0.06 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-28 19:28:12.187097+00:00" +} \ No newline at end of file diff --git a/Zeus_5_2.BTCjson b/Zeus_5_2.BTCjson new file mode 100644 index 0000000..77a2d2a --- /dev/null +++ b/Zeus_5_2.BTCjson @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_5_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_0_distance": 0.0, + "buy_0_percent20": 0.05, + "buy_1_bb_lower_5": 0.08, + "buy_2_bb_lower_5": 0.24, + "buy_2_distance": -0.09, + "buy_2_percent20": 0.05, + "buy_3_bb_lower_5": 0.01, + "buy_3_distance": 0.07, + "buy_3_percent20": -0.02, + "buy_b_bb_lowerband": 1.02, + "buy_b_bb_width": 0.12, + "buy_b_cat": ">R", + "buy_b_pct": 0.015, + "buy_b_pct_1": 0.03, + "buy_b_pct_3": 0.14, + "buy_b_pct_5": 0.19, + "buy_b_real": 0.5889, + "buy_b_sma": "sma5_1d", + "buy_b_sma_close": "sma10_1d", + "buy_base": 0.13, + "buy_decalage0": 6, + "buy_decalage2": 7, + "buy_decalage3": 8, + "buy_decalage_deb_0": 3, + "buy_decalage_deb_2": 2, + "buy_decalage_deb_3": 1, + "buy_h_bb_lowerband": 1.0, + "buy_h_bb_width": 0.05, + "buy_h_cat": ">R", + "buy_h_pct": 0.007, + "buy_h_pct_1": 0.12, + "buy_h_pct_3": 0.1, + "buy_h_pct_5": -0.07, + "buy_h_real": 0.2931, + "buy_h_sma": "sma10_1d", + "buy_h_sma_close": "sma3_1d", + "buy_min_horizon": 61, + "buy_real_num0": 0.15, + "buy_real_num1": 0.81, + "buy_real_num2": 0.04, + "buy_rsi": 46, + "decalage_b": 1, + "decalage_h": 2 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 5, + "protection_lost_percent": 0.06 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-28 18:36:28.951431+00:00" +} \ No newline at end of file diff --git a/Zeus_5_2.json b/Zeus_5_2.json new file mode 100644 index 0000000..6fad82b --- /dev/null +++ b/Zeus_5_2.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_5_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.08, + "buy_rsi": 70, + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01, + "sell_rsi5_1h": 41 + }, + "protection": { + "btc_allow_to_buy": 0.0, + "btc_fall_1": -0.03, + "btc_fall_3": -0.06, + "btc_fall_5": -0.09, + "btc_sell_all_profit": -0.42 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-28 20:13:07.504171+00:00" +} \ No newline at end of file diff --git a/Zeus_5_2.py b/Zeus_5_2.py new file mode 100644 index 0000000..1908c26 --- /dev/null +++ b/Zeus_5_2.py @@ -0,0 +1,1104 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_5_2(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " None: + inf_tf = '5m' + pairs = self.dp.current_whitelist() + print("Calcul des pairs informatives") + for pairname in pairs: + self.stop_buying[pairname] = True + print("Fin Calcul des pairs informatives") + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buy_for_all is True: + if info_last_candle['pct_change_1_1d'] > self.btc_allow_to_buy.value: + self.stop_buy_for_all = False + logger.info("1 -BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + else: + logger.info("1 -BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + return False + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + # if (info_last_candle['rsi_1h'] < self.protection_RSI_enable.value) & (self.stop_buying[pair] is True): + # print("Enable buying", pair) + # self.stop_buying[pair] = False + + # if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] > 20) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']) \ + # & (info_last_candle['max_rsi_1h'] < 50): + # print("2 - Enable buying", pair, info_last_candle['date'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + if self.stop_buying[pair] is True: + if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + # , (info_last_candle['trend_ichimoku_base'], + # (info_last_candle['close'] < info_last_candle['sma10']), + # (info_previous_last_candle['sma10'], info_last_candle['sma10']))) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (self.stop_buy_for_all is True) & (current_profit < self.btc_sell_all_profit.value): + return "btc_fall" + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if self.stop_buying[pair] is False: + if (last_candle['rsi5'] < 16): + logger.info("0 - Disable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = True + if (current_profit > 0): + return "stop_buying" + + if self.stop_buying[pair] is True: + if (last_candle['rsi5'] > 20) & (last_candle['percent10'] > 0): + logger.info("1 - Enable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + # print("1 - Enable buying ", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = False + + + if (days < 10) & ((btc_last_candle['percent5'] < self.btc_fall_5.value) | (btc_last_candle['percent3'] < self.btc_fall_3.value) | ( + btc_last_candle['percent'] < self.btc_fall_1.value)): + self.stop_buy_for_all = True + return "btc_fall" + + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.0 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ((last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / 4)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ((dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + # dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + # dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + # dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + # dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = True + #if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + # & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['cond1'] <= 1) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma20']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['min'] * 1.005) + # & (dataframe['moy200_12'] == dataframe['min200']) + # & (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'] >= -0.005) + # + # ), ['buy', 'buy_tag']] = (1, 'buy_near_m50') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + & (dataframe['volume'] * dataframe['close'] / 1000 >= 10) + & (dataframe['percent'] > -0.003) + & (dataframe['percent'].shift(1) > -0.003) + # & (dataframe['percent5'] > -0.025) + + # & (dataframe['close'] / dataframe['close'].shift(288) < 1.05) + # & (dataframe['percent'] > -0.005) + # & (dataframe['min_max50'] >= 0.02) + # & (dataframe['min200'].shift(2) <= dataframe['min200']) + # & (dataframe['max200'] / dataframe['min50'] >= 1.02) + # & (dataframe['bb_lowerband'].shift(1) <= dataframe['bb_lowerband']) + # & (dataframe['close'] < dataframe['min50'] * 1.01) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + # (dataframe['min_max50'] >= 0.03) + # & (dataframe['bb_width'] >= 0.02) + (dataframe['cond1'].shift(2) <= 1.2) + & (dataframe['rsi'] < 72) + & (dataframe['close'] < dataframe['min50'] * 1.006) + & (dataframe['min_max_close'] > 1) + & (dataframe['volume'] * dataframe['close'] / 1000 >= 10) + & (dataframe['percent'] > -0.003) + & (dataframe['percent'].shift(1) > -0.003) + # & (dataframe['percent5'] > -0.025) + # & (dataframe['min200'].shift(2) <= dataframe['min200']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['close'] / dataframe['close'].shift(288) < 1.05) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_5_3.json b/Zeus_5_3.json new file mode 100644 index 0000000..9c4df7e --- /dev/null +++ b/Zeus_5_3.json @@ -0,0 +1,105 @@ +{ + "strategy_name": "Zeus_5_3", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": {}, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_5_3.py b/Zeus_5_3.py new file mode 100644 index 0000000..5ca8139 --- /dev/null +++ b/Zeus_5_3.py @@ -0,0 +1,1144 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + + +class Zeus_5_3(IStrategy): + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + info_previous_5_candle = informative.iloc[-5].squeeze() + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + btc_previous_5_candle = btc.iloc[-5].squeeze() + + # if self.stop_buy_for_all is True: + # if (btc_last_candle['percent20'] > 0) & (btc_last_candle['min200'] == btc_previous_5_candle['min200']): # self.btc_allow_to_buy.value: + # self.stop_buy_for_all = False + # logger.info("1 - BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + # else: + # logger.info("1 - BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + # return False + + # if self.stop_buying.get(pair, None) is None: + # print("enable buying tag", pair) + # self.stop_buying[pair] = False + # + # if self.stop_buying[pair] is True: + # if (info_last_candle['min200'] == info_previous_5_candle['min200']): + # # if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + # logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + # self.stop_buying[pair] = False + # + # if self.stop_buying[pair]: + # allow_to_buy = False + # logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + # else: + # logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + minutes = (current_time - trade.open_date_utc).seconds / 60 + days = (current_time - trade.open_date_utc).days + candels_past = int(minutes / 5) + + positive = 0 + negative = 0 + if (candels_past > 12) & (candels_past <= 24): + # print(trade.pair, trade.open_rate, candels_past, minutes, (current_time - trade.open_date_utc).seconds) + sum_percent = 0 + for candel in range(0, candels_past): + df = dataframe.iloc[candel - candels_past].squeeze() + rate = (df['close'] - trade.open_rate) / trade.open_rate + if df['percent'] < 0: + negative = negative + 1 + else: + positive = positive + 1 + sum_percent = sum_percent + df['percent'] + # print(candels_past - candel, df['date'], rate, df['percent'], sum_percent) + # print(trade.pair, "positive=", positive, "negative=", negative, "pourcent=", + # positive / (positive + negative), + # "sum_percent=", sum_percent) + ###### + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + # if ( + # (btc_last_candle['percent'] < -0.02) | (btc_last_candle['percent5'] < -0.04)) & (current_profit > -0.03): + # self.stop_buy_for_all = True + # return "btc_fall" + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value) \ + & (days < self.sell_h_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2) \ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + # if not self.config['runmode'].value == 'hyperopt': + # dataframe = self.calculateIndicators(dataframe, metadata) + return dataframe + + def calculateIndicators(self, dataframe, metadata): + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma10xpct+'] = dataframe['sma10'] * 1.015 + dataframe['sma10xpct-'] = dataframe['sma10'] * 0.985 + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / 4)) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib - tib.min()) / (tib.max() - tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd - tkd.min()) / (tkd.max() - tkd.min()) + # test = dataframe['trend_ichimoku_base'].tail(200) + # dataframe['trend_ichimoku_base_2'] = (test - test.min()) / (test.max() - test.min()) + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # test = dataframe.copy().tail(200) + # test[buy_crossed_indicator0] = gene_calculator(test, buy_crossed_indicator0) + # test[buy_indicator0] = gene_calculator(test, buy_indicator0) + # dataframe["cond2"] = test[buy_indicator0].div(test[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + # pprint_df(dataframe['date'], dataframe['cond1'], dataframe['trend_ichimoku_base']) + # pprint_df(dataframe) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # if self.config['runmode'].value == 'hyperopt': + + dataframe = self.calculateIndicators(dataframe, metadata) + + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) # self.buy_h_pct_5.value) + # & (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) # self.buy_b_pct_5.value) + # & (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + # if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + # & (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + # & (dataframe['percent_4h'] > 0) + # & (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + # if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) # self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + # if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + #  & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + # & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + # & (dataframe['percent_4h'] > 0) + # & (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['cond1'] <= 1) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma20']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['min'] * 1.005) + # & (dataframe['moy200_12'] == dataframe['min200']) + # & (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'] >= -0.005) + # + # ), ['buy', 'buy_tag']] = (1, 'buy_near_m50') + + coef = 4 + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + # & (dataframe['volume'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent'] > - 0.003) + & (dataframe['percent'].shift(1) > -0.003) + # & (dataframe['percent5'] > -0.025) + # & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + # & (dataframe['close'] / dataframe['close'].shift(288) < 1.05) + # & (dataframe['percent'] > -0.005) + # & (dataframe['min_max50'] >= 0.02) + # & (dataframe['min200'].shift(2) <= dataframe['min200']) + # & (dataframe['max200'] / dataframe['min50'] >= 1.02) + # & (dataframe['bb_lowerband'].shift(1) <= dataframe['bb_lowerband']) + # & (dataframe['close'] < dataframe['min50'] * 1.01) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + # (dataframe['min_max50'] >= 0.03) + # & (dataframe['bb_width'] >= 0.02) + (dataframe['cond1'].shift(2) <= 0.75) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 72) + & (dataframe['close'] < dataframe['min50'] * 1.006) + & (dataframe['min_max_close'] > 2) + # & (dataframe['volume'] * dataframe['close'] / 1000 >= 10) + # & (dataframe['percent'] > -0.003) + # & (dataframe['percent'].shift(1) > -0.003) + # & (dataframe['percent5'] > -0.003) + # & (dataframe['min200'].shift(2) <= dataframe['min200']) + # & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006) & (last_candle['min_max_close'] > 2) + # print(reduce(lambda x, y: x & y, condition)) + if (0 < count_of_buys <= self.max_dca_orders) & (current_profit < -0.1) & (condition): + try: + print(last_candle['cond1'],last_candle['bb_width'],last_candle['rsi'],last_candle['close'],last_candle['percent5'], + last_candle['trend_ichimoku_base']) + # This returns first order stake size + stake_amount = self.config['stake_amount'] # filled_buys[0].cost + # This then calculates current safety order size + stake_amount = stake_amount * 1.5 #pow(2, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + "---------------------") + print("count_of_buys = " + str(count_of_buys)) + print("stake_amount = " + str(stake_amount)) + return stake_amount + except Exception as exception: + print("exception") + return None + return None diff --git a/Zeus_6.json b/Zeus_6.json new file mode 100644 index 0000000..3467653 --- /dev/null +++ b/Zeus_6.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.08, + "buy_rsi": 70, + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01, + "sell_rsi5_1h": 41 + }, + "protection": { + "btc_allow_to_buy": 0.0, + "btc_fall_1": -0.01, + "btc_fall_3": -0.02, + "btc_fall_5": -0.03, + "btc_sell_all_profit": -0.42 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_6.json2 b/Zeus_6.json2 new file mode 100644 index 0000000..c78edc1 --- /dev/null +++ b/Zeus_6.json2 @@ -0,0 +1,111 @@ +{ + "strategy_name": "Zeus_6", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_0_distance": 0.01, + "buy_0_percent20": -0.1, + "buy_1_bb_lower_5": 0.32, + "buy_2_bb_lower_5": 0.28, + "buy_2_distance": -0.05, + "buy_2_percent20": -0.09, + "buy_3_bb_lower_5": 0.0, + "buy_3_distance": 0.1, + "buy_3_percent20": 0.09, + "buy_b_bb_lowerband": 1.0, + "buy_b_bb_width": 0.07, + "buy_b_cat": "=R", + "buy_b_pct": 0.012, + "buy_b_pct_1": -0.19, + "buy_b_pct_3": 0.19, + "buy_b_pct_5": 0.05, + "buy_b_real": 0.3281, + "buy_b_sma": "sma10_1d", + "buy_b_sma_close": "sma5_1d", + "buy_base": 0.09, + "buy_decalage0": 8, + "buy_decalage2": 8, + "buy_decalage3": 8, + "buy_decalage_deb_0": 3, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 0, + "buy_diff": 0.03, + "buy_h_bb_lowerband": 1.05, + "buy_h_bb_width": 0.09, + "buy_h_cat": "", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_6(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " None: + inf_tf = '5m' + pairs = self.dp.current_whitelist() + print("Calcul des pairs informatives") + for pairname in pairs: + self.stop_buying[pairname] = True + print("Fin Calcul des pairs informatives") + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + info_previous_5_candle = informative.iloc[-5].squeeze() + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + btc_previous_5_candle = btc.iloc[-5].squeeze() + + if self.stop_buy_for_all is True: + if (btc_last_candle['percent20'] > 0) & (btc_last_candle['min200'] == btc_previous_5_candle['min200']): # self.btc_allow_to_buy.value: + self.stop_buy_for_all = False + logger.info("1 - BUYING IS ENABLED %s date %s", pair, info_last_candle['date']) + else: + logger.info("1 - BUYING IS BLOCKED BY BTC FALL %s date %s", pair, info_last_candle['date']) + return False + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + # if (info_last_candle['rsi_1h'] < self.protection_RSI_enable.value) & (self.stop_buying[pair] is True): + # print("Enable buying", pair) + # self.stop_buying[pair] = False + + # if self.stop_buying[pair] is True: + # if (info_last_candle['rsi_5_1h'] > 20) & (info_previous_last_candle['rsi_5_1h'] <= info_last_candle['rsi_5_1h']) \ + # & (info_last_candle['max_rsi_1h'] < 50): + # print("2 - Enable buying", pair, info_last_candle['date'], info_last_candle['rsi_5_1h'], info_last_candle['max_rsi_1h']) + # self.stop_buying[pair] = False + + if self.stop_buying[pair] is True: + if (info_last_candle['min200'] == info_previous_5_candle['min200']): + # if (info_last_candle['rsi5'] > 20) & (info_last_candle['rsi'] > 30): + # print("1 - Enable buying ", pair, info_last_candle['date'], info_last_candle['rsi5']) + logger.info("1 - Enable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + # , (info_last_candle['trend_ichimoku_base'], + # (info_last_candle['close'] < info_last_candle['sma10']), + # (info_previous_last_candle['sma10'], info_last_candle['sma10']))) + + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + if (self.stop_buy_for_all is True) & (current_profit < self.btc_sell_all_profit.value): + return "btc_fall" + + expected_profit = 0.01 + days = (current_time - trade.open_date_utc).days + ###### + + btc, _ = self.dp.get_analyzed_dataframe(pair="BTC/USDT", timeframe=self.timeframe) + btc_last_candle = btc.iloc[-1].squeeze() + btc_previous_last_candle = btc.iloc[-2].squeeze() + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if self.stop_buying[pair] is False: + if (last_candle['rsi5'] < 16): + logger.info("0 - Disable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = True + if (current_profit > 0): + return "stop_buying" + + if self.stop_buying[pair] is True: + if (last_candle['rsi5'] > 20) & (last_candle['percent10'] > 0): + logger.info("1 - Enable buying %s date=%s rsi=%s", pair, last_candle['date'], last_candle['rsi5']) + # print("1 - Enable buying ", pair, last_candle['date'], last_candle['rsi5']) + self.stop_buying[pair] = False + + if (days < 10) & ((btc_last_candle['percent5'] < self.btc_fall_5.value) | (btc_last_candle['percent3'] < self.btc_fall_3.value) | ( + btc_last_candle['percent'] < self.btc_fall_1.value)): + self.stop_buy_for_all = True + logger.info("0 - Disable ALL %s date=%s pct=%s pct3=%s pct5=%s", pair, last_candle['date'], btc_last_candle['percent'], + btc_last_candle['percent3'], btc_last_candle['percent5']) + if (current_profit > 0): + return "btc_fall" + + max_percent = last_candle['bb_width'] / 4 #0.005 + max_profit = last_candle['bb_width'] * 3 / 4 # 0.015 + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > max_profit) & ((last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value) \ + & (days < self.sell_b_too_old_day.value * 2) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2) \ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | (last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & (last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / 4)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + # dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + # dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + # dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + # dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + # dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = True + #if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['cond1'] <= 1) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma20']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['min'] * 1.005) + # & (dataframe['moy200_12'] == dataframe['min200']) + # & (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'] >= -0.005) + # + # ), ['buy', 'buy_tag']] = (1, 'buy_near_m50') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + # & (dataframe['close'] < dataframe['min50'] * 1.01) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + # (dataframe['min_max50'] >= 0.03) + # & (dataframe['bb_width'] >= 0.02) + (dataframe['cond1'].shift(2) <= 1.2) + & (dataframe['rsi'] < 72) + & (dataframe['close'] < dataframe['min50'] * 1.005) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_6.py2 b/Zeus_6.py2 new file mode 100644 index 0000000..edc78f2 --- /dev/null +++ b/Zeus_6.py2 @@ -0,0 +1,1089 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.hyper import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_6(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " float: + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # if current_candle['close'] < current_candle['sma10_1d']: + # print("use more stake", pair, " ", proposed_stake * 2) + # return min(max_stake, proposed_stake * 2) + # else: + # if current_candle['close'] < current_candle['sma5_1d']: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + # + # # Use default stake amount. + # return proposed_stake + + # def bot_loop_start(self, **kwargs) -> None: + # inf_tf = '5m' + # pairs = self.dp.current_whitelist() + # market_overview = {'up': 0, 'down': 0} + # sum_pct5 = 0 + # sum_pct1 = 0 + # self.max_open_trades = self.config['max_open_trades'] + # self.max_amount = self.config['stake_amount'] + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # for pairname in pairs: + # informative = self.dp.get_pair_dataframe(pair=pairname, timeframe=inf_tf) + # informative['pct'] = informative['close'].pct_change(1) + # informative['pct5'] = informative['close'].pct_change(5) + # # print(informative['pct5']) + # pct5 = (informative.tail(1).iloc[0]['pct5']) * 100 + # pct1 = (informative.tail(1).iloc[0]['pct']) * 100 + # if pairname == "COCOS/USDT": + # print(pairname, round(pct1, 5), round(pct5, 5)) #, informative.tail(1).iloc[0]) + # + # if pairname == "BTC/USDT": + # current = informative.tail(1).iloc[0]['close'] + # # 50000 => 2 30000 => 20 + # if (current > 50000): + # self.max_open_trades = 2 + # self.max_amount = self.config['stake_amount'] / 2 + # else: + # if (current > 32000): + # self.max_open_trades = 2 + int((50000 - current) / 1000) + # self.max_amount = self.config['stake_amount'] / 2 \ + # + self.config['stake_amount'] * self.max_open_trades / self.config['max_open_trades'] + # else: + # self.max_open_trades = self.config['max_open_trades'] + # self.max_amount = self.config['stake_amount'] + # + # logger.info("pair '%s' prix %s max open trade %s max amount %s.", + # pairname, current, self.max_open_trades, self.max_amount) + # + # if pct5 > 0: + # market_overview['up'] += 1 + # elif pct5 < 0: + # market_overview['down'] += 1 + # sum_pct5 += pct5 + # sum_pct1 += pct1 + # + # self.market_overview_pct1 = sum_pct1 / len(pairs) + # self.market_overview_pct5 = sum_pct5 / len(pairs) + # + # logger.info("market_overview_pct1 %s %s %s", round(self.market_overview_pct1,5), round(self.market_overview_pct5, 5), market_overview) + # self.market_overview = market_overview + + # def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + # current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + # + # # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # # 'info': + # # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + # + # allow_to_buy = True + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(Trade.get_open_trades()) >= self.max_open_trades: + # logger.info("too much open trades for BTC current value") + # allow_to_buy = False + # + # return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + ###### + + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # if (current_profit > - 0.04) & (self.market_overview_pct1 < - 1) & (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) < 0.05): + # return 'send_all' + + # if (current_profit > 0) & (last_candle['percent'] < 0) \ + # (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) < 0.25): + # return 'all_down' + + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_5'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max200_5'] = (dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = True + #if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # dataframe.loc[ + # ( + # (dataframe['cond1'] <= 1) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma20']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['min'] * 1.005) + # & (dataframe['moy200_12'] == dataframe['min200']) + # & (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10) + # & (dataframe['percent20'] >= -0.005) + # + # ), ['buy', 'buy_tag']] = (1, 'buy_near_m50') + + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= 0.08) + # & (dataframe['rsi'] < 42) + # & (dataframe['rsi_1h'] >= self.buy_rsi.value) + # & (dataframe['close'] < dataframe['sma10']) + # # & (dataframe['min50'].shift(2) == dataframe['min50']) + # ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + # d = dataframe.tail(1) + # print(metadata['pair'], d['percent50'].iloc[0], d['buy'].iloc[0], d['buy_tag'].iloc[0]) + + dataframe.loc[ + ( + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + | (dataframe['trend_kst_diff'] <= self.buy_diff.value) + ) + & (dataframe['rsi_1h'] < self.buy_rsi_1h.value) + & (dataframe['rsi_1h'] >= self.buy_rsi_max_1h.value) + & (dataframe['rsi'] > self.buy_rsi.value) + & (dataframe['rsi'] <= self.buy_rsi_max.value) + #& (dataframe['close'] < dataframe['sma10']) + # & (dataframe['close'] < dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + #& (dataframe['sma10'].shift(1) * 1.001 < dataframe['sma10']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['rsi_5_1h'] > 35) + & (dataframe['close'] <= dataframe['min50'] * (1 + dataframe['min_max50'] / 2)) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_h') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_7.json b/Zeus_7.json new file mode 100644 index 0000000..d1963d2 --- /dev/null +++ b/Zeus_7.json @@ -0,0 +1,82 @@ +{ + "strategy_name": "Zeus_7", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.12, + "buy_bb_width_n": 4.0, + "buy_diff": 0.3, + "buy_min_max_coef": 1.0, + "buy_min_max_cond1": 1.3, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.15, + "buy_min_max_nh": 25, + "buy_min_max_rsi": 60, + "buy_rsi": 79, + "buy_rsi_sup": 67 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 11, + "protection_lost_percent": 0.14 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-24 21:16:25.988317+00:00" +} \ No newline at end of file diff --git a/Zeus_7.py b/Zeus_7.py new file mode 100644 index 0000000..a74ad84 --- /dev/null +++ b/Zeus_7.py @@ -0,0 +1,723 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_7(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", " 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_5'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max200_5'] = (dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + # & (dataframe['min50'].shift(self.buy_min_max_decalage.value) == dataframe['min50']) + + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_8.json b/Zeus_8.json new file mode 100644 index 0000000..09bbe43 --- /dev/null +++ b/Zeus_8.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_8", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 11, + "protection_lost_percent": 0.14 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_8.py b/Zeus_8.py new file mode 100644 index 0000000..73553a8 --- /dev/null +++ b/Zeus_8.py @@ -0,0 +1,966 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + #if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + #& (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + # & (dataframe['min50'].shift(self.buy_min_max_decalage.value) == dataframe['min50']) + + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_8_1.json b/Zeus_8_1.json new file mode 100644 index 0000000..bd917bf --- /dev/null +++ b/Zeus_8_1.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_8_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 11, + "protection_lost_percent": 0.14 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-04-03 14:39:34.819040+00:00" +} diff --git a/Zeus_8_1.py b/Zeus_8_1.py new file mode 100644 index 0000000..79321dc --- /dev/null +++ b/Zeus_8_1.py @@ -0,0 +1,1013 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " 0.0) & (last_candle['percent'] < -0.01): + return 'percent_quick' + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + # & (dataframe['min50'].shift(self.buy_min_max_decalage.value) == dataframe['min50']) + + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-5].squeeze() + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + + + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['min50'] == last_candle_5['min50']) + + # print(reduce(lambda x, y: x & y, condition)) + if (0 < count_of_buys <= self.max_dca_orders) & (current_profit < -0.05 * count_of_buys) \ + & (condition): + try: + # print(last_candle['cond1'], last_candle['bb_width'], last_candle['rsi'], last_candle['close'], last_candle['percent5'], + # last_candle['trend_ichimoku_base']) + # This returns first order stake size + stake_amount = self.config['stake_amount'] * (count_of_buys ) # filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + # print("-----------" + trade.pair + " " + str(current_profit) + "---------------------") + # print("count_of_buys = " + str(count_of_buys)) + # print("stake_amount = " + str(stake_amount)) + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_2.json b/Zeus_8_2.json new file mode 100644 index 0000000..400734a --- /dev/null +++ b/Zeus_8_2.json @@ -0,0 +1,123 @@ +{ + "strategy_name": "Zeus_8_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_0_distance": -0.03, + "buy_0_percent20": 0.09, + "buy_1_bb_lower_5": 0.28, + "buy_2_bb_lower_5": 0.55, + "buy_2_distance": 0.08, + "buy_2_percent20": 0.09, + "buy_3_bb_lower_5": 0.26, + "buy_3_distance": 0.04, + "buy_3_percent20": 0.09, + "buy_b_bb_lowerband": 1.01, + "buy_b_bb_width": 0.08, + "buy_b_cat": ">R", + "buy_b_pct": 0.009, + "buy_b_pct_1": -0.15, + "buy_b_pct_3": 0.18, + "buy_b_pct_5": 0.01, + "buy_b_real": 0.8482, + "buy_b_sma": "sma3_1d", + "buy_b_sma_close": "sma3_1d", + "buy_base": 0.09, + "buy_bb_width_n": 9.6, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 3, + "buy_decalage_deb_3": 3, + "buy_h_bb_lowerband": 1.02, + "buy_h_bb_width": 0.08, + "buy_h_cat": "=R", + "buy_h_pct": 0.013, + "buy_h_pct_1": -0.15, + "buy_h_pct_3": 0.15, + "buy_h_pct_5": -0.18, + "buy_h_real": 0.2665, + "buy_h_sma": "sma10_1d", + "buy_h_sma_close": "sma5_1d", + "buy_min_horizon": 102, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 1.3, + "buy_min_max_decalage": 6, + "buy_min_max_n": 0.03, + "buy_min_max_nh": 31, + "buy_min_max_rsi": 69, + "buy_real_num0": 0.84, + "buy_real_num1": 0.99, + "buy_real_num2": 1.68, + "buy_rsi": 55, + "decalage_b": 1, + "decalage_h": 1 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 11, + "protection_lost_percent": 0.14, + "protection_nb_buy_lost": 4, + "protection_percent_buy_lost": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-01 01:52:55.970812+00:00" +} \ No newline at end of file diff --git a/Zeus_8_2.py b/Zeus_8_2.py new file mode 100644 index 0000000..c8c8f5b --- /dev/null +++ b/Zeus_8_2.py @@ -0,0 +1,1006 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_2(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " 0.0) & (last_candle['percent'] < -0.01): + return 'percent_quick' + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + # & (dataframe['min50'].shift(self.buy_min_max_decalage.value) == dataframe['min50']) + + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + # print(reduce(lambda x, y: x & y, condition)) + days = (current_time - trade.open_date_utc).days + + if (days > 1) & (0 < count_of_buys <= self.protection_nb_buy_lost.value) & (current_profit < - self.protection_percent_buy_lost.value / 100) & (condition): + try: + print(last_candle['cond1'], last_candle['bb_width'], last_candle['rsi'], last_candle['close'], last_candle['percent5'], + last_candle['trend_ichimoku_base']) + # This returns first order stake size + stake_amount = self.config['stake_amount'] * (count_of_buys ) # filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + "---------------------") + print("count_of_buys = " + str(count_of_buys)) + print("stake_amount = " + str(stake_amount)) + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3.json b/Zeus_8_3.json new file mode 100644 index 0000000..938bcfb --- /dev/null +++ b/Zeus_8_3.json @@ -0,0 +1,121 @@ +{ + "strategy_name": "Zeus_8_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_0_distance": -0.03, + "buy_0_percent20": 0.09, + "buy_1_bb_lower_5": 0.28, + "buy_2_bb_lower_5": 0.55, + "buy_2_distance": 0.08, + "buy_2_percent20": 0.09, + "buy_3_bb_lower_5": 0.26, + "buy_3_distance": 0.04, + "buy_3_percent20": 0.09, + "buy_b_bb_lowerband": 1.01, + "buy_b_bb_width": 0.08, + "buy_b_cat": ">R", + "buy_b_pct": 0.009, + "buy_b_pct_1": -0.15, + "buy_b_pct_3": 0.18, + "buy_b_pct_5": 0.01, + "buy_b_real": 0.8482, + "buy_b_sma": "sma3_1d", + "buy_b_sma_close": "sma3_1d", + "buy_base": 0.12, + "buy_bb_width_n": 9.6, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 3, + "buy_decalage_deb_3": 3, + "buy_h_bb_lowerband": 1.02, + "buy_h_bb_width": 0.08, + "buy_h_cat": "=R", + "buy_h_pct": 0.013, + "buy_h_pct_1": -0.15, + "buy_h_pct_3": 0.15, + "buy_h_pct_5": -0.18, + "buy_h_real": 0.2665, + "buy_h_sma": "sma10_1d", + "buy_h_sma_close": "sma5_1d", + "buy_min_horizon": 102, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 1.3, + "buy_min_max_decalage": 6, + "buy_min_max_n": 0.03, + "buy_min_max_nh": 31, + "buy_min_max_rsi": 69, + "buy_real_num0": 0.84, + "buy_real_num1": 0.99, + "buy_real_num2": 1.68, + "buy_rsi": 55, + "decalage_b": 1, + "decalage_h": 1 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 5, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-13 05:53:44.097978+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3.py b/Zeus_8_3.py new file mode 100644 index 0000000..70f7299 --- /dev/null +++ b/Zeus_8_3.py @@ -0,0 +1,1022 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " 0.0) & (last_candle['percent'] < -0.01): + return 'percent_quick' + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['pct_change_3_1d'] > 0) + # & (dataframe['pct_change_5_1d'] > 0) + # & (dataframe['min50'].shift(self.buy_min_max_decalage.value) == dataframe['min50']) + + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= min_d) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_1.json b/Zeus_8_3_1.json new file mode 100644 index 0000000..031fd68 --- /dev/null +++ b/Zeus_8_3_1.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_8_3_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 5, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-13 05:53:44.097978+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_1.py b/Zeus_8_3_1.py new file mode 100644 index 0000000..6689504 --- /dev/null +++ b/Zeus_8_3_1.py @@ -0,0 +1,1044 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " 0.0) & (last_candle['percent'] < -0.01): + return 'percent_quick' + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + ok = False + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # ok = (self.market_overview['up'] / (self.market_overview['down'] + self.market_overview['up']) > 0.35) + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_h_real.value + OPR = self.buy_h_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_h_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] > 0) + & (dataframe['pct_change_5_1d'] > 0) #self.buy_h_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_h_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_h_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + & (dataframe['trend_ichimoku_base'] <= 0.1) + , + ['buy', 'buy_tag']] = (1, 'buy_h') + + conditions = [] + IND = 'trend_ichimoku_base' + REAL = self.buy_b_real.value + OPR = self.buy_b_cat.value + DFIND = dataframe[IND] + # print(DFIND.mean()) + if OPR == ">R": + conditions.append(DFIND > REAL) + elif OPR == "=R": + conditions.append(np.isclose(DFIND, REAL)) + elif OPR == "= 10) + & (dataframe['pct_change'] < - self.buy_b_pct.value) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['pct_change_3_1d'] < 0) # self.buy_b_pct_3.value) + & (dataframe['pct_change_5_1d'] < 0) #self.buy_b_pct_5.value) + #& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_b_bb_lowerband.value) + & (dataframe['bb_width_1d'] >= self.buy_b_bb_width.value) + & (dataframe['close'] <= dataframe['sma5_1d']) + & (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d']) + & (dataframe['cond1'] <= 0.45) # self.buy_real_num0.value / 2) + , + ['buy', 'buy_tag']] = (1, 'buy_b') + + for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value): + #if self.buy_0.value: + conditions = list() + condition1, dataframe = condition_generator( + dataframe, + buy_operator0, + buy_indicator0, + buy_crossed_indicator0, + self.buy_real_num0.value, + self.buy_decalage0.value + ) + conditions.append(condition1) + dataframe.loc[ + ( + reduce(lambda x, y: x & y, conditions) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['bb_middleband']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value) + # & (dataframe['min20'] == dataframe['min50']) + & (dataframe['distance_min'] <= self.buy_0_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value) + #& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage)) + for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value): + #if self.buy_2.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value) + & (dataframe['distance_min'] <= self.buy_2_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + & (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value) + ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage)) + # d = dataframe.tail(1).iloc[0] + # print(metadata['pair'], d['cond1'], d['bb_width'], d['close'], d['sma10'], d['sma20']) + for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value): + #if self.buy_3.value: + dataframe.loc[ + ( + (dataframe['cond1'].shift(decalage) <= 0.2) + & (ok) + & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10) + # & (dataframe['sma10'].shift(1) <= dataframe['sma10']) + & (dataframe['bb_width'] >= 0.05) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['open'] < dataframe['sma20']) + & (dataframe['open'] < dataframe['sma10']) + & (dataframe['min50'].shift(decalage) == dataframe['min50']) + #& (dataframe['min10'] <= dataframe['min50'] * 1.02) + & (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value) + & (dataframe['distance_min'] <= self.buy_3_distance.value) + & ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift( + decalage) <= 0.005) + # & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value) + & (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value) + #& (dataframe['percent_4h'] > 0) + #& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value) + ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage)) + + # min_d = min(dataframe['sma3_4h'], dataframe['close_1d']) + # condition = (dataframe['min50'] == dataframe['min50'].shift(3)) & (dataframe['close'] <= min_d) + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_1_1.json b/Zeus_8_3_1_1.json new file mode 100644 index 0000000..075f6b2 --- /dev/null +++ b/Zeus_8_3_1_1.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_8_3_1_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 5, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-13 05:53:44.097978+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_1_1.py b/Zeus_8_3_1_1.py new file mode 100644 index 0000000..9a04c0f --- /dev/null +++ b/Zeus_8_3_1_1.py @@ -0,0 +1,998 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_1_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + # info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((info_last_candle['rsi_1h'] >= 72) | (info_last_candle['close_1h'] >= info_last_candle['bb_upperband_1h'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((info_last_candle['rsi_1h'] <= 35) | (info_last_candle['close_1h'] < info_last_candle['bb_lowerband_1h'])): + logger.info("2 - Enable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + ###### + + informative, _ = self.dp.get_analyzed_dataframe(pair='BTC/USDT', timeframe="5m") + btc_last_candle = informative.iloc[-1].squeeze() + + if (self.stop_buying[pair] is True) & (current_profit > -0.02): + return "force_sell_no_buy" + + if (self.stop_buying[pair] is False) & (btc_last_candle['percent3'] < -0.02) & (current_profit > -0.02): + self.stop_buying[pair] = True + return "force_sell_btc_fall" + + + # if last_candle['rsi_1h'] > 72: + # self.stop_buy[pair] = True + # return False + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + # dataframe = self.populate_buy_trend(dataframe, {'pair': trade.pair}) + # if not (self.populate_buy_trend(dataframe, {'pair': trade.pair})): + # return None + if (self.stop_buying.get(trade.pair) == None): + print("-----------" + trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + + self.stop_buying[trade.pair] = True + + if (self.stop_buying[trade.pair] == True): + print("-----------" + trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + condition = ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_2.json b/Zeus_8_3_2.json new file mode 100644 index 0000000..c1df837 --- /dev/null +++ b/Zeus_8_3_2.json @@ -0,0 +1,114 @@ +{ + "strategy_name": "Zeus_8_3_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 5, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-13 05:53:44.097978+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2.py b/Zeus_8_3_2.py new file mode 100644 index 0000000..e7e1167 --- /dev/null +++ b/Zeus_8_3_2.py @@ -0,0 +1,947 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_2(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " -0.03): + # self.stop_buy_for_all = True + # return "btc_fall" + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (True) | (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_2_1.json b/Zeus_8_3_2_1.json new file mode 100644 index 0000000..1e7e578 --- /dev/null +++ b/Zeus_8_3_2_1.json @@ -0,0 +1,81 @@ +{ + "strategy_name": "Zeus_8_3_2_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.13, + "buy_bb_width_n": 5.2, + "buy_min_horizon": 173, + "buy_min_max_coef": 1.002, + "buy_min_max_cond1": 2.0, + "buy_min_max_decalage": 3, + "buy_min_max_n": 0.04, + "buy_min_max_nh": 35, + "buy_min_max_rsi": 86, + "buy_rsi": 64 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "hours_sell": 44, + "percent_sell_stop": -0.4 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-27 08:51:29.097780+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2_1.py b/Zeus_8_3_2_1.py new file mode 100644 index 0000000..b2950a0 --- /dev/null +++ b/Zeus_8_3_2_1.py @@ -0,0 +1,1010 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_2_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", "= self.hours_sell.value) & (last_candle['percent_1h'] <= -0.05): + return 'sell_stop' + # if ( + # (btc_last_candle['percent'] < -0.02) | (btc_last_candle['percent5'] < -0.04)) & (current_profit > -0.03): + # self.stop_buy_for_all = True + # return "btc_fall" + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '1M') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['min_max_50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma5_inv'] = (dataframe['sma5'].shift(2) > dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) < dataframe['sma5']) + dataframe['sma5_sell_1'] = (dataframe['sma5'].shift(2) < dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) > dataframe['sma5']) \ + & ( + (dataframe['close'] >= dataframe['max_n']) | + (dataframe['close'].shift(1) >= dataframe['max_n']) | + (dataframe['close'].shift(2) >= dataframe['max_n']) + ) + dataframe['sma5_buy_1'] = (dataframe['sma5'].shift(2) > dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) < dataframe['sma5']) \ + & ( + (dataframe['close'] <= dataframe['min_n']) | + (dataframe['close'].shift(1) <= dataframe['min_n']) | + (dataframe['close'].shift(2) <= dataframe['min_n']) + ) + dataframe['sma5_pct'] = dataframe['sma5'].pct_change(1) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["zero"] = 0 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['max3'] = talib.MAX(informative['close'], timeperiod=3) + informative['max5'] = talib.MAX(informative['close'], timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative["rsi"] = talib.RSI(informative) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['percent'] = informative['close'].pct_change(1) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + ################### INFORMATIVE 1M + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1M") + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1M", ffill=True) + + # dataframe['support'] = min(dataframe['close_1d'], dataframe['sma3_1d'], dataframe['sma3_1d']) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + & (dataframe['close'] < dataframe['min_n'] * (1 + dataframe['min_max_50'] / 5) ) + # & (dataframe['close'] <= dataframe['min_200_001']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['close'] < dataframe['min_n'] * (1 + dataframe['min_max_50'] / 5)) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['close'] <= dataframe['min_200_001']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + + # conditions = [ + # (dataframe['percent10'] <= -0.06) + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + # ['buy', 'buy_tag']] = (1, 'buy_5') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + # def adjust_trade_position(self, trade: Trade, current_time: datetime, + # current_rate: float, current_profit: float, min_stake: float, + # max_stake: float, **kwargs): + # dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # if (len(dataframe) < 1): + # return None + # last_candle = dataframe.iloc[-1].squeeze() + # last_candle_5 = dataframe.iloc[-3].squeeze() + # + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + # + # filled_buys = trade.select_filled_orders('buy') + # count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + # + # condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']) + # p = self.protection_percent_buy_lost.value + # percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + # + # if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + # & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + # try: + # p = self.config['stake_amount'] + # factors = [p, p, p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + # + # stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # # This then calculates current safety order size + # # stake_amount = stake_amount * pow(1.5, count_of_buys) + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + # return stake_amount + # except Exception as exception: + # print(exception) + # return None + # return None diff --git a/Zeus_8_3_2_B_1.json b/Zeus_8_3_2_B_1.json new file mode 100644 index 0000000..8097c14 --- /dev/null +++ b/Zeus_8_3_2_B_1.json @@ -0,0 +1,87 @@ +{ + "strategy_name": "Zeus_8_3_2_B_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.19, + "buy_base_echange": 0.13, + "buy_bb_width_n": 1.1, + "buy_echange": -0.39, + "buy_min_horizon": 186, + "buy_min_max_coef": 1.002, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 5, + "buy_min_max_n": 0.18, + "buy_min_max_nh": 8, + "buy_min_max_rsi": 77, + "buy_rsi": 58, + "decalage_min50": 0, + "pct_change_1h": 0.002, + "percent_close_50": 1.002, + "stake_factor": 4 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": true, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": true, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": false, + "profit_h_quick_lost": true, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": true, + "profit_h_sma5": true, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 87, + "sell_b_RSI2": 82, + "sell_b_RSI2_percent": 0.007, + "sell_b_RSI3": 75, + "sell_b_candels": 23, + "sell_b_percent": 0.014, + "sell_b_percent3": 0.018, + "sell_b_profit_no_change": 0.003, + "sell_b_profit_percent10": 0.0011, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.013, + "sell_h_RSI": 82, + "sell_h_RSI2": 75, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 97, + "sell_h_candels": 6, + "sell_h_percent": 0.009, + "sell_h_percent3": 0.016, + "sell_h_profit_no_change": 0.017, + "sell_h_profit_percent10": 0.0014, + "sell_h_too_old_day": 3, + "sell_h_too_old_percent": 0.004 + }, + "protection": { + "protection_fibo": 9, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-12-15 19:58:58.055412+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2_B_1.py b/Zeus_8_3_2_B_1.py new file mode 100644 index 0000000..8e5e8c2 --- /dev/null +++ b/Zeus_8_3_2_B_1.py @@ -0,0 +1,1108 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_2_B_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", " float: + + # dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # current_candle = dataframe.iloc[-1].squeeze() + # + # min_value = min([current_candle['close_1d'], current_candle['sma3_1d'], current_candle['sma5_1d'], current_candle['sma10_1d']]) + # min_pct = (current_candle['close'] - min_value) / current_candle['close'] + # + # # + # # print("use more stake", pair, " ", proposed_stake * (1 - min_pct)) + # if min_pct < 0: + # proposed_stake = min(200, min(max_stake, proposed_stake * (1 - self.stake_factor.value * min_pct))) + # print(str(current_time), "proposed_stake=", proposed_stake, " max_stake=", max_stake , "min_pct=", min_pct) + + # + # if current_candle['bb_width'] > 0.035: + # print("use more stake", pair, " ", proposed_stake * 1.5) + # return min(max_stake, proposed_stake * 1.5) + + # if current_candle['bb_width'] < 0.020: + # print("use less stake", pair, " ", proposed_stake / 2) + # return min(max_stake, proposed_stake / 2) + # if self.config['stake_amount'] == 'unlimited': + # # Use entire available wallet during favorable conditions when in compounding mode. + # return max_stake + # else: + # # Compound profits during favorable conditions instead of using a static stake. + # return self.wallets.get_total_stake_amount() / self.config['max_open_trades'] + + + # Use default stake amount. + return proposed_stake + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + hours = (current_time - trade.open_date_utc).seconds / 3600 + + # fibo_fact = fibo[hours] + ###### + + if (last_candle['pct_change_1_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > max_profit) and (last_candle['echange*pct5'] < 0.0005): + return "b_nochange_pct" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > max_profit) and (last_candle['echange*pct12'] < 0.001): + return "h_nochange_pct" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): + # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min50_005'] = dataframe['min50'] * 1.005 + dataframe['min200_005'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['min_max_50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma5_inv'] = (dataframe['sma5'].shift(2) > dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) < dataframe['sma5']) + # dataframe['sma5_sell_1'] = (dataframe['sma5'].shift(2) < dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) > dataframe['sma5']) \ + # & ( + # (dataframe['close'] >= dataframe['max_n']) | + # (dataframe['close'].shift(1) >= dataframe['max_n']) | + # (dataframe['close'].shift(2) >= dataframe['max_n']) + # ) + # dataframe['sma5_buy_1'] = (dataframe['sma5'].shift(2) > dataframe['sma5'].shift(1)) & (dataframe['sma5'].shift(1) < dataframe['sma5']) \ + # & ( + # (dataframe['close'] <= dataframe['min_n']) | + # (dataframe['close'].shift(1) <= dataframe['min_n']) | + # (dataframe['close'].shift(2) <= dataframe['min_n']) + # ) + # dataframe['sma5_pct'] = dataframe['sma5'].pct_change(1) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + # dataframe["zero"] = 0 + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume5"] = dataframe["volume"].rolling(5).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).sum() + + # print(metadata['pair']) + # print(circulation[metadata['pair']]) + if circulation[metadata['pair']]: + dataframe["echange"] = 10000 * dataframe["volume"] / circulation[metadata['pair']] + dataframe["echange*pct"] = dataframe["echange"] * dataframe["percent"] + dataframe["echange5"] = 10000 * dataframe["volume5"] / circulation[metadata['pair']] + dataframe["echange*pct5"] = dataframe["echange5"] * dataframe["percent5"] + dataframe["pct_echange5"] = dataframe["echange5"].pct_change() + dataframe["acc_echange5"] = dataframe["echange*pct5"] / dataframe["echange*pct5"].shift(1) + for i in range(1, 4): + n = i * 12 + dataframe["echange*pct" + str(n)] = 10000 * dataframe["volume"].rolling(n).sum() / circulation[metadata['pair']] \ + * dataframe["percent"].rolling(n).sum() + + + dataframe["pente20"] = (dataframe["close"] - dataframe['close'].shift(20)) / dataframe["close"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min50_1.01'] = 1.01 * dataframe['min50'] + dataframe['min50_1.02'] = 1.02 * dataframe['min50'] + dataframe['min50_1.03'] = 1.03 * dataframe['min50'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe['trend_ichimoku_base_50'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=50) + dataframe['trend_ichimoku_base_5'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=5) + dataframe['trend_ichimoku_base_sma5'] = talib.SMA(dataframe['trend_ichimoku_base'], timeperiod=5) + dataframe['trend_ichimoku_base_pct'] = dataframe['trend_ichimoku_base'].pct_change(3) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cond_50'] = talib.MIN(dataframe['cond1'], timeperiod=50) + dataframe['cond_5'] = talib.MIN(dataframe['cond1'], timeperiod=5) + dataframe['cond_sma5'] = talib.SMA(dataframe['cond1'], timeperiod=5) + dataframe['cond_pct'] = dataframe['cond1'].pct_change(3) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['max3'] = talib.MAX(informative['close'], timeperiod=3) + informative['max5'] = talib.MAX(informative['close'], timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['min3'] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + # dataframe['support'] = min(dataframe['close_1d'], dataframe['sma3_1d'], dataframe['sma3_1d']) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # min_value = min([dataframe['close_1d'], dataframe['sma3_1d'], dataframe['sma5_1d'], + # dataframe['sma10_1d']]) + # min_pct = 100 * (dataframe['close'] - min_value) / dataframe['close'] + + # if self.config['runmode'].value in ('live', 'dry_run'): + # trades = Trade.get_trades([Trade.pair == metadata['pair'], + # Trade.open_date > datetime.utcnow() - timedelta(days=1), + # Trade.is_open.is_(False), + # ]).order_by(Trade.close_date).all() + # # Summarize profit for this pair. + # print("Trades=", trades) + # curdayprofit = sum(trade.close_profit for trade in trades) + # print(curdayprofit) + + decalage = 3 + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'].shift(decalage) <= self.buy_base.value) + & (dataframe['rsi'].shift(decalage) < self.buy_rsi.value) + & (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)) + & (dataframe['close'].shift(decalage) < dataframe['bb_middleband'].shift(decalage)) + & (dataframe['bb_width'].shift(decalage) > 0.003) + & ((dataframe['close'].shift(decalage) < dataframe['bb_lower_width_5'].shift(decalage))) + & ((dataframe['close'].shift(decalage) <= dataframe['min50'].shift(decalage) * self.percent_close_50.value) | + (dataframe['pct_change_1_1h'].shift(decalage) > - self.pct_change_1h.value) + ) + # & (dataframe['close'] <= dataframe['bb_upperband']) + # & (dataframe['close'] <= dataframe['min_200_001']) + & (dataframe['close'].shift(decalage) <= dataframe['close_1h'].shift(decalage)) + & ((dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)) | + (dataframe['pct_change_1_1h'].shift(decalage) > - self.pct_change_1h.value) + ) + & (dataframe['close'] < dataframe['bb_upperband']) + & (dataframe['open'] < dataframe['bb_upperband']) + # & (dataframe['open'] < dataframe['sma10']) + # & (dataframe['open'] < dataframe['sma100']) + # & ((dataframe['percent5'] < 0.005) | (dataframe['rsi'] < 50)) + # & (dataframe['close'] < dataframe['bb_upperband']) + # & (dataframe['close'] < dataframe['min50'] * (1 + dataframe['min_max_50'] / 2)) #self.buy_min_max_coef.value) + ), ['buy', 'enter_tag']] = (1, 'buy_ichimoku') + + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['close'] <= dataframe['min_200_001']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'enter_tag']] = (1, 'buy_min_max') + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base_echange.value) + & (dataframe['echange*pct12'] <= self.buy_echange.value) + & (dataframe['echange*pct12'].shift(1) <= dataframe['echange*pct12']) + & ( + (dataframe['close'] < dataframe['bb_lower_width_5']) + # (dataframe['open'] < dataframe['bb_lower_width_5']) + ) + & (dataframe['min50'] == dataframe['min50'].shift(self.decalage_min50.value)) + ), ['buy', 'enter_tag']] = (1, 'buy_echange') + + # dataframe.loc[ + # ( + # (dataframe['close'] <= dataframe['min200']) + # & (dataframe['min50'] == dataframe['min200']) + # & (dataframe['min_max_50'] >= 0.015) + # ), ['buy', 'enter_tag']] = (1, 'buy_min_max') + + # dataframe.loc[ + # ( + # (dataframe['percent20'] <= -0.015) + # # & (dataframe['rsi'] < self.buy_min_max_rsi.value) + # & (dataframe['close'] <= dataframe['min50'] * 1.005) + # & (dataframe['min50'].shift(5) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1h']) + # ), ['buy', 'buy_tag']] = (1, 'buy_percent20') + # dataframe.loc[ + # ( + # (dataframe['percent10'] <= -0.015) + # # & (dataframe['rsi'] < self.buy_min_max_rsi.value) + # & (dataframe['close'] <= dataframe['min50'] * 1.005) + # & (dataframe['min50'].shift(3) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1h']) + # ), ['buy', 'buy_tag']] = (1, 'buy_percent10') + + # conditions = [ + # (dataframe['percent10'] <= -0.06) + # ] + # # GUARDS AND TRENDS + # if conditions: + # dataframe.loc[(reduce(lambda x, y: x & y, conditions)), + # ['buy', 'buy_tag']] = (1, 'buy_5') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if True: #(len(dataframe) < 1): + return None + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + # self.protection_nb_buy_lost.value + if (0 < count_of_buys <= 2) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + if (last_candle['close'] < last_candle['min5_1h']): + factors = [1.25 * p, 1.75 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + else: + factors = [1 * p, 1.25 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_2_B_3.json b/Zeus_8_3_2_B_3.json new file mode 100644 index 0000000..4bc1b23 --- /dev/null +++ b/Zeus_8_3_2_B_3.json @@ -0,0 +1,75 @@ +{ + "strategy_name": "Zeus_8_3_2_B_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "max_open_trades": { + "max_open_trades": 8 + }, + "buy": { + "buy_base": 0.33 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": true, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": true, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": false, + "profit_h_quick_lost": true, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": true, + "profit_h_sma5": true, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 87, + "sell_b_RSI2": 82, + "sell_b_RSI2_percent": 0.007, + "sell_b_RSI3": 75, + "sell_b_candels": 23, + "sell_b_percent": 0.014, + "sell_b_percent3": 0.018, + "sell_b_profit_no_change": 0.003, + "sell_b_profit_percent10": 0.0011, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.013, + "sell_h_RSI": 82, + "sell_h_RSI2": 75, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 97, + "sell_h_candels": 6, + "sell_h_percent": 0.009, + "sell_h_percent3": 0.016, + "sell_h_profit_no_change": 0.017, + "sell_h_profit_percent10": 0.0014, + "sell_h_too_old_day": 3, + "sell_h_too_old_percent": 0.004 + }, + "protection": { + "protection_fibo": 9, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2023-02-16 05:58:02.440989+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2_B_3.py b/Zeus_8_3_2_B_3.py new file mode 100644 index 0000000..322feb7 --- /dev/null +++ b/Zeus_8_3_2_B_3.py @@ -0,0 +1,1023 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_2_B_3(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", " 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0) \ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > max_profit) and (last_candle['echange*pct5'] < 0.0005): + return "b_nochange_pct" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma5_s5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma10_s5'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((last_candle['sma20_s2'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (last_candle['percent10_s2'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > max_profit) and (last_candle['echange*pct12'] < 0.001): + return "h_nochange_pct" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma5_s5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma10_s5'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((last_candle['sma20_s2'] > last_candle['sma20']) & + ((last_candle['percent'] < 0) & (last_candle['percent5'] < 0) & (last_candle['percent10'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI.value): + # & (last_candle['percent'] < 0): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (last_candle['percent10_s2'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min50_005'] = dataframe['min50'] * 1.005 + dataframe['min200_005'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['mean10'] = dataframe['close'].rolling(10).mean() + dataframe['mean20'] = dataframe['close'].rolling(20).mean() + dataframe['mean50'] = dataframe['close'].rolling(50).mean() + dataframe['mean100'] = dataframe['close'].rolling(100).mean() + + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['min_max_50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi_pente'] = dataframe['rsi'].pct_change(1) + dataframe['rsi_acc'] = dataframe['rsi_pente'].pct_change(1) + + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume5"] = dataframe["volume"].rolling(5).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).sum() + + dataframe['sma5_s2'] = dataframe['sma5'].shift(1) + dataframe['sma10_s2'] = dataframe['sma10'].shift(1) + dataframe['sma20_s2'] = dataframe['sma20'].shift(1) + dataframe['percent10_s2'] = dataframe['percent10'].shift(1) + dataframe['rsi_s2'] = dataframe['rsi'].shift(1) + + dataframe['sma5_s5'] = dataframe['sma5'].shift(4) + dataframe['sma10_s5'] = dataframe['sma10'].shift(4) + dataframe['sma20_s5'] = dataframe['sma20'].shift(4) + # print(metadata['pair']) + # print(circulation[metadata['pair']]) + if circulation[metadata['pair']]: + dataframe["echange"] = 10000 * dataframe["volume"] / circulation[metadata['pair']] + dataframe["echange*pct"] = dataframe["echange"] * dataframe["percent"] + dataframe["echange5"] = 10000 * dataframe["volume5"] / circulation[metadata['pair']] + dataframe["echange*pct5"] = dataframe["echange5"] * dataframe["percent5"] + dataframe["pct_echange5"] = dataframe["echange5"].pct_change() + dataframe["acc_echange5"] = dataframe["echange*pct5"] / dataframe["echange*pct5"].shift(1) + for i in range(1, 4): + n = i * 12 + dataframe["echange*pct" + str(n)] = 10000 * dataframe["volume"].rolling(n).sum() / circulation[metadata['pair']] \ + * dataframe["percent"].rolling(n).sum() + + dataframe["pente20"] = (dataframe["close"] - dataframe['close'].shift(20)) / dataframe["close"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"])) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + dataframe["bb_pente"] = (dataframe["bb_lowerband"] - dataframe['bb_lowerband'].shift(3)) / dataframe["bb_lowerband"] + dataframe["bb_pente_inv"] = (dataframe["bb_pente"].shift(2) > dataframe["bb_pente"].shift(1)) & \ + (dataframe["bb_pente"] > dataframe["bb_pente"].shift(1)) + dataframe["bb_max_width"] = (dataframe["bb_ecart"].shift(2) < dataframe["bb_ecart"].shift(1)) & \ + (dataframe["bb_ecart"] < dataframe["bb_ecart"].shift(1)) + dataframe["bb_tag"] = dataframe["bb_pente_inv"] & dataframe["bb_max_width"] + # dataframe['bb_min'] = talib.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min50_1.01'] = 1.01 * dataframe['min50'] + dataframe['min50_1.02'] = 1.02 * dataframe['min50'] + dataframe['min50_1.03'] = 1.03 * dataframe['min50'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = normalize(tib) #(tib-tib.min())/(tib.max()-tib.min()) + dataframe["trend_ichimoku_pente"] = (dataframe["trend_ichimoku_base"] - dataframe['trend_ichimoku_base'].shift(3)) / dataframe["trend_ichimoku_base"] + + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = normalize(tkd) #(tkd-tkd.min())/(tkd.max()-tkd.min()) + + # dataframe['trend_ichimoku_base_50'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=50) + # dataframe['trend_ichimoku_base_5'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=5) + # dataframe['trend_ichimoku_base_sma5'] = talib.SMA(dataframe['trend_ichimoku_base'], timeperiod=5) + # dataframe['trend_ichimoku_base_pct'] = dataframe['trend_ichimoku_base'].pct_change(3) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cond_50'] = talib.MIN(dataframe['cond1'], timeperiod=50) + dataframe['cond_5'] = talib.MIN(dataframe['cond1'], timeperiod=5) + dataframe['cond_sma5'] = talib.SMA(dataframe['cond1'], timeperiod=5) + dataframe['cond_pct'] = dataframe['cond1'].pct_change(3) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + #FreqAI / Rewards + # dataframe["%-raw_close"] = dataframe["close"] + # dataframe["%-raw_open"] = dataframe["open"] + # dataframe["%-raw_high"] = dataframe["high"] + # dataframe["%-raw_low"] = dataframe["low"] + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['max3'] = talib.MAX(informative['close'], timeperiod=3) + informative['max5'] = talib.MAX(informative['close'], timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['min3'] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['rsi_pente'] = informative['rsi'].pct_change(1) + informative['rsi_acc'] = informative['rsi_pente'].pct_change(1) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + # dataframe['support'] = min(dataframe['close_1d'], dataframe['sma3_1d'], dataframe['sma3_1d']) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # enter_long_conditions = [dataframe["do_predict"] == 1] #, dataframe["&-s_close"] > dataframe["target_roi"]] + # + # if enter_long_conditions: + # dataframe.loc[ + # reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] + # ] = (1, "long") + + base = 0.33 #self.buy_base.value + # base = base / dataframe[self.buy_rsi_ichimoku.value] * self.buy_rsi_divisor.value + base = base / dataframe['rsi'] * 52 + + decalage = 3 + dataframe.loc[ + ( + # (reduce(lambda x, y: x & y, enter_long_conditions)) + (dataframe['trend_ichimoku_base'].shift(decalage) <= base) + # & (dataframe['close'] > dataframe['close_1d']) + & (dataframe['rsi'].shift(decalage) < 60) + & (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)) + & (dataframe['close'].shift(decalage) < dataframe['bb_middleband'].shift(decalage)) + & (dataframe['bb_width'].shift(decalage) > 0.003) + # & (dataframe['close'].shift(decalage) < dataframe['bb_lower_width_5'].shift(decalage)) + & ((dataframe['close'].shift(decalage) <= dataframe['min50'].shift(decalage) * 1.002) | + (dataframe['pct_change_1_1h'].shift(decalage) > - 0.002) + ) + # & (dataframe['close'] <= dataframe['bb_upperband']) + # & (dataframe['close'] <= dataframe['min_200_001']) + & (dataframe['close'].shift(decalage) <= dataframe['close_1h'].shift(decalage)) + & ((dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)) | + (dataframe['pct_change_1_1h'].shift(decalage) > - 0.002) + ) + & (dataframe['close'] < dataframe['bb_upperband']) + & (dataframe['open'] < dataframe['bb_upperband']) + & ((dataframe['bb_pente_inv'] == 1) | (dataframe['bb_pente_inv'].shift(1) == 1) | (dataframe['bb_pente_inv'].shift(2) == 1) + | (dataframe['bb_pente_inv'].shift(3) == 1)) + ), ['buy', 'enter_tag']] = (1, 'buy_ichimoku') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + # last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + # self.protection_nb_buy_lost.value + if (0 < count_of_buys <= 2) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + if last_candle['close'] < last_candle['min5_1h']: + factors = [1.5 * p, 1.75 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + else: + if last_candle['close'] < last_candle['min3_1h']: + factors = [1.25 * p, 1.5 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + else: + factors = [1 * p, 1.25 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_2_B_4.json b/Zeus_8_3_2_B_4.json new file mode 100644 index 0000000..02db540 --- /dev/null +++ b/Zeus_8_3_2_B_4.json @@ -0,0 +1,83 @@ +{ + "strategy_name": "Zeus_8_3_2_B_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "max_open_trades": { + "max_open_trades": 8 + }, + "buy": { + "buy_rsi_1d": 45, + "buy_rsi_1h": 49, + "buy_sum_rsi_1d": 17.9, + "buy_sum_rsi_1h": 11.5 + }, + "sell": { + "pHSL": -0.99, + "pPF_1": 0.022, + "pSL_1": 0.021, + "pPF_2": 0.08, + "pSL_2": 0.04, + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": true, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": true, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": false, + "profit_h_quick_lost": true, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": true, + "profit_h_sma5": true, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 87, + "sell_b_RSI2": 82, + "sell_b_RSI2_percent": 0.007, + "sell_b_RSI3": 75, + "sell_b_candels": 23, + "sell_b_percent": 0.014, + "sell_b_percent3": 0.018, + "sell_b_profit_no_change": 0.003, + "sell_b_profit_percent10": 0.0011, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.013, + "sell_h_RSI": 82, + "sell_h_RSI2": 75, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 97, + "sell_h_candels": 6, + "sell_h_percent": 0.009, + "sell_h_percent3": 0.016, + "sell_h_profit_no_change": 0.017, + "sell_h_profit_percent10": 0.0014, + "sell_h_too_old_day": 3, + "sell_h_too_old_percent": 0.004 + }, + "protection": { + "protection_fibo": 9, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2023-02-18 16:52:23.048460+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2_B_4.jsonKeep b/Zeus_8_3_2_B_4.jsonKeep new file mode 100644 index 0000000..2bbf04f --- /dev/null +++ b/Zeus_8_3_2_B_4.jsonKeep @@ -0,0 +1,80 @@ +{ + "strategy_name": "Zeus_8_3_2_B_4", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "max_open_trades": { + "max_open_trades": 8 + }, + "buy": { + "buy_percent_max3": 0.98 + }, + "sell": { + "pHSL": -0.99, + "pPF_1": 0.022, + "pPF_2": 0.08, + "pSL_1": 0.021, + "pSL_2": 0.04, + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": true, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": true, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": false, + "profit_h_quick_lost": true, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": true, + "profit_h_sma5": true, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 87, + "sell_b_RSI2": 82, + "sell_b_RSI2_percent": 0.007, + "sell_b_RSI3": 75, + "sell_b_candels": 23, + "sell_b_percent": 0.014, + "sell_b_percent3": 0.018, + "sell_b_profit_no_change": 0.003, + "sell_b_profit_percent10": 0.0011, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.013, + "sell_h_RSI": 82, + "sell_h_RSI2": 75, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 97, + "sell_h_candels": 6, + "sell_h_percent": 0.009, + "sell_h_percent3": 0.016, + "sell_h_profit_no_change": 0.017, + "sell_h_profit_percent10": 0.0014, + "sell_h_too_old_day": 3, + "sell_h_too_old_percent": 0.004 + }, + "protection": { + "protection_fibo": 9, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2023-02-18 23:02:43.700998+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_2_B_4.py b/Zeus_8_3_2_B_4.py new file mode 100644 index 0000000..42c546c --- /dev/null +++ b/Zeus_8_3_2_B_4.py @@ -0,0 +1,1080 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +from freqtrade.strategy import stoploss_from_open, merge_informative_pair, DecimalParameter, IntParameter, CategoricalParameter + +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_2_B_4(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -1 #0.256 + # Custom stoploss + use_custom_stoploss = True + + # Buy hypers + timeframe = '5m' + + max_open_trades = 5 + max_amount = 40 + + # DCA config + position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + }, + "sar": { + "color": "#4f9f51", + }, + "min5_1d": { + "color": "#6aa123", + }, + "max5_1d": { + "color": "red" + }, + "max3_1d": { + "color": "blue" + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + # "Cond": { + # "cond1": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi": { + "color": "pink" + }, + "rsi_1d": { + "color": "yellow" + } + }, + "Percent": { + "max_min": { + "color": "#74effc" + }, + "pct_change_1_1d": { + "color": "green" + }, + "pct_change_3_1d": { + "color": "orange" + }, + "pct_change_5_1d": { + "color": "red" + }, + "sma5_pct": { + "color": "yellow" + } + } + } + } + trades = list() + # buy_real = DecimalParameter(0.001, 0.999, decimals=4, default=0.5392, space='buy') + # buy_cat = CategoricalParameter([">R", "=R", " float: + + # hard stoploss profit + HSL = self.pHSL.value + PF_1 = self.pPF_1.value + SL_1 = self.pSL_1.value + PF_2 = self.pPF_2.value + SL_2 = self.pSL_2.value + + # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + + if current_profit > PF_2: + sl_profit = SL_2 + (current_profit - PF_2) + elif current_profit > PF_1: + sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + else: + sl_profit = HSL + + return stoploss_from_open(sl_profit, current_profit) + + def custom_exit(self, pair: str, trade: Trade, current_time, current_rate, current_profit, **kwargs): + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + candle_12 = dataframe.iloc[-13].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + hours = (current_time - trade.open_date_utc).seconds / 3600 + + # fibo_fact = fibo[hours] + ###### + # if last_candle['percent5'] < -0.05: + # return "stop_loss_005" + + if last_candle['pct_change_1_1h'] <= 0: #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0) \ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.0005): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma5_s5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma10_s5'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((last_candle['sma20_s2'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if False: #self.profit_b_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (last_candle['percent10_s2'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) & (last_candle['percent3'] < 0)\ + & (last_candle['echange*pct12'] < 0.001): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma5_s5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((last_candle['sma10_s5'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (last_candle['sma10_s2'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((last_candle['sma20_s2'] > last_candle['sma20']) & + ((last_candle['percent'] < 0) & (last_candle['percent5'] < 0) & (last_candle['percent10'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if False: #self.profit_h_over_rsi.value: + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI.value): + # & (last_candle['percent'] < 0): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (last_candle['rsi_s2'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (last_candle['percent10_s2'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (last_candle['rsi_s2'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min50_005'] = dataframe['min50'] * 1.005 + dataframe['min200_005'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['mean10'] = dataframe['close'].rolling(10).mean() + dataframe['mean20'] = dataframe['close'].rolling(20).mean() + dataframe['mean50'] = dataframe['close'].rolling(50).mean() + dataframe['mean100'] = dataframe['close'].rolling(100).mean() + + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['min_max_50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi_pente'] = dataframe['rsi'].pct_change(1) + dataframe['rsi_acc'] = dataframe['rsi_pente'].pct_change(1) + dataframe['sum_rsi'] = (dataframe['rsi'].rolling(5).sum() - 250) / 5 + + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe["volume5"] = dataframe["volume"].rolling(5).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).sum() + + dataframe['sma5_s2'] = dataframe['sma5'].shift(1) + dataframe['sma10_s2'] = dataframe['sma10'].shift(1) + dataframe['sma20_s2'] = dataframe['sma20'].shift(1) + dataframe['percent10_s2'] = dataframe['percent10'].shift(1) + dataframe['rsi_s2'] = dataframe['rsi'].shift(1) + + dataframe['sma5_s5'] = dataframe['sma5'].shift(4) + dataframe['sma10_s5'] = dataframe['sma10'].shift(4) + dataframe['sma20_s5'] = dataframe['sma20'].shift(4) + # print(metadata['pair']) + # print(circulation[metadata['pair']]) + if circulation[metadata['pair']]: + dataframe["echange"] = 10000 * dataframe["volume"] / circulation[metadata['pair']] + dataframe["echange*pct"] = dataframe["echange"] * dataframe["percent"] + dataframe["echange5"] = 10000 * dataframe["volume5"] / circulation[metadata['pair']] + dataframe["echange*pct5"] = dataframe["echange5"] * dataframe["percent5"] + dataframe["pct_echange5"] = dataframe["echange5"].pct_change() + dataframe["acc_echange5"] = dataframe["echange*pct5"] / dataframe["echange*pct5"].shift(1) + for i in range(1, 4): + n = i * 12 + dataframe["echange*pct" + str(n)] = 10000 * dataframe["volume"].rolling(n).sum() / circulation[metadata['pair']] \ + * dataframe["percent"].rolling(n).sum() + + dataframe["pente20"] = (dataframe["close"] - dataframe['close'].shift(20)) / dataframe["close"] + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"])) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + dataframe["bb_pente"] = (dataframe["bb_lowerband"] - dataframe['bb_lowerband'].shift(3)) / dataframe["bb_lowerband"] + dataframe["bb_pente_inv"] = (dataframe["bb_pente"].shift(2) > dataframe["bb_pente"].shift(1)) & \ + (dataframe["bb_pente"] > dataframe["bb_pente"].shift(1)) + dataframe["bb_max_width"] = (dataframe["bb_ecart"].shift(2) < dataframe["bb_ecart"].shift(1)) & \ + (dataframe["bb_ecart"] < dataframe["bb_ecart"].shift(1)) + dataframe["bb_tag"] = dataframe["bb_pente_inv"] & dataframe["bb_max_width"] + # dataframe['bb_min'] = talib.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min50_1.01'] = 1.01 * dataframe['min50'] + dataframe['min50_1.02'] = 1.02 * dataframe['min50'] + dataframe['min50_1.03'] = 1.03 * dataframe['min50'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = normalize(tib) #(tib-tib.min())/(tib.max()-tib.min()) + dataframe["trend_ichimoku_pente"] = (dataframe["trend_ichimoku_base"] - dataframe['trend_ichimoku_base'].shift(3)) / dataframe["trend_ichimoku_base"] + + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = normalize(tkd) #(tkd-tkd.min())/(tkd.max()-tkd.min()) + + # dataframe['trend_ichimoku_base_50'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=50) + # dataframe['trend_ichimoku_base_5'] = talib.MIN(dataframe['trend_ichimoku_base'], timeperiod=5) + # dataframe['trend_ichimoku_base_sma5'] = talib.SMA(dataframe['trend_ichimoku_base'], timeperiod=5) + # dataframe['trend_ichimoku_base_pct'] = dataframe['trend_ichimoku_base'].pct_change(3) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['cond_50'] = talib.MIN(dataframe['cond1'], timeperiod=50) + dataframe['cond_5'] = talib.MIN(dataframe['cond1'], timeperiod=5) + dataframe['cond_sma5'] = talib.SMA(dataframe['cond1'], timeperiod=5) + dataframe['cond_pct'] = dataframe['cond1'].pct_change(3) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + #FreqAI / Rewards + # dataframe["%-raw_close"] = dataframe["close"] + # dataframe["%-raw_open"] = dataframe["open"] + # dataframe["%-raw_high"] = dataframe["high"] + # dataframe["%-raw_low"] = dataframe["low"] + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative, timeperiod=7) + informative['sum_rsi'] = (informative['rsi'].rolling(5).sum() - 250) / 5 + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['max3'] = talib.MAX(informative['close'], timeperiod=3) + informative['max5'] = talib.MAX(informative['close'], timeperiod=5) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['min3'] = talib.MIN(informative['close'], timeperiod=3) + informative['min5'] = talib.MIN(informative['close'], timeperiod=5) + informative['rsi_pente'] = informative['rsi'].pct_change(1) + informative['rsi_acc'] = informative['rsi_pente'].pct_change(1) + informative['sum_rsi'] = (informative['rsi'].rolling(5).sum() - 250) / 5 + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + # dataframe['support'] = min(dataframe['close_1d'], dataframe['sma3_1d'], dataframe['sma3_1d']) + return dataframe + + # def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + # current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + # + # # {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489, + # # 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198, + # # 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808, + # # 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799, + # # 'info': + # # {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667', + # # 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000', + # # 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000', + # # 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000', + # # 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000', + # # 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570', + # # 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484 + # + # allow_to_buy = True + # max_gain = -100 + # sum_gain = 0 + # max_time = 0 + # + # if self.dp: + # if self.dp.runmode.value in ('live', 'dry_run'): + # if len(self.trades) == 0: + # print('search') + # self.trades = Trade.get_open_trades() + # + # if len(self.trades) >= self.config['max_open_trades'] / 2: + # for trade in self.trades: + # ticker = self.dp.ticker(trade.pair) + # last_price = ticker['last'] + # gain = (last_price - trade.open_rate) / trade.open_rate + # max_gain = max(max_gain, gain) + # sum_gain += gain + # max_time = max(max_time, datetime.timestamp(trade.open_date)) + # print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date), + # datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000)) + # now = datetime.now() + # diff = (datetime.timestamp(now) - max_time / 3600) + # if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6): + # print("allow_to_buy=false") + # allow_to_buy = False + # print(pair, allow_to_buy, len(self.trades), + # "max gain=", max_gain, + # "sum_gain=", sum_gain, + # "now=", now, + # "max=", max_time, + # "diff=", datetime.timestamp(now) - max_time) + # + # if allow_to_buy: + # self.trades = list() + # + # return allow_to_buy + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # enter_long_conditions = [dataframe["do_predict"] == 1] #, dataframe["&-s_close"] > dataframe["target_roi"]] + # + # if enter_long_conditions: + # dataframe.loc[ + # reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] + # ] = (1, "long") + + base = 0.33 #self.buy_base.value + # base = base / dataframe[self.buy_rsi_ichimoku.value] * self.buy_rsi_divisor.value + base = base / dataframe['rsi'] * 52 + + decalage = 3 + dataframe.loc[ + ( + # (reduce(lambda x, y: x & y, enter_long_conditions)) + (dataframe['trend_ichimoku_base'].shift(decalage) <= base) + # & (dataframe['close'] > dataframe['close_1d']) + & (dataframe['rsi'].shift(decalage) < 60) + & (dataframe['close'].shift(decalage) < dataframe['sma10'].shift(decalage)) + & (dataframe['close'].shift(decalage) < dataframe['bb_middleband'].shift(decalage)) + & (dataframe['bb_width'].shift(decalage) > 0.025) + # & (dataframe['close'].shift(decalage) < dataframe['bb_lower_width_5'].shift(decalage)) + & ((dataframe['close'].shift(decalage) <= dataframe['min50'].shift(decalage) * 1.002) | + (dataframe['pct_change_1_1h'].shift(decalage) > - 0.002) + ) + # & (dataframe['close'] <= dataframe['bb_upperband']) + # & (dataframe['close'] <= dataframe['min_200_001']) + & (dataframe['close'].shift(decalage) <= dataframe['close_1h'].shift(decalage)) + & ((dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage)) | + (dataframe['pct_change_1_1h'].shift(decalage) > - 0.002) + ) + & (dataframe['close'] < dataframe['bb_upperband']) + & (dataframe['open'] < dataframe['bb_upperband']) + & ((dataframe['bb_pente_inv'] == 1) | (dataframe['bb_pente_inv'].shift(1) == 1) | (dataframe['bb_pente_inv'].shift(2) == 1) + | (dataframe['bb_pente_inv'].shift(3) == 1)) + # & (dataframe['close_1d'] < dataframe['bb_upperband_1d']) + ), ['buy', 'enter_tag']] = (1, 'buy_ichimoku') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if True: #(len(dataframe) < 1): + return None + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + # last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + # self.protection_nb_buy_lost.value + if (0 < count_of_buys <= 2) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + if last_candle['close'] < last_candle['min5_1h']: + factors = [1.5 * p, 1.75 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + else: + if last_candle['close'] < last_candle['min3_1h']: + factors = [1.25 * p, 1.5 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + else: + factors = [1 * p, 1.25 * p, 2 * p, 2 * p, 3 * p, 4 * p, 5 * p, 6 * p] + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_2_B_4_2.json b/Zeus_8_3_2_B_4_2.json new file mode 100644 index 0000000..f28e416 --- /dev/null +++ b/Zeus_8_3_2_B_4_2.json @@ -0,0 +1,83 @@ +{ + "strategy_name": "Zeus_8_3_2_B_4_2", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "max_open_trades": { + "max_open_trades": 3 + }, + "buy": { + "buy_rsi_1d": 45, + "buy_rsi_1h": 49, + "buy_sum_rsi_1d": 17.9, + "buy_sum_rsi_1h": 11.5 + }, + "sell": { + "pHSL": -0.99, + "pPF_1": 0.022, + "pSL_1": 0.015, + "pPF_2": 0.05, + "pSL_2": 0.03, + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": true, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": true, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": false, + "profit_h_quick_lost": true, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": true, + "profit_h_sma5": true, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 87, + "sell_b_RSI2": 82, + "sell_b_RSI2_percent": 0.007, + "sell_b_RSI3": 75, + "sell_b_candels": 23, + "sell_b_percent": 0.014, + "sell_b_percent3": 0.018, + "sell_b_profit_no_change": 0.003, + "sell_b_profit_percent10": 0.0011, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.013, + "sell_h_RSI": 82, + "sell_h_RSI2": 75, + "sell_h_RSI2_percent": 0.011, + "sell_h_RSI3": 97, + "sell_h_candels": 6, + "sell_h_percent": 0.009, + "sell_h_percent3": 0.016, + "sell_h_profit_no_change": 0.017, + "sell_h_profit_percent10": 0.0014, + "sell_h_too_old_day": 300, + "sell_h_too_old_percent": 0.004 + }, + "protection": { + "protection_fibo": 9, + "protection_percent_buy_lost": 3 + } + }, + "ft_stratparam_v": 1, + "export_time": "2023-02-18 16:52:23.048460+00:00" +} diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py new file mode 100644 index 0000000..ce529e0 --- /dev/null +++ b/Zeus_8_3_2_B_4_2.py @@ -0,0 +1,1365 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from freqtrade.persistence import Trade +from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, stoploss_from_open, + IntParameter, IStrategy, merge_informative_pair, informative, stoploss_from_absolute) +import pandas as pd +import numpy as np +from pandas import DataFrame +from typing import Optional, Union, Tuple + +import logging +import configparser +from technical import pivots_points +# -------------------------------- + +# Add your lib to import here +import ta +import talib.abstract as talib +import freqtrade.vendor.qtpylib.indicators as qtpylib +import requests + +logger = logging.getLogger(__name__) + +from tabulate import tabulate + + +def pprint_df(dframe): + print(tabulate(dframe, headers='keys', tablefmt='psql', showindex=False)) + + +def normalize(df): + df = (df - df.min()) / (df.max() - df.min()) + return df + + +def get_limit_from_config(section, pair): + file_path = '/HOME/home/souti/freqtrade2/user_data/strategies/Zeus_8_3_2_B_4_2.txt' + # Créez un objet ConfigParser + config = configparser.ConfigParser() + + try: + # Lisez le fichier avec les valeurs + config.read(file_path) + + # Vérifiez si la section existe + if config.has_section(section): + # Obtenez les valeurs à partir de la section et de la clé (pair) + limit = config.get(section, pair) + return limit + else: + raise ValueError(f"La section '{section}' n'existe pas dans le fichier de configuration.") + except Exception as e: + print(f"Erreur lors de la lecture du fichier de configuration : {e}") + return None + + +class Zeus_8_3_2_B_4_2(IStrategy): + levels = [1, 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -1 # 0.256 + # Custom stoploss + use_custom_stoploss = True + + # Buy hypers + timeframe = '5m' + + max_open_trades = 5 + max_amount = 40 + + # DCA config + position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "max50": { + "color": "white" + }, + "max200": { + "color": "yellow" + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + "Rsi": { + "rsi": { + "color": "pink" + } + }, + "Percent": { + "max_min": { + "color": "#74effc" + } + } + } + } + + # 20 20 40 60 100 160 260 420 + # 50 50 100 300 500 + # fibo = [1, 1, 2, 3, 5, 8, 13, 21] + # my fibo + # 50 50 50 100 100 150 200 250 350 450 600 1050 + fibo = [1, 1, 1, 2, 2, 3, 4, 5, 7, 9, 12, 16, 21] + baisse = [1, 2, 3, 5, 7, 10, 14, 19, 26, 35, 47, 63, 84] + # Ma suite 1 1 1 2 2 3 4 5 7 9 12 16 21 + # Mise 50 50 50 100 100 150 200 250 350 450 600 800 1050 + # Somme Mises 50 100 150 250 350 500 700 950 1300 1750 2350 3150 4200 + # baisse 1 2 3 5 7 10 14 19 26 35 47 63 84 + + trades = list() + max_profit_pairs = {} + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=300, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent12 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=300, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent12 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + protection_percent_buy_lost = IntParameter(1, 10, default=5, space='protection') + # protection_nb_buy_lost = IntParameter(1, 2, default=2, space='protection') + + protection_fibo = IntParameter(1, 10, default=2, space='protection') + + # trailing stoploss hyperopt parameters + # hard stoploss profit + sell_allow_decrease = DecimalParameter(0.005, 0.02, default=0.2, decimals=2, space='sell', optimize=True, load=True) + + pHSL = DecimalParameter(-0.200, -0.040, default=-0.08, decimals=3, space='sell', optimize=False, load=True) + # profit threshold 1, trigger point, SL_1 is used + pPF_1 = DecimalParameter(0.008, 0.020, default=0.016, decimals=3, space='sell', optimize=True, load=True) + pSL_1 = DecimalParameter(0.008, 0.020, default=0.011, decimals=3, space='sell', optimize=True, load=True) + + # profit threshold 2, SL_2 is used + pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True) + pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True) + + def min_max_scaling(self, series: pd.Series) -> pd.Series: + """Normaliser les données en les ramenant entre 0 et 100.""" + return 100 * (series - series.min()) / (series.max() - series.min()) + + def z_score_scaling(self, series: pd.Series) -> pd.Series: + """Normaliser les données en utilisant Z-Score Scaling.""" + return (series - series.mean()) / series.std() + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + # count_buys = 0 + # trade = self.getTrade(pair) + # if trade: + # filled_buys = trade.select_filled_orders('buy') + # count_buys = len(filled_buys) + + print('entry_tag' + str(entry_tag)) + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + # last_candle_12 = dataframe.iloc[-13].squeeze() + limit = get_limit_from_config('Achats', pair) + + # allow_to_buy = True #(not self.stop_all) #& (not self.all_down) + allow_to_buy = True # (rate <= float(limit)) | (entry_tag == 'force_entry') + # allow_to_buy = rate <= dataframe['lbp_3'] + self.trades = list() + dispo = round(self.wallets.get_available_stake_amount()) + logger.info(f"{pair} allow_to_buy {allow_to_buy} limit={limit} Buy {entry_tag} {current_time} dispo={dispo}") + + return allow_to_buy + + def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, + time_in_force: str, + exit_reason: str, current_time, **kwargs, ) -> bool: + # allow_to_sell = (minutes > 30) + limit = get_limit_from_config('Ventes', pair) + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + + allow_to_sell = (last_candle['percent'] < 0) # rate > float(limit) + string = "" + + if allow_to_sell: + self.trades = list() + logger.info('Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str( + round(self.wallets.get_available_stake_amount())) # "+ str(amount) + ' ' + str(rate) + + " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit=" + str( + trade.calc_profit(rate, amount)) + + " " + string) + # del self.max_profit_pairs[pair] + else: + logger.info('Cancel Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair) + return (allow_to_sell) | (exit_reason == 'force_exit') + + def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, + proposed_stake: float, min_stake: float, max_stake: float, + **kwargs) -> float: + + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + current_candle = dataframe.iloc[-1].squeeze() + adjusted_stake_amount = self.adjust_stake_amount(pair, current_candle) + + logger.info(f"{pair} adjusted_stake_amount{adjusted_stake_amount}") + + # Use default stake amount. + return adjusted_stake_amount + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + # # hard stoploss profit + # HSL = self.pHSL.value + # PF_1 = self.pPF_1.value + # SL_1 = self.pSL_1.value + # PF_2 = self.pPF_2.value + # SL_2 = self.pSL_2.value + # + # # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + # + # if current_profit > PF_2: + # sl_profit = SL_2 + (current_profit - PF_2) + # elif current_profit > PF_1: + # sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + # else: + # sl_profit = HSL + + #print(f"entry_tag={trade.entry_tag} max={trade.max_rate} min={trade.min_rate} ") + if current_profit > 0.0125: + sl_profit = 0.75 * current_profit # 75% du profit en cours + else: + sl_profit = self.pHSL.value # Hard stop-loss + stoploss = stoploss_from_open(sl_profit, current_profit) + logger.info(f"stoploss={stoploss}") + return stoploss + + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # last_candle = dataframe.iloc[-1].squeeze() + # limit = get_limit_from_config('Ventes', pair) + # + # print(pair + " " + str(current_rate) + " " + str(limit)) + # + # #stop_loss = self.adjust_stop_loss(dataframe.iloc[-1]) + # + # #if current_rate < float(limit): + # # return -1 + # + # # "pHSL": -0.99, + # # "pPF_1": 0.022, + # # "pSL_1": 0.021, + # # "pPF_2": 0.08, + # # "pSL_2": 0.04, + # # + # # hard stoploss profit + # HSL = self.pHSL.value + # PF_1 = self.pPF_1.value + # SL_1 = self.pSL_1.value + # PF_2 = self.pPF_2.value + # SL_2 = self.pSL_2.value + # + # # For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated + # # between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value + # # rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used. + # + # # 0.04 + # if current_profit > PF_2: + # # 0.04 + (current_profit - 0.08) + # sl_profit = SL_2 + (current_profit - PF_2) + # # 0.022 + # elif current_profit > PF_1: + # # 0.021 + ((current_profit - 0.022) * (0.04 - 0.021) / (0.08 - 0.022)) + # sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1)) + # else: + # sl_profit = HSL + # + # slfo = stoploss_from_open(sl_profit, current_profit) + # print('current_profit=' + str(current_profit) + ' stop from open=' + str(slfo)) + # return slfo + + # def custom_exit(self, pair: str, trade: Trade, current_time, current_rate, current_profit, **kwargs): + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # last_candle = dataframe.iloc[-1].squeeze() + # + # # self.analyze_conditions(pair, dataframe) + # + # print("---------------" + pair + "----------------") + # expected_profit = self.expectedProfit(pair, last_candle) + # + # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # last_candle = dataframe.iloc[-1] + # + # # Calcul du prix cible basé sur l'ATR + # atr_take_profit = trade.open_rate + (last_candle['atr'] * 2) # Prendre profit à 2x l'ATR + # + # logger.info(f"{pair} Custom exit atr_take_profit={atr_take_profit:.4f}") + # # if current_rate >= atr_take_profit: + # # return 'sell_atr_take_profit' + # + # if (last_candle['percent3'] < -0.002) & (last_candle['percent12'] < 0) & ( + # current_profit > last_candle['min_max200'] / 2): + # self.trades = list() + # return 'min_max200' + # if (last_candle['percent12'] <= -0.01) & (current_profit >= expected_profit): + # self.trades = list() + # return 'profit' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + pair = metadata['pair'] + + dataframe['achats'] = get_limit_from_config('Achats', pair) + dataframe['ventes'] = get_limit_from_config('Ventes', pair) + + heikinashi = qtpylib.heikinashi(dataframe) + dataframe['haopen'] = heikinashi['open'] + dataframe['haclose'] = heikinashi['close'] + dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] + + dataframe['close_02'] = dataframe['haclose'] * 1.02 + + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min12'] = talib.MIN(dataframe['close'], timeperiod=12) + + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max144'] = talib.MAX(dataframe['close'], timeperiod=144) + dataframe['min_max50'] = (dataframe['max50'] - dataframe['min50']) / dataframe['min50'] + + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['max200_diff'] = (dataframe['max200'] - dataframe['close']) / dataframe['close'] + dataframe['max50_diff'] = (dataframe['max50'] - dataframe['close']) / dataframe['close'] + + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent3"] = (dataframe["close"] - dataframe["open"].shift(3)) / dataframe["open"].shift(3) + dataframe["percent5"] = (dataframe["close"] - dataframe["open"].shift(5)) / dataframe["open"].shift(5) + dataframe["percent12"] = (dataframe["close"] - dataframe["open"].shift(12)) / dataframe["open"].shift(12) + dataframe["percent24"] = (dataframe["close"] - dataframe["open"].shift(24)) / dataframe["open"].shift(24) + dataframe["percent48"] = (dataframe["close"] - dataframe["open"].shift(48)) / dataframe["open"].shift(48) + dataframe["percent_max_144"] = (dataframe["close"] - dataframe["max144"]) / dataframe["close"] + + dataframe['sma10_s2'] = dataframe['sma10'].shift(1) + dataframe['sma20_s2'] = dataframe['sma20'].shift(1) + dataframe['percent12_s2'] = dataframe['percent12'].shift(1) + + dataframe['sma5_s5'] = dataframe['sma5'].shift(4) + dataframe['sma10_s5'] = dataframe['sma10'].shift(4) + dataframe['sma20_s5'] = dataframe['sma20'].shift(4) + # print(metadata['pair']) + dataframe['rsi'] = talib.RSI(dataframe['close'], length=14) + + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + + # Normalization + + dataframe['average_line'] = dataframe['close'].mean() + dataframe['average_line_50'] = talib.MIDPOINT(dataframe['close'], timeperiod=50) + + dataframe['average_line_288'] = talib.MIDPOINT(dataframe['close'], timeperiod=288) + dataframe['average_line_288_098'] = dataframe['average_line_288'] * 0.98 + dataframe['average_line_288_099'] = dataframe['average_line_288'] * 0.99 + # Sort the close prices to find the 4 lowest values + sorted_close_prices = dataframe['close'].tail(576).sort_values() + lowest_4 = sorted_close_prices.head(20) + + dataframe['lowest_4_average'] = lowest_4.mean() + # Propagate this mean value across the entire dataframe + # dataframe['lowest_4_average'] = dataframe['lowest_4_average'].iloc[0] + + # # Sort the close prices to find the 4 highest values + sorted_close_prices = dataframe['close'].tail(288).sort_values(ascending=False) + highest_4 = sorted_close_prices.head(20) + + # # Calculate the mean of the 4 highest values + dataframe['highest_4_average'] = highest_4.mean() + + # # Propagate this mean value across the entire dataframe + # dataframe['highest_4_average'] = dataframe['highest_4_average'].iloc[0] + + dataframe['volatility'] = talib.STDDEV(dataframe['close'], timeperiod=144) / dataframe['close'] + dataframe['atr'] = talib.ATR(dataframe['high'], dataframe['low'], dataframe['close'], timeperiod=144) / \ + dataframe['close'] + # dataframe['pct_average'] = (dataframe['highest_4_average'] - dataframe['close']) / dataframe['lowest_4_average'] + # dataframe['highest_4_average_1'] = dataframe['highest_4_average'] * 0.99 + # dataframe['highest_4_average_2'] = dataframe['highest_4_average'] * 0.98 + # dataframe['highest_4_average_3'] = dataframe['highest_4_average'] * 0.97 + # dataframe['highest_4_average_4'] = dataframe['highest_4_average'] * 0.96 + # dataframe['highest_4_average_5'] = dataframe['highest_4_average'] * 0.95 + + # Normaliser les données de 'close' + # normalized_close = self.min_max_scaling(dataframe['close']) + ################### INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative['volatility'] = talib.STDDEV(informative['close'], timeperiod=14) / informative['close'] + informative['atr'] = (talib.ATR(informative['high'], informative['low'], informative['close'], timeperiod=14)) / informative['close'] + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + ################### INFORMATIVE 1d + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + sorted_close_prices = informative['close'].tail(365).sort_values() + lowest_4 = sorted_close_prices.head(4) + informative['lowest_4'] = lowest_4.mean() + + sorted_close_prices = informative['close'].tail(365).sort_values(ascending=False) + highest_4 = sorted_close_prices.head(4) + informative['highest_4'] = highest_4.mean() + + last_14_days = informative.tail(14) + + # Récupérer le minimum et le maximum de la colonne 'close' des 14 derniers jours + min_14_days = last_14_days['close'].min() + max_14_days = last_14_days['close'].max() + informative['lowest'] = min_14_days + informative['highest'] = max_14_days + informative['pct_min_max'] = (max_14_days - min_14_days) / min_14_days + informative['mid_min_max'] = min_14_days + (max_14_days - min_14_days) / 2 + informative['middle'] = informative['lowest_4'] + (informative['highest_4'] - informative['lowest_4']) / 2 + informative['mid_min_max_0.98'] = informative['mid_min_max'] * 0.98 + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + dataframe['count_buys'] = 0 + + dataframe['last_price'] = dataframe['close'] + dataframe['first_price'] = dataframe['close'] + dataframe['mid_price'] = (dataframe['last_price'] + dataframe['first_price']) / 2 + dataframe['close01'] = dataframe.iloc[-1]['close'] * 1.01 + dataframe['amount'] = 0 + dataframe['limit'] = dataframe['close'] + count_buys = 0 + if self.dp: + if self.dp.runmode.value in ('live', 'dry_run'): + self.getOpenTrades() + + for trade in self.trades: + if trade.pair != pair: + continue + print(trade) + filled_buys = trade.select_filled_orders('buy') + dataframe['count_buys'] = len(filled_buys) + count = 0 + amount = 0 + for buy in filled_buys: + if count == 0: + dataframe['first_price'] = buy.price + dataframe['close01'] = buy.price * 1.01 + + # Order(id=2396, trade=1019, order_id=29870026652, side=buy, filled=0.00078, price=63921.01, + # status=closed, date=2024-08-26 02:20:11) + dataframe['last_price'] = buy.price + print(buy) + count = count + 1 + amount += buy.price * buy.filled + dataframe['mid_price'] = (dataframe['last_price'] + dataframe['first_price']) / 2 + count_buys = count + dataframe['limit'] = dataframe['last_price'] * (1 - self.baisse[count] / 100) + dataframe['amount'] = amount + print(f"amount= {amount}") + # trades = Trade.get_trades([Trade.is_open is False]).all() + trades = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + if trades: + trade = trades[-1] + print('closed trade pair is : ') + print(trade) + dataframe['expected_profit'] = (1 + self.expectedProfit(pair, dataframe.iloc[-1])) * dataframe[ + 'last_price'] + dataframe['lbp'] = dataframe['last_price'] + dataframe['lbp_3'] = dataframe['lbp'] * 0.97 # 3 + dataframe['lbp_6'] = dataframe['lbp'] * 0.94 # 6 + dataframe['lbp_9'] = dataframe['lbp'] * 0.90 # 10 + dataframe['lbp_12'] = dataframe['lbp'] * 0.85 # 15 + dataframe['lbp_20'] = dataframe['lbp'] * 0.8 # 20 + dataframe['fbp'] = trade.open_rate + # else: + # last_trade = self.get_trades(pair=pair).order_by('-close_date').first() + # filled_buys = last_trade.select_filled_orders('buy') + # print(last_trade) + # for buy in filled_buys: + # print(filled_buys) + + dataframe['buy_level'] = dataframe['lowest_4_average'] * (1 - self.levels[count_buys] / 100) + # ---------------------------------------------------------- + # Calcul de la variation entre deux bougies successives + dataframe['price_change'] = dataframe['close'].diff() + + # Marquer les bougies en baisse + dataframe['is_down'] = dataframe['price_change'] < 0 + + # Identifier les blocs consécutifs de baisses + # dataframe['drop_id'] = (dataframe['is_down'] != dataframe['is_down'].shift(1)).cumsum() + dataframe['drop_id'] = np.where(dataframe['is_down'], + (dataframe['is_down'] != dataframe['is_down'].shift(12)).cumsum(), np.nan) + + # Identifier uniquement les blocs de baisse + dataframe['drop_id'] = dataframe['drop_id'].where(dataframe['is_down']) + # # Grouper par les chutes détectées + # drop_info = dataframe.groupby('drop_id').agg( + # start=('close', 'first'), # Prix au début de la chute + # end=('close', 'last'), # Prix à la fin de la chute + # start_index=('close', 'idxmin'), # Début de la chute (index) + # end_index=('close', 'idxmax'), # Fin de la chute (index) + # ) + # + # # Calcul de l'ampleur de la chute en % + # drop_info['drop_amplitude_pct'] = ((drop_info['end'] - drop_info['start']) / drop_info['start']) * 100 + # # Filtrer les chutes avec une amplitude supérieure à 3% + # drop_info = drop_info[drop_info['drop_amplitude_pct'] < -3] + + # ************** + + # Identifier le prix de début et de fin de chaque chute + drop_stats = dataframe.groupby('drop_id').agg( + start_price=('close', 'first'), # Prix au début de la chute + end_price=('close', 'last'), # Prix à la fin de la chute + ) + + # Calculer l'amplitude en % + drop_stats['amplitude_pct'] = ((drop_stats['end_price'] - drop_stats['start_price']) / drop_stats[ + 'start_price']) * 100 + # drop_stats = drop_stats[drop_stats['amplitude_pct'] < -1] + # Associer les amplitudes calculées à chaque drop_id dans dataframe + dataframe = dataframe.merge(drop_stats[['amplitude_pct']], on='drop_id', how='left') + # Remplir les lignes sans drop_id par 0 + dataframe['amplitude_pct'] = dataframe['amplitude_pct'].fillna(0) + dataframe['amplitude_pct_60'] = dataframe['amplitude_pct'].rolling(60).sum() + # ---------------------------------------------------------- + + self.getBinanceOrderBook(pair, dataframe) + + return dataframe + + def getOpenTrades(self): + # if len(self.trades) == 0: + print('search open trades') + self.trades = Trade.get_open_trades() + return self.trades + + def getTrade(self, pair): + trades = self.getOpenTrades() + trade_for_pair = None + for trade in trades: + if trade.pair == pair: + trade_for_pair = trade + break + return trade_for_pair + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + pair = metadata['pair'] + + self.getOpenTrades() + expected_profit = self.expectedProfit(pair, dataframe.iloc[-1]) + # self.getBinanceOrderBook(pair, dataframe) + last_candle = dataframe.iloc[-1].squeeze() + # limit = last_candle['first_price'] * (1 - self.baisse[last_candle['count_buys']] / 100) + + # self.updateLastValue(dataframe, 'expected_profit', expected_profit) + print("---------------" + pair + "----------------") + print('adjust stake amount ' + str(self.adjust_stake_amount(pair, dataframe.iloc[-1]))) + print('adjust exit price ' + str(self.adjust_exit_price(dataframe.iloc[-1]))) + print('calcul expected_profit ' + str(expected_profit)) + + buy_level = dataframe['buy_level'] # self.get_buy_level(pair, dataframe) + + dataframe.loc[ + ( + (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['percent_max_144'] <= -0.012) + & (dataframe['haopen'] < buy_level) + & (dataframe['open'] < dataframe['average_line_288']) + & (dataframe['min50'].shift(3) == dataframe['min50']) + ), ['buy', 'enter_tag']] = (1, 'buy_fractal') + + dataframe.loc[ + ( + (dataframe['max200_diff'].shift(4) >= 0.015) + & (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['max50_diff'].shift(4) >= 0.01) + & (dataframe['haclose'] < dataframe['bb_middleband']) + & (dataframe['close'] < buy_level) + & (dataframe['open'] < dataframe['average_line_288']) + & (dataframe['min50'].shift(3) == dataframe['min50']) + ), ['buy', 'enter_tag']] = (1, 'buy_max_diff_015') + + dataframe.loc[ + ( + (dataframe['max200_diff'] >= 0.018) + & (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['max50_diff'] >= 0.009) + & (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['haclose'] < dataframe['bb_middleband']) + & (dataframe['close'] < buy_level) + & (dataframe['open'] < dataframe['average_line_288']) + & (dataframe['min50'].shift(3) == dataframe['min50']) + ), ['buy', 'enter_tag']] = (1, 'buy_max_diff_018') + + # dataframe.loc[ + # ( + # (dataframe['max200_diff'] >= 0.018) + # & (dataframe['open'] < dataframe['average_line_288']) + # & (dataframe['close'] < dataframe['min12'] * 1.002) + # & (dataframe['min12'].shift(2) == dataframe['min12']) + # ), ['buy', 'enter_tag']] = (1, 'buy_min_max200') + dataframe.loc[ + ( + (dataframe['max200_diff'] >= 0.025) + & (dataframe['percent12'] < -0.002) + & (dataframe['pct_change'] < 0) + & (dataframe['open'] < dataframe['average_line_288_099']) + & (dataframe['open'] < dataframe['average_line_50']) + & (dataframe['count_buys'] == 0 | + ((dataframe['count_buys'] > 0) & (dataframe['close'] <= dataframe['limit'])) + ) + & (dataframe['percent'] >= -0.0005) + & (dataframe['min12'].shift(2) == dataframe['min12']) + ), ['buy', 'enter_tag']] = (1, 'buy_min_max200_2') + dataframe.loc[ + ( + ((dataframe['count_buys'] > 0) & (dataframe['close'] <= dataframe['limit'])) + & (dataframe['close'] < dataframe['min200'] * 1.002) + # & (dataframe['percent'] >= -0.0005) + & ( + (dataframe['min12'].shift(2) == dataframe['min12']) | + (dataframe['min200'].shift(60) >= dataframe['min200'] * 1.03) + ) + ), ['buy', 'enter_tag']] = (1, 'buy_count_buy') + + dataframe.loc[ + ( + ( + (dataframe['percent12'] < -0.015) | + (dataframe['percent24'] < -0.022) | + (dataframe['percent48'] < -0.030) + ) + & (dataframe['count_buys'] == 0) + & (dataframe['close'] <= dataframe['min50'] * 1.002) + & (dataframe['open'] < dataframe['average_line_50']) + & ( + (dataframe['close'] < dataframe['min12'] * 1.002) + | (dataframe['percent12'] < -0.022) + | (dataframe['percent24'] < -0.022) + ) + & ( + (dataframe['min50'].shift(2) == dataframe['min50']) + | (dataframe['percent12'] < -0.022) + | (dataframe['percent24'] < -0.022) + ) + ), ['buy', 'enter_tag']] = (1, 'buy_0_percent12') + dataframe.loc[ + ( + # (dataframe['percent12'] < -0.015) + ((dataframe['count_buys'] > 0) & (dataframe['close'] <= dataframe['limit'])) + & (dataframe['open'] < dataframe['average_line_50']) + & (dataframe['close'] < dataframe['min12'] * 1.002) + & (dataframe['min12'].shift(2) == dataframe['min12']) + ), ['buy', 'enter_tag']] = (1, 'buy_percent12') + + dataframe.loc[ + ( + (dataframe['percent_max_144'] <= -0.02) + & (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['haopen'] < buy_level) + & (dataframe['min50'].shift(3) == dataframe['min50']) + & (dataframe['close'] <= dataframe['min50'] * 1.002) + & (dataframe['open'] < dataframe['average_line_288']) + ), ['buy', 'enter_tag']] = (1, 'buy_percent_max_144') + dataframe.loc[ + ( + (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe['min_max200'] > 0.015) + & (dataframe['pct_change'] < 0) + & (dataframe['haopen'] < buy_level) + & (dataframe['open'] < dataframe['average_line_288']) + ), ['buy', 'enter_tag']] = (1, 'buy_min_max_200') + dataframe.loc[ + ( + (dataframe['percent_max_144'] <= -0.02) + & (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['close_02'] < dataframe['max144']) + & (dataframe['haopen'] < buy_level) + & (dataframe['close'] <= dataframe['average_line_288_099']) + & (dataframe['min50'].shift(3) == dataframe['min50']) + & (dataframe['close'] <= dataframe['min50'] * 1.002) + ), ['buy', 'enter_tag']] = (1, 'buy_close_02') + dataframe.loc[ + ( + (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['haopen'] >= dataframe['lbp_3']) + & (dataframe['haclose'] <= dataframe['lbp_3']) + & (dataframe['haopen'] < buy_level) + ), ['buy', 'enter_tag']] = (1, 'buy_lbp_3') + dataframe.loc[ + ( + (dataframe['close'] <= dataframe['lowest_4_average'] * 1.002) + & (dataframe['haopen'] >= dataframe['average_line_288_098']) + & (dataframe['haclose'] <= dataframe['average_line_288_098']) + & (dataframe['haopen'] < buy_level) + ), ['buy', 'enter_tag']] = (1, 'buy_average_line_288_098') + dataframe.loc[ + ( + (dataframe['close'].shift(2) <= dataframe['min200']) + & (dataframe['pct_change'] < 0) + & (dataframe['min200'].shift(2) == dataframe['min200']) + & (dataframe['close'] < dataframe['lowest_4_average']) + & (dataframe['count_buys'] == 0 | + ((dataframe['count_buys'] > 0) & (dataframe['close'] <= dataframe['limit'])) + ) + ), ['buy', 'enter_tag']] = (1, 'buy_min200') + + dataframe['test'] = np.where(dataframe['buy'] == 1, dataframe['close'] * 1.01, np.nan) + + return dataframe + + # def get_buy_level(self, pair, dataframe): + # limit = get_limit_from_config('Achats', pair) + # + # filled_buys = {} + # for trade in self.trades: + # if trade.pair != pair: + # continue + # filled_buys = trade.select_filled_orders('buy') + # print('populate_buy_trend filled_buys : ' + str(len(filled_buys))) + # # Affichez les valeurs + # print(pair, limit) + # # BUY_LEVELS = { + # # 'BTC/USDT': [int(btc_limit), 42600, 41000, 40000, 39000, 38000, 37000, 36000, 35000], + # # 'ETH/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], + # # 'ETC/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], + # # 'DOGE/USDT': [int(eth_limit), 2290, 1900, 1800, 1700, 1600, 1500, 1400, 1300], + # # # Ajoutez d'autres paires avec leurs niveaux d'achat ici... + # # } + # count_of_buys = len(filled_buys) + # buy_level = dataframe['lbp'] * (1 - self.levels[count_of_buys] / 100) # float(limit) #BUY_LEVELS.get(pair, [])[0] #dataframe['lbp_3'] #" + # return buy_level + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + last_candle_12 = dataframe.iloc[-13].squeeze() + + if (len(dataframe) < 1): + return None + pair = trade.pair + if pair not in ('BTC/USDT', 'DOGE/USDT', 'ETH/USDT'): + return None + max_buys = 7 + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + if count_of_buys >= max_buys: + return None + + if 'buy' in last_candle: + condition = (last_candle['buy'] == 1) + else: + condition = False + # self.protection_nb_buy_lost.value + # limits = ['lbp_3', 'lbp_6', 'lbp_9', 'lbp_12', 'lbp_20'] + # limit = last_candle[limits[count_of_buys]] + limit = last_candle['limit'] + stake_amount = min(200, self.adjust_stake_amount(pair, last_candle) * self.fibo[count_of_buys]) + + # print("Adjust " + trade.pair + " time=" + str(current_time) + ' rate=' + str(current_rate) + " buys=" + str(count_of_buys) + " limit=" + str(limit) + " stake=" + str(stake_amount)) + logger.info( + f"Adjust price={trade.pair} buy={condition} rate={current_rate:.4f} buys={count_of_buys} limit={limit:.4f} stake={stake_amount:.4f}") + + if (0 < count_of_buys <= max_buys) & (current_rate <= limit) & (condition): + try: + + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + # print("Effective Adjust " + trade.pair + " time=" + str(current_time) + ' rate=' + str(current_rate) + " buys=" + str(count_of_buys) + " limit=" + str(limit) + " stake=" + str(stake_amount)) + logger.info( + f"Effective Adjust price={trade.pair} rate={current_rate:.4f} buys={count_of_buys} limit={limit:.4f} stake={stake_amount:.4f}") + + return stake_amount + except Exception as exception: + print(exception) + return None + return None + + def adjust_stake_amount(self, pair: str, dataframe: DataFrame): + # Calculer le minimum des 14 derniers jours + current_price = dataframe['close'] + + # trade = self.getTrade(pair) + # if trade: + # current_price = trade.open_rate + base_stake_amount = self.config.get('stake_amount', 50) # Montant de base configuré + + # Calculer le max des 14 derniers jours + min_14_days_4 = dataframe['lowest_4_1d'] + max_14_days_4 = dataframe['highest_4_1d'] + percent_4 = 1 - (current_price - min_14_days_4) / (max_14_days_4 - min_14_days_4) + factor_4 = 1 / ((current_price - min_14_days_4) / (max_14_days_4 - min_14_days_4)) + max_min_4 = max_14_days_4 / min_14_days_4 + + # min_14_days = dataframe['lowest_1d'] + # max_14_days = dataframe['highest_1d'] + # percent = 1 - (current_price - min_14_days) / (max_14_days - min_14_days) + # factor = 1 / ((current_price - min_14_days) / (max_14_days - min_14_days)) + # max_min = max_14_days / min_14_days + # Stack amount ajusté price=2473.47 min_max=0.15058074985054215 percent=0.8379141364642171 amount=20.0 + + adjusted_stake_amount = max(base_stake_amount / 2.5, min(75, base_stake_amount * percent_4)) + # if pair in ('BTC/USDT', 'ETH/USDT'): + # if percent_4 > 0.5: + # adjusted_stake_amount = 300 + + # adjusted_stake_amount_2 = max(base_stake_amount / 2.5, min(75, base_stake_amount * percent)) + + print( + f"Stack amount ajusté price={current_price} max_min={max_min_4:.4f} min_14={min_14_days_4:.4f} max_14={max_14_days_4:.4f} factor={factor_4:.4f} percent={percent_4:.4f} amount={adjusted_stake_amount:.4f}") + # print(f"Stack amount ajusté price={current_price} max_min={max_min:.4f} min_14={min_14_days:.4f} max_14={max_14_days:.4f} factor={factor:.4f} percent={percent:.4f} amount={adjusted_stake_amount_2:.4f}") + + return adjusted_stake_amount + + def adjust_exit_price(self, dataframe: DataFrame): + # Calculer le max des 14 derniers jours + min_14_days = dataframe['lowest_1d'] + max_14_days = dataframe['highest_1d'] + entry_price = dataframe['fbp'] + current_price = dataframe['close'] + percent = 0.5 * (max_14_days - min_14_days) / min_14_days + exit_price = (1 + percent) * entry_price + + print(f"Exit price ajusté price={current_price:.4f} max_14={max_14_days:.4f} exit_price={exit_price:.4f}") + + return exit_price + + def adjust_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + + # Utiliser l'ATR pour ajuster le stoploss + atr_stoploss = current_rate - (last_candle['atr'] * 1.5) # Stoploss à 1.5x l'ATR + + # Retourner le stoploss dynamique en pourcentage du prix actuel + return (atr_stoploss / current_rate) - 1 + + def expectedProfit(self, pair: str, dataframe: DataFrame): + + current_price = dataframe['last_price'] # dataframe['close'] + + # trade = self.getTrade(pair) + # if trade: + # current_price = trade.open_rate + + # Calculer le max des 14 derniers jours + min_14_days = dataframe['lowest_1d'] + max_14_days = dataframe['highest_1d'] + percent = (max_14_days - current_price) / (min_14_days) + + min_max = dataframe['pct_min_max_1d'] # (max_14_days - min_14_days) / min_14_days + expected_profit = min(0.1, max(0.01, dataframe['min_max200'] * 0.5)) + + print( + f"Expected profit price={current_price:.4f} min_max={min_max:.4f} min_14={min_14_days:.4f} max_14={max_14_days:.4f} percent={percent:.4f} expected_profit={expected_profit:.4f}") + + # self.analyze_conditions(pair, dataframe) + return expected_profit + + # def adjust_exit_price(self, dataframe: DataFrame): + # # Calculer le max des 14 derniers jours + # min_14_days = dataframe['lowest_1d'] + # max_14_days = dataframe['highest_1d'] + # entry_price = dataframe['fbp'] + # current_price = dataframe['close'] + # percent = 0.5 * (max_14_days - min_14_days) / min_14_days + # exit_price = (1 + percent) * entry_price + # + # print(f"Exit price ajusté price={current_price} max_14={max_14_days} exit_price={exit_price}") + # + # return exit_price + + # def adjust_entry_price(self, dataframe: DataFrame): + # # Calculer le max des 14 derniers jours + # min_14_days = dataframe['lowest_1d'] + # max_14_days = dataframe['highest_1d'] + # current_price = dataframe['close'] + # percent = 0.5 * (max_14_days - min_14_days) / min_14_days + # entry_price = (1 + percent) * entry_price + # + # print(f"Entry price ajusté price={current_price} max_14={max_14_days} exit_price={entry_price}") + # + # return entry_price + + # def adjust_stake_amount(self, dataframe: DataFrame): + # # Calculer le minimum des 14 derniers jours + # middle = dataframe['middle_1d'] + # + # # Récupérer la dernière cotation actuelle (peut être le dernier point de la série) + # current_price = dataframe['close'] + # + # # Calculer l'écart entre la cotation actuelle et le minimum des 14 derniers jours + # difference = middle - current_price + # # Ajuster la stake_amount en fonction de l'écart + # # Par exemple, augmenter la stake_amount proportionnellement à l'écart + # base_stake_amount = self.config.get('stake_amount', 100) # Montant de base configuré + # + # multiplier = 1 - (difference / current_price) # Exemple de logique d'ajustement + # + # adjusted_stake_amount = max(base_stake_amount / 2.5, base_stake_amount * multiplier) + # + # # difference = 346.07000000000016 + # # price = 2641.75 + # # min_14 = 2295.68 + # # amount = 56.5500141951358 + # + # print(f"Stack amount ajusté difference={difference} price={current_price} middle={middle} multiplier={multiplier} amount={adjusted_stake_amount}") + # + # return adjusted_stake_amount + + def analyze_conditions(self, pair: str, row: DataFrame): + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + + if dataframe is None or dataframe.empty: + return + if row is None or row.empty: + return + # Créer un tableau pour stocker les résultats de l'analyse + results = [] + # row = dataframe.iloc[-1].squeeze() + # result = {'triggered': False, 'conditions_failed': []} + try: + buy_level = row['buy_level'] + except Exception as exception: + print(exception) + return None + # Première condition : 'buy_fractal' + print('------------------------------------------------') + print('Test buy fractal ' + pair + ' buy_level=' + str(buy_level)) + if not ( + (row['close'] <= (row['min200'] * 1.002)) and + (row['percent_max_144'] <= -0.012) and + (row['haopen'] < buy_level) and + (row['open'] < row['average_line_288']) and + (dataframe['min50'].shift(3).iloc[-1] == row['min50']) + ): + failed_conditions = [] + if row['close'] > (row['min200'] * 1.002): + print('close > min200 * 1.002') + if row['percent_max_144'] > -0.012: + print('percent_max_144 > -0.012') + if row['haopen'] >= buy_level: + print('haopen >= buy_level') + if row['open'] >= row['average_line_288']: + print('open >= average_line_288') + if dataframe['min50'].shift(3).iloc[-1] != row['min50']: + print('min50.shift(3) != min50') + # result['conditions_failed'].append({'buy_fractal': failed_conditions}) + print('------------------------------------------------') + print('Test buy_max_diff_015 ' + pair + ' buy_level=' + str(buy_level)) + # Deuxième condition : 'buy_max_diff_015' + if not ( + (dataframe['max200_diff'].shift(4).iloc[-1] >= 0.015) and + (row['close'] <= row['lowest_4_average'] * 1.002) and + (row['close'] <= row['min200'] * 1.002) and + (dataframe['max50_diff'].shift(4).iloc[-1] >= 0.01) and + (row['haclose'] < row['bb_middleband']) and + (row['close'] < buy_level) and + (row['open'] < row['average_line_288']) and + (dataframe['min50'].shift(3).iloc[-1] == row['min50']) + ): + if dataframe['max200_diff'].shift(4).iloc[-1] < 0.015: + print('max200_diff.shift(4) < 0.015') + if row['close'] > row['lowest_4_average'] * 1.002: + print('close > lowest_4_average * 1.002') + if row['close'] > row['min200'] * 1.002: + print('close > min200 * 1.002') + if dataframe['max50_diff'].shift(4).iloc[-1] < 0.01: + print('max50_diff.shift(4) < 0.01') + if row['haclose'] >= row['bb_middleband']: + print('haclose >= bb_middleband') + if row['close'] >= buy_level: + print('close >= buy_level') + if row['open'] >= row['average_line_288']: + print('open >= average_line_288') + if dataframe['min50'].shift(3).iloc[-1] != row['min50']: + print('min50.shift(3) != min50') + print('------------------------------------------------') + print('Test buy_min_max_200 ' + pair + ' buy_level=' + str(buy_level)) + if not ( + (row['close'] <= row['min200'] * 1.002) + and (row['min_max200'] > 0.015) + and (row['haopen'] < buy_level) + and (row['open'] < row['average_line_288']) + ): + if row['close'] > row['min200'] * 1.002: + print('close > row[min200] * 1.002') + if row['min_max200'] <= 0.015: + print('row[min_max200] <= 0.015') + if row['haopen'] < buy_level: + print('row[haopen] < buy_level') + if row['open'] < row['average_line_288']: + print('row[open] >= row[average_line_288]') + print('------------------------------------------------') + + # Ajouter le résultat à la liste des résultats + # results.append(result) + + # print(result) + + def getBinanceOrderBook(self, pair, dataframe: DataFrame): + """Fetch the order book (depth) from Binance.""" + # print(dataframe) + last_candle = dataframe.iloc[-1].squeeze() + symbol = pair.replace('/', '') + + try: + url = f"https://api.binance.com/api/v3/depth?symbol={symbol}&limit=5000" + response = requests.get(url) + data = response.json() + + # Extract bids and asks from the order book + asks, bids = self.calculateSMA(20, data['asks'], data['bids']) # Ventes List of [price, quantity] + # bids = data['bids'] + # asks = data['asks'] # Achats List of [price, quantity] + + # Process the depth data as you need it + # bid_volume = sum([float(bid[1]) for bid in bids]) # Sum of all bid volumes + # $ * nb / $ => nb + bid_volume = sum([float(bid[0]) * float(bid[1]) / float(last_candle['close']) for bid in bids[:10]]) + # ask_volume = sum([float(ask[1]) for ask in asks]) # Sum of all ask volumes + ask_volume = sum([float(ask[0]) * float(ask[1]) / float(last_candle['close']) for ask in asks[:10]]) + + # Example: add the difference in volumes as an indicator + if bid_volume and ask_volume: + self.updateLastValue(dataframe, 'depth_bid_ask_diff', round(bid_volume - ask_volume, 2)) + else: + self.updateLastValue(dataframe, 'depth_bid_ask_diff', 0) + + # probabilité baisse hausse sur les n premiers élements + for start in [0, 50, 100, 150]: + self.updateLastValue(dataframe, 'prob_hausse_' + str(start + 50), + self.calculateProbaNb(asks, bids, start, start + 50)) + # dataframe['prob_hausse_' + str(nb)] = self.calculateProbaNb(asks, bids, nb) + # Analyse des prix moyens pondérés par les volumes (VWAP) : + # + # Le VWAP (Volume Weighted Average Price) peut être utilisé pour comprendre la pression directionnelle. + # Si le VWAP basé sur les ordres d'achat est plus élevé que celui des ordres de vente, + # cela peut indiquer une probabilité de hausse. + nb = 50 + + bid_vwap = sum([float(bid[0]) * float(bid[1]) for bid in bids[:nb]]) / sum( + [float(bid[1]) for bid in bids[:nb]]) + ask_vwap = sum([float(ask[0]) * float(ask[1]) for ask in asks[:nb]]) / sum( + [float(ask[1]) for ask in asks[:nb]]) + + if bid_vwap > ask_vwap: + self.updateLastValue(dataframe, 'vwap_hausse', + round(100 * (bid_vwap - ask_vwap) / (bid_vwap + ask_vwap), 2)) + else: + self.updateLastValue(dataframe, 'vwap_hausse', + - round(100 * (ask_vwap - bid_vwap) / (bid_vwap + ask_vwap), 2)) + + current_price = last_candle['close'] # le prix actuel du marché + + # Calcul du seuil de variation de 1% + lower_threshold = current_price * 0.99 + upper_threshold = current_price * 1.01 + + # Volumes d'achat (bids) sous 1% du prix actuel + bid_volume_1percent = sum( + [float(bid[1]) for bid in bids if current_price >= float(bid[0]) >= lower_threshold]) + + # Volumes de vente (asks) au-dessus de 1% du prix actuel + ask_volume_1percent = sum( + [float(ask[1]) for ask in asks if current_price <= float(ask[0]) <= upper_threshold]) + + # Estimation de la probabilité basée sur le déséquilibre des volumes + total_volume = bid_volume_1percent + ask_volume_1percent + if total_volume > 0: + prob_hausse = bid_volume_1percent / total_volume + prob_baisse = ask_volume_1percent / total_volume + else: + prob_hausse = prob_baisse = 0 + + self.updateLastValue(dataframe, 'proba_hausse_1%', round(prob_hausse * 100, 2)) + self.updateLastValue(dataframe, 'proba_baisse_1%', round(prob_baisse * 100, 2)) + print(f"Probabilité de hausse de 1%: {prob_hausse * 100:.2f}%") + print(f"Probabilité de baisse de 1%: {prob_baisse * 100:.2f}%") + + self.calculateResistance(pair, asks, dataframe) + self.calculateSupport(pair, bids, dataframe) + + dataframe['r_s'] = 100 * (dataframe['r_min'] - dataframe['s_min']) / dataframe['s_min'] + + except Exception as e: + logger.error(f"Error fetching order book: {e}") + return None, None + + def calculateProbaNb(self, asks, bids, start, nb): + top_bids = sum([float(bid[1]) for bid in bids[start:nb]]) + top_asks = sum([float(ask[1]) for ask in asks[start:nb]]) + if top_bids > top_asks: + proba = round(100 * (top_bids - top_asks) / (top_bids + top_asks), 2) + else: + proba = - round(100 * (top_asks - top_bids) / (top_bids + top_asks), 2) + return proba + + def calculateResistance(self, pair, asks, dataframe: DataFrame): + last_candle = dataframe.iloc[-1].squeeze() + + # Filtrage +-5% + current_price = float(last_candle['close']) + lower_bound = current_price * 0.95 + upper_bound = current_price * 1.05 + ask_prices = [float(ask[0]) for ask in asks] + ask_volumes = [float(ask[1]) for ask in asks] + ask_df = pd.DataFrame({'price': ask_prices, 'volume': ask_volumes}) + filtered_ask_df = ask_df[(ask_df['price'] >= lower_bound) & (ask_df['price'] <= upper_bound)] + # Trier le DataFrame sur la colonne 'volume' en ordre décroissant + sorted_ask_df = filtered_ask_df.sort_values(by='volume', ascending=False) + + # Ne garder que les 3 premières lignes (les 3 plus gros volumes) + top_3_asks = sorted_ask_df.head(3) + print(top_3_asks) + + # Convertir les ordres de vente en numpy array pour faciliter le traitement + asks_array = np.array(filtered_ask_df, dtype=float) + + # Détecter les résistances : on peut définir qu'une résistance est un niveau de prix où la quantité est élevée + # Ex: seuil de résistance à partir des 10% des plus grosses quantités + resistance_threshold = np.percentile(asks_array[:, 1], 90) + resistances = asks_array[asks_array[:, 1] >= resistance_threshold] + + # Afficher les résistances trouvées + # print(f"{pair} Niveaux de résistance détectés:") + # for resistance in resistances: + # print(f"{pair} Prix: {resistance[0]}, Quantité: {resistance[1]}") + + # Exemple : somme des quantités sur des plages de prix + # Intervalles de 10 USDT + step = last_candle['close'] / 100 + price_intervals = np.arange(asks_array[:, 0].min(), asks_array[:, 0].max(), step=step) + + for start_price in price_intervals: + end_price = start_price + step + mask = (asks_array[:, 0] >= start_price) & (asks_array[:, 0] < end_price) + volume_in_range = asks_array[mask, 1].sum() + amount = volume_in_range * end_price + print( + f"Prix entre {start_price:.6f} et {end_price:.6f}: Volume total = {volume_in_range:.2f} amount={amount:.2f}") + + # Trier les asks par quantité en ordre décroissant + asks_sorted = asks_array[asks_array[:, 1].argsort()][::-1] + + # Sélectionner les trois plus gros resistances + top_3_resistances = asks_sorted[:3] + + # Afficher les trois plus gros resistances + print("Les trois plus grosses resistances détectées : ") + self.updateLastValue(dataframe, 'r3', top_3_resistances[0][0]) + self.updateLastValue(dataframe, 'r2', top_3_resistances[1][0]) + self.updateLastValue(dataframe, 'r1', top_3_resistances[2][0]) + self.updateLastValue(dataframe, 'r_min', + min(top_3_resistances[0][0], top_3_resistances[1][0], top_3_resistances[2][0])) + for resistance in top_3_resistances: + print(f"{pair} Prix: {resistance[0]}, Quantité: {resistance[1]}") + + def calculateSupport(self, pair, bids, dataframe: DataFrame): + last_candle = dataframe.iloc[-1].squeeze() + + # Convert to pandas DataFrame to apply moving average + current_price = float(last_candle['close']) + lower_bound = current_price * 0.95 + upper_bound = current_price * 1.05 + bid_prices = [float(bid[0]) for bid in bids] + bid_volumes = [float(bid[1]) for bid in bids] + bid_df = pd.DataFrame({'price': bid_prices, 'volume': bid_volumes}) + filtered_bid_df = bid_df[(bid_df['price'] >= lower_bound) & (bid_df['price'] <= upper_bound)] + # Trier le DataFrame sur la colonne 'volume' en ordre décroissant + sorted_bid_df = filtered_bid_df.sort_values(by='volume', ascending=False) + + # Ne garder que les 3 premières lignes (les 3 plus gros volumes) + top_3_bids = sorted_bid_df.head(3) + print(top_3_bids) + + # Convertir les ordres d'achat en numpy array pour faciliter le traitement + bids_array = np.array(filtered_bid_df, dtype=float) + + # Détecter les supports : on peut définir qu'un support est un niveau de prix où la quantité est élevée + # Ex: seuil de support à partir des 10% des plus grosses quantités + support_threshold = np.percentile(bids_array[:, 1], 90) + supports = bids_array[bids_array[:, 1] >= support_threshold] + + # Afficher les supports trouvés + # print(f"{pair} Niveaux de support détectés:") + # for support in supports: + # print(f"{pair} Prix: {support[0]}, Quantité: {support[1]}") + + step = last_candle['close'] / 100 + # Exemple : somme des quantités sur des plages de prix pour les bids + price_intervals = np.arange(bids_array[:, 0].min(), bids_array[:, 0].max(), step=step) # Intervalles de 10 USDT + + for start_price in price_intervals: + end_price = start_price + step + mask = (bids_array[:, 0] >= start_price) & (bids_array[:, 0] < end_price) + volume_in_range = bids_array[mask, 1].sum() + amount = volume_in_range * end_price + print( + f"Prix entre {start_price:.6f} et {end_price:.6f}: Volume total = {volume_in_range:.2f} amount={amount:.2f}") + + # Trier les bids par quantité en ordre décroissant + bids_sorted = bids_array[bids_array[:, 1].argsort()][::-1] + + # Sélectionner les trois plus gros supports + top_3_supports = bids_sorted[:3] + + # Afficher les trois plus gros supports + print("Les trois plus gros supports détectés:") + + self.updateLastValue(dataframe, 's1', top_3_supports[0][0]) + self.updateLastValue(dataframe, 's2', top_3_supports[1][0]) + self.updateLastValue(dataframe, 's3', top_3_supports[2][0]) + self.updateLastValue(dataframe, 's_min', max(top_3_supports[0][0], top_3_supports[1][0], top_3_supports[2][0])) + + for support in top_3_supports: + print(f"{pair} Prix: {support[0]}, Quantité: {support[1]}") + + def updateLastValue(self, df: DataFrame, col, value): + if col in df.columns: + print(f"update last col {col} {value}") + df.iloc[-1, df.columns.get_loc(col)] = value + else: + print(f"update all col {col} {value}") + df[col] = value + + # def update_last_record(self, dataframe: DataFrame, new_data): + # # Vérifiez si de nouvelles données ont été reçues + # if new_data is not None: + # # Ne mettez à jour que la dernière ligne du dataframe + # last_index = dataframe.index[-1] # Sélectionne le dernier enregistrement + # dataframe.loc[last_index] = new_data # Met à jour le dernier enregistrement avec les nouvelles données + # return dataframe + + def calculateSMA(self, nb, asks, bids): + # Prepare data for plotting + bid_prices = [float(bid[0]) for bid in bids] + bid_volumes = [float(bid[1]) for bid in bids] + + ask_prices = [float(ask[0]) for ask in asks] + ask_volumes = [float(ask[1]) for ask in asks] + + # Convert to pandas DataFrame to apply moving average + bid_df = pd.DataFrame({'price': bid_prices, 'volume': bid_volumes}) + ask_df = pd.DataFrame({'price': ask_prices, 'volume': ask_volumes}) + + # Apply a rolling window to calculate a 10-value simple moving average (SMA) + bid_df['volume_sma'] = bid_df['volume'].rolling(window=nb).mean() + ask_df['volume_sma'] = ask_df['volume'].rolling(window=nb).mean() + + # Pour bid_df + bid_df = bid_df.dropna(subset=['volume_sma']) + bids_with_sma = list(zip(bid_df['price'], bid_df['volume_sma'])) + + # Pour ask_df + ask_df = ask_df.dropna(subset=['volume_sma']) + asks_with_sma = list(zip(ask_df['price'], ask_df['volume_sma'])) + + # print(bids_with_sma) + # print(asks_with_sma) + + return asks_with_sma, bids_with_sma diff --git a/Zeus_8_3_2_B_4_2.txt b/Zeus_8_3_2_B_4_2.txt new file mode 100644 index 0000000..5df2352 --- /dev/null +++ b/Zeus_8_3_2_B_4_2.txt @@ -0,0 +1,15 @@ +[Achats] +BTC/USDT=63400 +ETH/USDT=2570 +ETC/USDT=10 +DOGE/USDT=0.106 +SOL/USDT=150 +XRP/USDT=0.584 + +[Ventes] +BTC/USDT=63979 +ETH/USDT=2542 +ETC/USDT=70 +DOGE/USDT=0.122 +SOL/USDT=150.24 +XRP/USDT=0.6 diff --git a/Zeus_8_3_2_B_4_2.txtold b/Zeus_8_3_2_B_4_2.txtold new file mode 100644 index 0000000..e678a37 --- /dev/null +++ b/Zeus_8_3_2_B_4_2.txtold @@ -0,0 +1,11 @@ +[Achats] +BTC/USDT=52669 +ETH/USDT=2375 +ETC/USDT=17.05 +DOGE/USDT=0.0901 + +[Ventes] +BTC/USDT=66331 +ETH/USDT=3321 +ETC/USDT=22.424 +DOGE/USDT=0.12660 diff --git a/Zeus_8_3_3.json b/Zeus_8_3_3.json new file mode 100644 index 0000000..b69c006 --- /dev/null +++ b/Zeus_8_3_3.json @@ -0,0 +1,117 @@ +{ + "strategy_name": "Zeus_8_3_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 1, + "buy_base": 0.1, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 3, + "protection_strategy": 1, + "protection_strategy_amount": 2 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-17 14:09:36.720609+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_3.py b/Zeus_8_3_3.py new file mode 100644 index 0000000..aafe7e9 --- /dev/null +++ b/Zeus_8_3_3.py @@ -0,0 +1,1014 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_3(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + # info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((info_last_candle['rsi_1h'] >= 76) & (info_last_candle['close_1h'] >= info_last_candle['bb_upperband_1h'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((info_last_candle['rsi_1h'] <= 35) | (info_last_candle['close_1h'] < info_last_candle['bb_lowerband_1h'])): + logger.info("2 - Enable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + ###### + + if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + & (dataframe['percent'].shift(1) > -0.003) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_h') + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + # & (dataframe['rsi'] < self.buy_rsi.value) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['close_1h']) + # ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + # dataframe = self.populate_buy_trend(dataframe, {'pair': trade.pair}) + # if not (self.populate_buy_trend(dataframe, {'pair': trade.pair})): + # return None + if (self.stop_buying.get(trade.pair) == None): + print("-----------" + trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + + self.stop_buying[trade.pair] = True + + if (self.stop_buying[trade.pair] == True): + print("-----------" + trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # print(last_candle['buy']) + + condition = ( + ( + (last_candle['trend_ichimoku_base'] <= self.buy_base.value) + & (last_candle['rsi'] < self.buy_rsi.value) + & (last_candle['close'] < last_candle['sma10']) + & (last_candle['close'] < last_candle['bb_lower_width_5']) + & (last_candle['close'] <= last_candle['close_1h']) + ) | ( + (last_candle['min_max_n'] >= self.buy_min_max_n.value) + & (last_candle_decalage['cond1'] <= self.buy_min_max_cond1.value) + & (last_candle['rsi'] < self.buy_min_max_rsi.value) + & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + & (last_candle_decalage['min_n'] == last_candle['min_n']) + & (last_candle['pct_change_1_1d'] > 0) + & (last_candle['close'] <= last_candle['close_1h']) + ) + ) + + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_3_1.json b/Zeus_8_3_3_1.json new file mode 100644 index 0000000..56bdc2b --- /dev/null +++ b/Zeus_8_3_3_1.json @@ -0,0 +1,117 @@ +{ + "strategy_name": "Zeus_8_3_3_1", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 1, + "buy_base": 0.1, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 3, + "protection_strategy": 1, + "protection_strategy_amount": 2 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-17 14:09:36.720609+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_3_1.py b/Zeus_8_3_3_1.py new file mode 100644 index 0000000..8f4583e --- /dev/null +++ b/Zeus_8_3_3_1.py @@ -0,0 +1,984 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_8_3_3_1(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " bool: + allow_to_buy = True + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + # info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((info_last_candle['rsi_1h'] >= 72) | (info_last_candle['close_1h'] >= info_last_candle['bb_upperband_1h'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((info_last_candle['rsi_1h'] <= 35) | (info_last_candle['close_1h'] < info_last_candle['bb_lowerband_1h'])): + logger.info("2 - Enable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_5_candle = dataframe.iloc[-5].squeeze() + + expected_profit = 0.01 + #print(last_candle['buy_tag']) + + days = (current_time - trade.open_date_utc).days + ###### + + if (current_profit > 0.0) & (last_candle['percent'] < -0.01): + return 'percent_quick' + if (self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + if (current_profit > 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > 0.005) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= 0.12) + & (dataframe['bb_width'] > 0.018) + & (dataframe['rsi'] < 79) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + & (dataframe['close'] < dataframe['min50'] * 1.005) + & (dataframe['percent'].shift(1) > -0.003) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku_h') + # dataframe.loc[ + # ( + # (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + # & (dataframe['rsi'] < self.buy_rsi.value) + # & (dataframe['close'] < dataframe['sma10']) + # & (dataframe['close'] <= dataframe['close_1h']) + # ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + # dataframe = self.populate_buy_trend(dataframe, {'pair': trade.pair}) + # if not (self.populate_buy_trend(dataframe, {'pair': trade.pair})): + # return None + if (self.stop_buying.get(trade.pair) == None): + print("-----------" + trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + + self.stop_buying[trade.pair] = True + + if (self.stop_buying[trade.pair] == True): + print("-----------" + trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # print(last_candle['buy']) + + condition = ( + ( + (last_candle['trend_ichimoku_base'] <= self.buy_base.value) + & (last_candle['rsi'] < self.buy_rsi.value) + & (last_candle['close'] < last_candle['sma10']) + & (last_candle['close'] < last_candle['bb_lower_width_5']) + & (last_candle['close'] <= last_candle['close_1h']) + ) | ( + (last_candle['min_max_n'] >= self.buy_min_max_n.value) + & (last_candle_decalage['cond1'] <= self.buy_min_max_cond1.value) + & (last_candle['rsi'] < self.buy_min_max_rsi.value) + & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + & (last_candle_decalage['min_n'] == last_candle['min_n']) + & (last_candle['pct_change_1_1d'] > 0) + & (last_candle['close'] <= last_candle['close_1h']) + ) + ) + + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_3_2.json b/Zeus_8_3_3_2.json new file mode 100644 index 0000000..88bf9e5 --- /dev/null +++ b/Zeus_8_3_3_2.json @@ -0,0 +1,35 @@ +{ + "strategy_name": "Zeus_8_3_3_2", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 625, + "buy_min_max_n": 0.2, + "buy_rsi": 26 + }, + "sell": { + "sell_b_RSI": 72, + "sell_percent": 0.25, + "sell_profit_percent": 0.1 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 3, + "protection_start_buying_rsi_1d": 5, + "protection_stop_buying_rsi_1d": 91 + }, + "stoploss": { + "stoploss": -0.262 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-03 12:06:46.910000+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_3_2.py b/Zeus_8_3_3_2.py new file mode 100644 index 0000000..943f7f7 --- /dev/null +++ b/Zeus_8_3_3_2.py @@ -0,0 +1,441 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8_3_3_2(IStrategy): + + # ROI table: + minimal_roi = { + "0": 10 + # 0.564, + # "567": 0.273, + # "2814": 0.12, + # "7675": 0 + } + + # Stoploss: + stoploss = -1 #0.256 + + # Buy hypers + timeframe = '5m' + + stop_buying = {} + + # DCA config + position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_min_horizon = IntParameter(50, 800, default=72, space='buy') + buy_rsi = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + # adx_1d_limit = IntParameter(15, 45, default=18, space='buy') + sell_b_RSI = IntParameter(70, 98, default=60, space='sell') + sell_profit_percent = DecimalParameter(0.1, 1.5, decimals=1, default=0.8, space='sell') + + sell_percent = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + protection_stop_buying_rsi_1d = IntParameter(50, 100, default=76, space='protection') + protection_start_buying_rsi_1d = IntParameter(1, 50, default=30, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + # info_previous_last_candle = informative.iloc[-2].squeeze() + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((last_candle['rsi5'] >= self.protection_stop_buying_rsi_1d.value) | (last_candle['close'] >= last_candle['bb_upperband'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((last_candle['rsi5'] <= self.protection_start_buying_rsi_1d.value) & (last_candle['percent5'] >= 0.005)): + logger.info("2 - Enable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = False + + logger.info("Buy ==> %s ", pair + " " + str(current_time) + "---------------------") + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + else: + logger.info("3 - accept buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if (current_profit > self.buy_min_max_n.value * self.sell_profit_percent.value) \ + & (previous_last_candle['rsi5'] > self.sell_b_RSI.value) \ + & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \ + & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']): + logger.info("Sell ==> %s ", pair + " " + str(current_time) + str(current_profit) + " " + str(current_rate)) + + return 'profit_1' # + str(self.sell_percent.value) + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + # dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + # dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + # dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + # dataframe['min200_1'] = dataframe['min200'] * 1.005 + # dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + # dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + # dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + # dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + # dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + # dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + # dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + # dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + # dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + # dataframe['stop_buying'] = (dataframe['rsi5'] >= self.protection_stop_buying_rsi_1d.value) \ + # & (dataframe['close'] >= dataframe['bb_upperband']) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + # informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # ######################## INFORMATIVE 4h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative["rsi"] = talib.RSI(informative) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi5'] < self.protection_stop_buying_rsi_1d.value) + & (dataframe['rsi5'] > self.protection_start_buying_rsi_1d.value) + & (dataframe['rsi5'].shift(1) < self.buy_rsi.value) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(6) == dataframe['min_n']) + # & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + # & (dataframe['close'] <= dataframe['close_1d']) + # & (dataframe['close_1d'] <= dataframe['sma3_1d']) + # & (dataframe['close_1d'] <= dataframe['sma5_1d']) + # & (dataframe['close_1d'] <= dataframe['sma10_1d']) + # & (dataframe['adx_1d'] > self.adx_1d_limit.value) + # & (dataframe['rsi3_1d'].shift(288) <= dataframe['rsi3_1d']) + ), ['buy', 'buy_tag']] = (1, 'buy_adx_inf') + + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['rsi5'].shift(1) > self.sell_b_RSI.value) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5']) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5'].shift(2)) + # & (dataframe['close'] > dataframe['close_1d']) + # & (dataframe['close_1d'] > dataframe['sma3_1d']) + # & (dataframe['close_1d'] > dataframe['sma5_1d']) + # & (dataframe['close_1d'] > dataframe['sma10_1d']) + # # & (dataframe['rsi3_1d'].shift(288) > dataframe['rsi3_1d']) + # # (dataframe['close_1d'] > dataframe['sma3_1d']) + # # & (dataframe['rsi3_1d'] > 72) + # #& (dataframe['last_buy_price'] < (dataframe['close'])) + # #& (dataframe['should_sell'] == True) + # ), ['sell', 'sell_tag']] = (1, 'sell_close_1d') + # print("dans sell" + metadata['pair']) + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + if (self.stop_buying.get(trade.pair, None) == None): + # logger.info("----------- %s ", trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + self.stop_buying[trade.pair] = False + + if (self.stop_buying[trade.pair] == True): + # logger.info("----------- %s ", trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + last_candle_6 = dataframe.iloc[-7].squeeze() + + # last_candle_5 = dataframe.iloc[-3].squeeze() + # last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # print(last_candle['buy']) + + condition = ( + (previous_last_candle['rsi5'] < self.buy_rsi.value) + & (previous_last_candle['rsi5'] < last_candle['rsi5']) + & (previous_last_candle['rsi5'] < previous_previous_last_candle['rsi5']) + & (last_candle_6['min_n'] == last_candle['min_n']) + & (last_candle['min_max_n'] >= self.buy_min_max_n.value) + # & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + # & (last_candle['close'] <= last_candle['close_1d']) + # & (last_candle['close_1d'] <= last_candle['sma3_1d']) + # & (last_candle['close_1d'] <= last_candle['sma5_1d']) + # & (last_candle['close_1d'] <= last_candle['sma10_1d']) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + ) + if not (condition): + return None + + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # logger.info("----------- %s ", trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # " " + str(current_time) + "---------------------") + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_3_3_3.json b/Zeus_8_3_3_3.json new file mode 100644 index 0000000..b3b89b0 --- /dev/null +++ b/Zeus_8_3_3_3.json @@ -0,0 +1,79 @@ +{ + "strategy_name": "Zeus_8_3_3_3", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_bb_width_n": 5, + "buy_min_horizon": 192, + "buy_min_max_coef": 1.004, + "buy_min_max_decalage": 5, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_rsi": 72 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": false, + "profit_b_quick_gain_3": true, + "profit_b_quick_lost": false, + "profit_b_short_loss": false, + "profit_b_sma10": true, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": true, + "profit_h_no_change": false, + "profit_h_old_sma10": false, + "profit_h_over_rsi": true, + "profit_h_quick_gain": true, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": true, + "profit_h_sma10": true, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": false, + "sell_b_RSI": 79, + "sell_b_RSI2": 71, + "sell_b_RSI2_percent": 0.0, + "sell_b_RSI3": 89, + "sell_b_candels": 23, + "sell_b_percent": 0.017, + "sell_b_percent3": 0.003, + "sell_b_profit_no_change": 0.014, + "sell_b_profit_percent10": 0.0008, + "sell_b_too_old_day": 10, + "sell_b_too_old_percent": 0.01, + "sell_h_RSI": 98, + "sell_h_RSI2": 80, + "sell_h_RSI2_percent": 0.008, + "sell_h_RSI3": 95, + "sell_h_candels": 15, + "sell_h_percent": 0.019, + "sell_h_percent3": 0.0, + "sell_h_profit_no_change": 0.016, + "sell_h_profit_percent10": 0.0008, + "sell_h_too_old_day": 0, + "sell_h_too_old_percent": 0.0 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 5 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-23 21:11:15.507514+00:00" +} \ No newline at end of file diff --git a/Zeus_8_3_3_3.py b/Zeus_8_3_3_3.py new file mode 100644 index 0000000..7dce27a --- /dev/null +++ b/Zeus_8_3_3_3.py @@ -0,0 +1,756 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8_3_3_3(IStrategy): + + # ROI table: + minimal_roi = { + "0": 0.564, + "567": 0.273, + "2814": 0.12, + "7675": 0 + } + + # Stoploss: + stoploss = -1 #0.256 + + # Buy hypers + timeframe = '5m' + + market_overview = {'up': 0, 'down': 0} + market_overview_pct5 = 0 + market_overview_pct1 = 0 + max_open_trades = 5 + max_amount = 40 + stop_buy_for_all = False + stop_buying = {} + + # DCA config + position_adjustment_enable = True + #max_dca_orders = 2 # n - 1 + max_dca_multiplier = 7 # (2^n - 1) + dca_trigger = 0 + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_min_horizon = IntParameter(50, 200, default=72, space='buy') + + buy_rsi = IntParameter(20, 90, default=72, space='buy') + buy_bb_width_n = DecimalParameter(1, 10, decimals=1, default=5, space='buy') + + buy_min_max_nh = IntParameter(1, 48, default=24, space='buy') + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_min_max_rsi = IntParameter(50, 90, default=72, space='buy') + buy_min_max_coef = DecimalParameter(1, 1.01, decimals=3, default=1.002, space='buy') + buy_min_max_decalage = IntParameter(2, 10, default=2, space='buy') + + profit_b_no_change = BooleanParameter(default=True, space="sell") + profit_b_quick_lost = BooleanParameter(default=True, space="sell") + profit_b_sma5 = BooleanParameter(default=True, space="sell") + profit_b_sma10 = BooleanParameter(default=True, space="sell") + profit_b_sma20 = BooleanParameter(default=True, space="sell") + profit_b_quick_gain = BooleanParameter(default=True, space="sell") + profit_b_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_b_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_b_over_rsi = BooleanParameter(default=True, space="sell") + profit_b_short_loss = BooleanParameter(default=True, space="sell") + + sell_b_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_b_candels = IntParameter(0, 48, default=12, space='sell') + + sell_b_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_b_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_b_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_b_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_b_RSI = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_b_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_b_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + # sell_b_expected_profit = DecimalParameter(0, 0.01, decimals=3, default=0.01, space='sell') + + profit_h_no_change = BooleanParameter(default=True, space="sell") + profit_h_quick_lost = BooleanParameter(default=True, space="sell") + profit_h_sma5 = BooleanParameter(default=True, space="sell") + profit_h_sma10 = BooleanParameter(default=True, space="sell") + profit_h_sma20 = BooleanParameter(default=True, space="sell") + profit_h_quick_gain = BooleanParameter(default=True, space="sell") + profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell") + profit_h_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell") + profit_h_over_rsi = BooleanParameter(default=True, space="sell") + profit_h_short_loss = BooleanParameter(default=True, space="sell") + + sell_h_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + sell_h_candels = IntParameter(0, 48, default=12, space='sell') + + sell_h_too_old_day = IntParameter(0, 10, default=5, space='sell') + sell_h_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + sell_h_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell') + sell_h_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell') + + sell_h_RSI = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI2 = IntParameter(70, 98, default=88, space='sell') + sell_h_RSI3 = IntParameter(70, 98, default=80, space='sell') + + sell_h_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell') + + protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + + def calc_profit(self, price: float, current: float) -> float: + fee = 1.0007 + profit = ((current*fee) - + (price*fee)) + + return float(f"{profit:.8f}") + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + # info_previous_last_candle = informative.iloc[-2].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + informative, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + info_last_candle = informative.iloc[-1].squeeze() + + if ((info_last_candle['rsi_1h'] >= 76) & (info_last_candle['close_1h'] >= info_last_candle['bb_upperband_1h'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((info_last_candle['rsi_1h'] <= 35) | (info_last_candle['close_1h'] < info_last_candle['bb_lowerband_1h'])): + logger.info("2 - Enable buying %s date %s", pair, info_last_candle['date']) + self.stop_buying[pair] = False + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, info_last_candle['date']) + else: + logger.info("3 - accept buying %s date %s", pair, info_last_candle['date']) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-2].squeeze() + + previous_5_candle = dataframe.iloc[-5].squeeze() + + return (previous_last_candle['rsi5'] > 60) \ + & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \ + & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']) \ + & (last_candle['close'] > last_candle['close_1d']) & (last_candle['percent'] < 0) + + # expected_profit = 0.01 + # #print(last_candle['buy_tag']) + # + # days = (current_time - trade.open_date_utc).days + # ###### + # + # if (last_candle['mrsi3_1h'] < previous_last_candle['mrsi3_1h']): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + # max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + # max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + # + # if (current_profit > 0.01) & \ + # (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + # return 'b_percent10' + # if (current_profit > max_profit) & \ + # ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + # last_candle['percent5'] < -max_percent)): + # return 'b_percent_quick' + # + # if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + # & (days < self.sell_b_too_old_day.value * 2)\ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "b_too_old_0.01" + # if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + # & (days < self.sell_b_too_old_day.value * 3) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "b_too_old_0.02" + # if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "b_too_old_0.03" + # + # if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + # last_candle['percent3'] < -max_percent): + # return "b_quick_lost" + # + # if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + # & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # return "b_no_change" + # + # if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + # & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + # return "b_quick_gain_param" + # + # if self.profit_b_sma5.value: + # if (current_profit > expected_profit) \ + # & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + # | (last_candle['percent3'] < -expected_profit) | ( + # last_candle['percent5'] < -expected_profit)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_sma5' + # + # if self.profit_b_sma10.value: + # if (current_profit > expected_profit) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + # | (last_candle['percent3'] < -expected_profit) | ( + # last_candle['percent5'] < -expected_profit)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_sma10' + # + # if self.profit_b_sma20.value: + # if (current_profit > max_percent) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma20'] > last_candle['sma20']) & + # ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + # last_candle['percent20'] < 0))): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_sma20' + # + # if self.profit_b_over_rsi.value: + # if (current_profit > 0) & (previous_last_candle[ + # 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_over_rsi' + # + # if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + # (last_candle[ + # 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_over_rsi_2' + # + # if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + # (last_candle['close'] >= last_candle['max200']) & (last_candle[ + # 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_over_rsi_max' + # + # if self.profit_b_short_loss.value: + # if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + # last_candle['percent'] < 0) \ + # & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'b_short_lost' + # else: + # max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + # max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + # + # if (current_profit > max_profit) & ( + # (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + # last_candle['percent5'] < -max_percent)): + # return 'h_percent_quick' + # + # # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # # return 'h_bb_width_max' + # + # if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + # & (days < self.sell_h_too_old_day.value * 2)\ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "h_too_old_0.01" + # if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + # & (days < self.sell_h_too_old_day.value * 3) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "h_too_old_0.02" + # if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + # return "h_too_old_0.03" + # + # if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + # last_candle['percent3'] < -max_percent): + # return "h_quick_lost" + # + # if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + # & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600): + # return "h_no_change" + # + # if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + # & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + # return "h_quick_gain_param" + # + # if self.profit_h_sma5.value: + # if (current_profit > expected_profit) \ + # & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + # | (last_candle['percent3'] < -expected_profit) | ( + # last_candle['percent5'] < -expected_profit)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_sma5' + # + # if self.profit_h_sma10.value: + # if (current_profit > expected_profit) \ + # & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + # | (last_candle['percent3'] < -expected_profit) | ( + # last_candle['percent5'] < -expected_profit)) \ + # & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_sma10' + # + # if self.profit_h_sma20.value: + # if (current_profit > max_percent) \ + # & (previous_last_candle['sma10'] > last_candle['sma10']) \ + # & ((current_time - trade.open_date_utc).seconds >= 3600) \ + # & ((previous_last_candle['sma20'] > last_candle['sma20']) & + # ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + # last_candle['percent20'] < 0))): + # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_sma20' + # + # if self.profit_h_over_rsi.value: + # if (current_profit > 0) & (previous_last_candle[ + # 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_over_rsi' + # + # if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + # (last_candle[ + # 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_over_rsi_2' + # + # if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + # (last_candle['close'] >= last_candle[ + # 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_over_rsi_max' + # + # if self.profit_h_short_loss.value: + # if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + # last_candle['percent'] < 0) \ + # & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + # return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + # profit = False + # profit_percent = False + # percent_lower = False + # current_price = dataframe['close'].iloc[-1] + # + # dataframe['should_sell'] = False + # dataframe['should_buy'] = False + # + # # Get the previous trade + # trade = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + # if trade: + # trade = trade[-1] + # lsp = trade.close_rate + # if lsp: + # percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + # # Found a bug? When force selling it doesnt close it + # else: + # lsp = trade.open_rate + # if lsp: + # percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + # else: + # lsp = 0.00 + # + # # Get the current Trade + # trade = Trade.get_trades_proxy(is_open=True, pair=metadata['pair']) + # if trade: + # trade = trade[-1] + # lbp = trade.open_rate + # open_trade = True + # profit = self.calc_profit(price=lbp, current=current_price) + # profit_percent = (profit/lbp)*100 + # else: + # lbp = 0.00 + # open_trade = False + # profit = False + # profit_percent = False + # + # print("------------") + # + # print("Last Sold For:", lsp) + # + # if open_trade: + # print("Bought for: ", lbp) + # print("Current Price: ", current_price) + # if profit: + # print("Current Profit: ", profit, " ", float(f"{profit_percent:.8f}"), "%") + # if percent_lower and not open_trade: + # print("Percent Lower: ", float(f"{percent_lower:.8f}"), "%") + # + # # Should we Sell? + # if profit_percent: + # if profit_percent > 1: + # dataframe['should_sell'] = True + # + # # Should we buy? + # if not open_trade: + # if (lsp == 0.00 ) & (lbp == 0.00): + # dataframe['should_buy'] = True + # # Is the percentage of what we sold for and the current price 2% lower + # if percent_lower > 2: + # dataframe['should_buy'] = True + # + # dataframe['last_sell_price'] = lsp + # dataframe['last_buy_price'] = lbp + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["rsi3"] = talib.RSI(informative, 3) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # ######################## INFORMATIVE 4h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative["rsi"] = talib.RSI(informative) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["rsi3"] = talib.RSI(informative, 3) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + # (dataframe['min_max_n'] >= self.buy_min_max_n.value) + (dataframe['rsi5'].shift(1) < 12) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + #& (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + # & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close_1d'] <= dataframe['sma3_1d']) + & (dataframe['close_1d'] <= dataframe['sma5_1d']) + & (dataframe['close_1d'] <= dataframe['sma10_1d']) + & (dataframe['low'] <= dataframe['min200']) + & (dataframe['min'].shift(2) == dataframe['min50']) + # & (dataframe['rsi3_1d'].shift(288) <= dataframe['rsi3_1d']) + ), ['buy', 'buy_tag']] = (1, 'buy_rsi5') + + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['rsi5'].shift(1) > 60) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5']) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5'].shift(2)) + # & (dataframe['close'] > dataframe['close_1d']) + # # & (dataframe['close_1d'] > dataframe['sma3_1d']) + # # & (dataframe['close_1d'] > dataframe['sma5_1d']) + # # & (dataframe['close_1d'] > dataframe['sma10_1d']) + # # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + # + # # & (dataframe['rsi3_1d'].shift(288) > dataframe['rsi3_1d']) + # # (dataframe['close_1d'] > dataframe['sma3_1d']) + # # & (dataframe['rsi3_1d'] > 72) + # #& (dataframe['last_buy_price'] < (dataframe['close'])) + # #& (dataframe['should_sell'] == True) + # ), ['sell', 'sell_tag']] = (1, 'sell_close_1d') + # print("dans sell" + metadata['pair']) + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + # dataframe = self.populate_buy_trend(dataframe, {'pair': trade.pair}) + # if not (self.populate_buy_trend(dataframe, {'pair': trade.pair})): + # return None + if (self.stop_buying.get(trade.pair, None) == None): + print("-----------" + trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + self.stop_buying[trade.pair] = True + + if (self.stop_buying[trade.pair] == True): + print("-----------" + trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + # last_candle_5 = dataframe.iloc[-3].squeeze() + # last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # print(last_candle['buy']) + + condition = ( + # (last_candle['min_max_n'] >= self.buy_min_max_n.value) + (previous_last_candle['rsi5'] < 12) + & (previous_last_candle['rsi5'] < last_candle['rsi5']) + & (previous_last_candle['rsi5'] < previous_previous_last_candle['rsi5']) + # & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + & (last_candle['close'] <= last_candle['close_1d']) + & (last_candle['close_1d'] <= last_candle['sma3_1d']) + & (last_candle['close_1d'] <= last_candle['sma5_1d']) + & (last_candle['close_1d'] <= last_candle['sma10_1d']) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + ) + if not (condition): + return None + + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8_4h.json b/Zeus_8_4h.json new file mode 100644 index 0000000..9d3fbf9 --- /dev/null +++ b/Zeus_8_4h.json @@ -0,0 +1,40 @@ +{ + "strategy_name": "Zeus_8_4h", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 109, + "buy_min_horizon_4h": 30, + "buy_min_max_n": 0.06, + "buy_min_max_n_4h": 0.11, + "buy_percent_4h": 1.02, + "buy_rsi": 26, + "buy_rsi_4h": 24, + "decalage": 9, + "decalage_4h": 10 + }, + "sell": { + "sell_b_RSI": 89, + "sell_percent": 0.25, + "sell_percent3_quick": 0.16, + "sell_profit_percent": 0.9 + }, + "protection": { + "protection_start_buying_rsi_4h": 40, + "protection_stop_buying_rsi_4h": 99 + }, + "stoploss": { + "stoploss": -0.235 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-05 18:50:45.473684+00:00" +} \ No newline at end of file diff --git a/Zeus_8_4h.jsonProfit b/Zeus_8_4h.jsonProfit new file mode 100644 index 0000000..6a5634f --- /dev/null +++ b/Zeus_8_4h.jsonProfit @@ -0,0 +1,44 @@ +{ + "strategy_name": "Zeus_8_4h", + "params": { + "roi": { + "0": 10 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 238, + "buy_min_horizon_4h": 106, + "buy_min_max_n": 0.16, + "buy_min_max_n_4h": 0.15, + "buy_percent_4h": 1.004, + "buy_rsi": 7, + "buy_rsi_4h": 20, + "decalage_4h": 5 + }, + "sell": { + "sell_b_RSI": 93, + "sell_percent": 0.17, + "sell_percent10_quick": 0.19, + "sell_percent3_quick": 0.07, + "sell_percent5_quick": 0.21, + "sell_percent_quick": 0.1, + "sell_profit_percent": 1.3 + }, + "protection": { + "protection_nb_buy_lost": 2, + "protection_percent_buy_lost": 26, + "protection_start_buying_rsi_4h": 49, + "protection_stop_buying_rsi_4h": 68 + }, + "stoploss": { + "stoploss": -0.234 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-05 01:29:52.992774+00:00" +} \ No newline at end of file diff --git a/Zeus_8_4h.py b/Zeus_8_4h.py new file mode 100644 index 0000000..42ad24f --- /dev/null +++ b/Zeus_8_4h.py @@ -0,0 +1,409 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8_4h(IStrategy): + + # ROI table: + minimal_roi = { + "0": 10 + # 0.564, + # "567": 0.273, + # "2814": 0.12, + # "7675": 0 + } + + # Stoploss: + stoploss = -1 #0.256 + + # Buy hypers + timeframe = '5m' + + stop_buying = {} + + # DCA config + # position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + decalage = IntParameter(1, 12, default=6, space='buy') + buy_min_horizon = IntParameter(50, 288, default=72, space='buy') + buy_rsi = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + # adx_1d_limit = IntParameter(15, 45, default=18, space='buy') + sell_b_RSI = IntParameter(70, 98, default=60, space='sell') + sell_profit_percent = DecimalParameter(0.1, 1.5, decimals=1, default=0.8, space='sell') + + # sell_percent_quick = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + sell_percent3_quick = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + # sell_percent5_quick = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + # sell_percent10_quick = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + + sell_percent = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + # protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + # protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + # protection_stop_buying_rsi_1d = IntParameter(50, 100, default=76, space='protection') + # protection_start_buying_rsi_1d = IntParameter(1, 50, default=30, space='protection') + + # 4h + protection_stop_buying_rsi_4h = IntParameter(50, 100, default=76, space='protection') + protection_start_buying_rsi_4h = IntParameter(1, 50, default=30, space='protection') + buy_min_horizon_4h = IntParameter(1, 120, default=72, space='buy') + buy_rsi_4h = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n_4h = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + buy_percent_4h = DecimalParameter(1.005, 1.02, decimals=3, default=1.01, space='buy') + decalage_4h = IntParameter(1, 12, default=6, space='buy') + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + ret = None + if (current_profit > 0.01) \ + & (previous_last_candle['rsi5'] > self.sell_b_RSI.value) \ + & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \ + & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']): + ret = 'profit_1' # + str(self.sell_percent.value) + + # if (last_candle['percent'] < - self.sell_percent_quick.value): + # ret = 'quick_percent' + + if (last_candle['percent3'] < - self.sell_percent3_quick.value): + ret = 'quick_percent3' + + # if (last_candle['percent5'] < - self.sell_percent5_quick.value): + # ret = 'quick_percent5' + # + # if (last_candle['percent10'] < - self.sell_percent10_quick.value): + # ret = 'quick_percent10' + + if ret: + logger.info("Sell ==> %s ", ret + " " + pair + " " + str(current_time) + " " + str(current_profit)) + #+ " " + str(self.wallets.get_total_stake_amount())) + return ret + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + # informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + # dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + # dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + # dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + # dataframe['min200_1'] = dataframe['min200'] * 1.005 + # dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + # dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + # dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + # dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + # dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + # dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + # dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + # dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + # dataframe['stop_buying'] = (dataframe['rsi5'] >= self.protection_stop_buying_rsi_1d.value) \ + # & (dataframe['close'] >= dataframe['bb_upperband']) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + # informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + + # informative["bb_width"] = ( + # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['rsi5'] = talib.RSI(informative, timeperiod=5) + informative['min'] = talib.MIN(informative['close'], timeperiod=self.buy_min_horizon_4h.value) + informative['min_n'] = talib.MIN(informative['close'], timeperiod=self.buy_min_horizon_4h.value) + informative['max_n'] = talib.MAX(informative['close'], timeperiod=self.buy_min_horizon_4h.value) + informative['min_max_n'] = (informative['max_n'] - informative['min_n']) / informative['min_n'] + informative['allow_to_buy'] = (informative['rsi5'] < self.protection_stop_buying_rsi_4h.value) \ + & (informative['rsi5'] > self.protection_start_buying_rsi_4h.value) \ + & (informative['min_n'].shift(self.decalage_4h.value) == informative['min_n'])\ + & (informative['min_max_n'] >= self.buy_min_max_n.value) + # informative['allow_to_sell'] = ( + # (informative['rsi5'] > self.protection_stop_buying_rsi_4h.value) \ + # | (informative['rsi5'] < self.protection_start_buying_rsi_4h.value) + # ) + # & (informative['close'] <= informative['min_n'] * self.buy_percent_4h.value) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + dataframe['allow_to_buy'] = (dataframe['rsi5'].shift(1) < self.buy_rsi.value) \ + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) \ + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) \ + & (dataframe['min_n'].shift(6) == dataframe['min_n']) \ + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + + ######################## INFORMATIVE 1h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['allow_to_buy_4h']) + # & (dataframe['rsi5'] < self.protection_stop_buying_rsi_1d.value) + # & (dataframe['rsi5'] > self.protection_start_buying_rsi_1d.value) + & (dataframe['rsi5'].shift(1) < self.buy_rsi.value) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + & (dataframe['min_n'].shift(self.decalage.value) == dataframe['min_n']) + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + ), ['buy', 'buy_tag']] = (1, 'buy_rsi5') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['rsi5'].shift(1) > self.sell_b_RSI.value) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5']) + # & (dataframe['rsi5'].shift(1) >= dataframe['rsi5'].shift(2)) + # & (dataframe['close'] > dataframe['close_1d']) + # & (dataframe['close_1d'] > dataframe['sma3_1d']) + # & (dataframe['close_1d'] > dataframe['sma5_1d']) + # & (dataframe['close_1d'] > dataframe['sma10_1d']) + # # & (dataframe['rsi3_1d'].shift(288) > dataframe['rsi3_1d']) + # # (dataframe['close_1d'] > dataframe['sma3_1d']) + # # & (dataframe['rsi3_1d'] > 72) + # #& (dataframe['last_buy_price'] < (dataframe['close'])) + # #& (dataframe['should_sell'] == True) + # ), ['sell', 'sell_tag']] = (1, 'sell_close_1d') + # print("dans sell" + metadata['pair']) + return dataframe + + # def adjust_trade_position(self, trade: Trade, current_time: datetime, + # current_rate: float, current_profit: float, min_stake: float, + # max_stake: float, **kwargs): + # dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # if (len(dataframe) < 1) | (current_profit > - 0.2): + # return None + # + # last_candle = dataframe.iloc[-1].squeeze() + # + # condition = ( + # (last_candle['allow_to_buy_4h']) + # & (last_candle['allow_to_buy']) + # ) + # if not (condition): + # return None + # # print(trade.pair, current_profit, last_candle['allow_to_buy_4h'], last_candle['allow_to_buy']) + # + # filled_buys = trade.select_filled_orders('buy') + # count_of_buys = len(filled_buys) + # + # p = self.protection_percent_buy_lost.value + # percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + # + # if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + # & (current_profit < - 0.2) & (condition): #(percents[count_of_buys - 1] / 100)) + # try: + # p = self.config['stake_amount'] + # factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + # + # stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # return stake_amount + # except Exception as exception: + # print(exception) + # return None + # return None diff --git a/Zeus_8d.json b/Zeus_8d.json new file mode 100644 index 0000000..9a19b42 --- /dev/null +++ b/Zeus_8d.json @@ -0,0 +1,36 @@ +{ + "strategy_name": "Zeus_8d", + "params": { + "roi": { + "0": 5 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.068, + "trailing_stop_positive_offset": 0.155, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 96, + "buy_min_max_n": 0.14, + "buy_rsi": 30, + "decalage": 7 + }, + "sell": { + "sell_b_RSI": 86, + "sell_percent": 0.13, + "sell_profit_percent": 0.6 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 4, + "protection_start_buying_rsi_1d": 22, + "protection_stop_buying_rsi_1d": 64 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-03 15:13:16.143482+00:00" +} \ No newline at end of file diff --git a/Zeus_8d.jsonstoploss b/Zeus_8d.jsonstoploss new file mode 100644 index 0000000..6f2eb9c --- /dev/null +++ b/Zeus_8d.jsonstoploss @@ -0,0 +1,36 @@ +{ + "strategy_name": "Zeus_8d", + "params": { + "roi": { + "0": 5 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.068, + "trailing_stop_positive_offset": 0.155, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 33, + "buy_min_max_n": 0.19, + "buy_rsi": 28, + "decalage": 8 + }, + "sell": { + "sell_b_RSI": 86, + "sell_percent": 0.13, + "sell_profit_percent": 0.9 + }, + "protection": { + "protection_nb_buy_lost": 1, + "protection_percent_buy_lost": 5, + "protection_start_buying_rsi_1d": 19, + "protection_stop_buying_rsi_1d": 83 + }, + "stoploss": { + "stoploss": -1 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-03 14:11:59.654713+00:00" +} \ No newline at end of file diff --git a/Zeus_8d.py b/Zeus_8d.py new file mode 100644 index 0000000..5170e34 --- /dev/null +++ b/Zeus_8d.py @@ -0,0 +1,437 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8d(IStrategy): + + # ROI table: + minimal_roi = { + "0": 10 + # 0.564, + # "567": 0.273, + # "2814": 0.12, + # "7675": 0 + } + + # Stoploss: + stoploss = -1 #0.256 + + # Buy hypers + timeframe = '4h' + + stop_buying = {} + + # DCA config + position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_min_horizon = IntParameter(1, 100, default=7, space='buy') + buy_rsi = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n = DecimalParameter(0, 0.2, decimals=2, default=0.05, space='buy') + decalage = IntParameter(1, 12, default=6, space='buy') + # adx_1d_limit = IntParameter(15, 45, default=18, space='buy') + sell_b_RSI = IntParameter(70, 98, default=60, space='sell') + sell_profit_percent = DecimalParameter(0.1, 1.5, decimals=1, default=0.8, space='sell') + + sell_percent = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + protection_stop_buying_rsi_1d = IntParameter(50, 100, default=76, space='protection') + protection_start_buying_rsi_1d = IntParameter(1, 50, default=30, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + # info_previous_last_candle = informative.iloc[-2].squeeze() + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((last_candle['rsi5'] >= self.protection_stop_buying_rsi_1d.value) | (last_candle['close'] >= last_candle['bb_upperband'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((last_candle['rsi5'] <= self.protection_start_buying_rsi_1d.value) & (last_candle['percent5'] >= 0.005)): + logger.info("2 - Enable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = False + + logger.info("Buy ==> %s ", pair + " " + str(current_time) + "---------------------") + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + else: + logger.info("3 - accept buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if (current_profit > self.buy_min_max_n.value * self.sell_profit_percent.value) \ + & (previous_last_candle['rsi5'] > self.sell_b_RSI.value) \ + & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \ + & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']): + logger.info("Sell ==> %s ", pair + " " + str(current_time) + str(current_profit) + " " + str(current_rate)) + + return 'profit_1' # + str(self.sell_percent.value) + + # def informative_pairs(self): + # # get access to all pairs available in whitelist. + # pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '4h') for pair in pairs] + # # informative_pairs += [(pair, '4h') for pair in pairs] + # informative_pairs += [(pair, '1h') for pair in pairs] + # + # return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + # dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + # dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + # dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + # dataframe['min200_1'] = dataframe['min200'] * 1.005 + # dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + # dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + # dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + # dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + # dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + # dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + # dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + # dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + # dataframe['stop_buying'] = (dataframe['rsi5'] >= self.protection_stop_buying_rsi_1d.value) \ + # & (dataframe['close'] >= dataframe['bb_upperband']) + + # ################### INFORMATIVE 1D + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # # informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + # # informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + # # informative['pct_change_1'] = informative['close'].pct_change(1) + # # informative['pct_change_3'] = informative['close'].pct_change(3) + # # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # # informative['adx'] = talib.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + # + # # informative["bb_width"] = ( + # # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # # ) + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # ######################## INFORMATIVE 4h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative["rsi"] = talib.RSI(informative) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi5'] < self.protection_stop_buying_rsi_1d.value) + & (dataframe['rsi5'] > self.protection_start_buying_rsi_1d.value) + & (dataframe['rsi5'].shift(1) < self.buy_rsi.value) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.decalage.value) == dataframe['min_n']) + # & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + # & (dataframe['percent'] > -0.005) + # & (dataframe['close'] <= dataframe['close_1d']) + # & (dataframe['close_1d'] <= dataframe['sma3_1d']) + # & (dataframe['close_1d'] <= dataframe['sma5_1d']) + # & (dataframe['close_1d'] <= dataframe['sma10_1d']) + # & (dataframe['adx_1d'] > self.adx_1d_limit.value) + # & (dataframe['rsi3_1d'].shift(288) <= dataframe['rsi3_1d']) + ), ['buy', 'buy_tag']] = (1, 'buy_adx_inf') + + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['percent10'] < -0.05) + # ), ['sell', 'sell_tag']] = (1, 'sell_percent10') + # dataframe.loc[ + # ( + # (dataframe['percent'] < -0.02) + # ), ['sell', 'sell_tag']] = (1, 'sell_percent') + + # print("dans sell" + metadata['pair']) + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + + if (self.stop_buying.get(trade.pair, None) == None): + # logger.info("----------- %s ", trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + self.stop_buying[trade.pair] = False + + if (self.stop_buying[trade.pair] == True): + # logger.info("----------- %s ", trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + return None + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + last_candle_6 = dataframe.iloc[-7].squeeze() + + # last_candle_5 = dataframe.iloc[-3].squeeze() + # last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # print(last_candle['buy']) + + condition = ( + (previous_last_candle['rsi5'] < self.buy_rsi.value) + & (previous_last_candle['rsi5'] < last_candle['rsi5']) + & (previous_last_candle['rsi5'] < previous_previous_last_candle['rsi5']) + & (last_candle_6['min_n'] == last_candle['min_n']) + & (last_candle['min_max_n'] >= self.buy_min_max_n.value) + # & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + # & (last_candle['close'] <= last_candle['close_1d']) + # & (last_candle['close_1d'] <= last_candle['sma3_1d']) + # & (last_candle['close_1d'] <= last_candle['sma5_1d']) + # & (last_candle['close_1d'] <= last_candle['sma10_1d']) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + ) + if not (condition): + return None + + # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + # days = (current_time - trade.open_date_utc).days + # minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # logger.info("----------- %s ", trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # " " + str(current_time) + "---------------------") + # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # " " + str(current_time) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/Zeus_8d_1.py b/Zeus_8d_1.py new file mode 100644 index 0000000..cf19a55 --- /dev/null +++ b/Zeus_8d_1.py @@ -0,0 +1,472 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8d_1(IStrategy): + + # Buy hyperspace params: + buy_params = { + "buy_min_horizon": 63, + "buy_min_max_n": 0.11, + "buy_rsi": 30, + "decalage": 2, + } + + # Sell hyperspace params: + sell_params = { + "sell_b_RSI": 85, + "sell_percent": 0.08, + "sell_profit_percent": 0.2, + } + + # Protection hyperspace params: + protection_params = { + "protection_nb_buy_lost": 1, + "protection_percent_buy_lost": 24, + "protection_start_buying_rsi_1d": 5, + "protection_stop_buying_rsi_1d": 66, + } + + # ROI table: # value loaded from strategy + minimal_roi = { + "0": 10 + } + + # Stoploss: + stoploss = -0.208 + + # Trailing stop: + trailing_stop = False # value loaded from strategy + trailing_stop_positive = None # value loaded from strategy + trailing_stop_positive_offset = 0.0 # value loaded from strategy + trailing_only_offset_is_reached = False # value loaded from strategy + + # Buy hypers + timeframe = '4h' + + stop_buying = {} + + # DCA config + # position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + trades = list() + + buy_min_horizon = IntParameter(1, 100, default=7, space='buy') + buy_rsi = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n = DecimalParameter(0.01, 0.2, decimals=2, default=0.05, space='buy') + decalage = IntParameter(1, 12, default=6, space='buy') + # adx_1d_limit = IntParameter(15, 45, default=18, space='buy') + sell_b_RSI = IntParameter(60, 98, default=60, space='sell') + sell_profit_percent = DecimalParameter(0.1, 1.5, decimals=1, default=0.8, space='sell') + + sell_percent = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + protection_stop_buying_rsi_1d = IntParameter(50, 100, default=76, space='protection') + protection_start_buying_rsi_1d = IntParameter(1, 50, default=30, space='protection') + + def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + allow_to_buy = True + # info_previous_last_candle = informative.iloc[-2].squeeze() + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1].squeeze() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if self.stop_buying.get(pair, None) is None: + print("enable buying tag", pair) + self.stop_buying[pair] = False + + if ((last_candle['rsi5'] >= self.protection_stop_buying_rsi_1d.value) | (last_candle['close'] >= last_candle['bb_upperband'])) \ + & (self.stop_buying[pair] is False): + logger.info("1 - Disable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = True + + if self.stop_buying[pair] is True: + if ((last_candle['rsi5'] <= self.protection_start_buying_rsi_1d.value) & (last_candle['percent5'] >= 0.005)): + logger.info("2 - Enable buying %s date %s", pair, last_candle['date']) + self.stop_buying[pair] = False + + logger.info("Buy ==> %s ", pair + " " + str(current_time) + "---------------------") + + if self.stop_buying[pair]: + allow_to_buy = False + logger.info("3 - cancel buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + else: + logger.info("3 - accept buying %s date %s", pair, str(last_candle['date']) + " " + str(last_candle['rsi5'])) + return allow_to_buy + + def custom_sell(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() + previous_last_candle = dataframe.iloc[-2].squeeze() + previous_previous_last_candle = dataframe.iloc[-3].squeeze() + + if (current_profit > self.buy_min_max_n.value * self.sell_profit_percent.value): + # \ + # & (previous_last_candle['rsi5'] > self.sell_b_RSI.value) \ + # & (previous_last_candle['rsi5'] >= last_candle['rsi5']) \ + # & (previous_last_candle['rsi5'] >= previous_previous_last_candle['rsi5']): + logger.info("Sell ==> %s ", pair + " " + str(current_time) + " " + str(current_profit) + + " " + str(self.buy_min_max_n.value * self.sell_profit_percent.value) + + " " + str(previous_previous_last_candle['rsi5']) + " " + str( + previous_last_candle['rsi5']) + " " + str(last_candle['rsi5']) + ) + return 'profit_1' # + str(self.sell_percent.value) + # else: + # logger.info("No Sell ==> %s ", pair + " " + str(current_time) + " " + str(current_profit) + # + " " + str(self.buy_min_max_n.value * self.sell_profit_percent.value) + # + " " + str(previous_previous_last_candle['rsi5']) + " " + str(previous_last_candle['rsi5']) + " " + str(last_candle['rsi5']) + # ) + return None + + # def informative_pairs(self): + # # get access to all pairs available in whitelist. + # pairs = self.dp.current_whitelist() + # informative_pairs = [(pair, '4h') for pair in pairs] + # # informative_pairs += [(pair, '4h') for pair in pairs] + # informative_pairs += [(pair, '1h') for pair in pairs] + # + # return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + # dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + # dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + # dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + # dataframe['min200_1'] = dataframe['min200'] * 1.005 + # dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + # dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + # dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + # dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + # dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + # dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + # dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + # dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + # dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + # dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + # dataframe['stop_buying'] = (dataframe['rsi5'] >= self.protection_stop_buying_rsi_1d.value) \ + # & (dataframe['close'] >= dataframe['bb_upperband']) + + # ################### INFORMATIVE 1D + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # # informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + # # informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + # # informative['pct_change_1'] = informative['close'].pct_change(1) + # # informative['pct_change_3'] = informative['close'].pct_change(3) + # # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # # informative['adx'] = talib.ADX(informative) + # + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # informative["bb_percent"] = ( + # (informative["close"] - informative["bb_lowerband"]) / + # (informative["bb_upperband"] - informative["bb_lowerband"]) + # ) + # + # # informative["bb_width"] = ( + # # (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + # # ) + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + # ######################## INFORMATIVE 4h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + # informative["rsi"] = talib.RSI(informative) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi3"] = talib.RSI(informative, 3) + # informative["mrsi3"] = informative["rsi"].rolling(3).mean() + # informative['pct_change_1'] = informative['close'].pct_change(1) + # informative['pct_change_3'] = informative['close'].pct_change(3) + # informative['pct_change_5'] = informative['close'].pct_change(5) + # informative['sma3'] = talib.SMA(informative, timeperiod=3) + # informative['sma5'] = talib.SMA(informative, timeperiod=5) + # informative['sma10'] = talib.SMA(informative, timeperiod=10) + # informative['adx'] = talib.ADX(informative) + # bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + # informative['bb_lowerband'] = bollinger['lower'] + # informative['bb_middleband'] = bollinger['mid'] + # informative['bb_upperband'] = bollinger['upper'] + # + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi5'] < self.protection_stop_buying_rsi_1d.value) + & (dataframe['rsi5'] > self.protection_start_buying_rsi_1d.value) + & (dataframe['rsi5'].shift(1) < self.buy_rsi.value) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.decalage.value) == dataframe['min_n']) + # & (dataframe['pct_change_1_1d'] > 0) + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + # & (dataframe['percent'] > -0.005) + # & (dataframe['close'] <= dataframe['close_1d']) + # & (dataframe['close_1d'] <= dataframe['sma3_1d']) + # & (dataframe['close_1d'] <= dataframe['sma5_1d']) + # & (dataframe['close_1d'] <= dataframe['sma10_1d']) + # & (dataframe['adx_1d'] > self.adx_1d_limit.value) + # & (dataframe['rsi3_1d'].shift(288) <= dataframe['rsi3_1d']) + ), ['buy', 'buy_tag']] = (1, 'buy_adx_inf') + + return dataframe + + # def bot_loop_start(self, **kwargs) -> None: + # pairs = self.dp.current_whitelist() + # print("Calcul des pairs informatives") + # for pairname in pairs: + # self.stop_buying[pairname] = True + # print("Fin Calcul des pairs informatives") + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # dataframe.loc[ + # ( + # (dataframe['percent10'] < -0.05) + # ), ['sell', 'sell_tag']] = (1, 'sell_percent10') + # dataframe.loc[ + # ( + # (dataframe['percent'] < -0.02) + # ), ['sell', 'sell_tag']] = (1, 'sell_percent') + + # print("dans sell" + metadata['pair']) + return dataframe + + # def adjust_trade_position(self, trade: Trade, current_time: datetime, + # current_rate: float, current_profit: float, min_stake: float, + # max_stake: float, **kwargs): + # dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + # if (len(dataframe) < 1): + # return None + # + # if (self.stop_buying.get(trade.pair, None) == None): + # # logger.info("----------- %s ", trade.pair + " Init stop buying " + str(current_profit) + " " + str(current_time) + "---------------------") + # self.stop_buying[trade.pair] = False + # + # if (self.stop_buying[trade.pair] == True): + # # logger.info("----------- %s ", trade.pair + " Canceled " + str(current_profit) + " " + str(current_time) + "---------------------") + # return None + # last_candle = dataframe.iloc[-1].squeeze() + # previous_last_candle = dataframe.iloc[-2].squeeze() + # previous_previous_last_candle = dataframe.iloc[-3].squeeze() + # last_candle_6 = dataframe.iloc[-7].squeeze() + # + # # last_candle_5 = dataframe.iloc[-3].squeeze() + # # last_candle_decalage = dataframe.iloc[- self.buy_min_max_decalage.value].squeeze() + # # print(last_candle['buy']) + # + # condition = ( + # (previous_last_candle['rsi5'] < self.buy_rsi.value) + # & (previous_last_candle['rsi5'] < last_candle['rsi5']) + # & (previous_last_candle['rsi5'] < previous_previous_last_candle['rsi5']) + # & (last_candle_6['min_n'] == last_candle['min_n']) + # & (last_candle['min_max_n'] >= self.buy_min_max_n.value) + # # & (last_candle['close'] < last_candle['min_n'] * self.buy_min_max_coef.value) + # # & (last_candle['close'] <= last_candle['close_1d']) + # # & (last_candle['close_1d'] <= last_candle['sma3_1d']) + # # & (last_candle['close_1d'] <= last_candle['sma5_1d']) + # # & (last_candle['close_1d'] <= last_candle['sma10_1d']) + # # & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + # ) + # if not (condition): + # return None + # + # # min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + # + # filled_buys = trade.select_filled_orders('buy') + # count_of_buys = len(filled_buys) + # # days = (current_time - trade.open_date_utc).days + # # minutes = (current_time - trade.open_date_utc).seconds / 60 + # # condition = condition & ((last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h'])) + # p = self.protection_percent_buy_lost.value + # percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + # + # if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + # & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + # try: + # p = self.config['stake_amount'] + # factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + # + # stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # # This then calculates current safety order size + # # logger.info("----------- %s ", trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # # " " + str(current_time) + "---------------------") + # # print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + + # # " " + str(current_time) + "---------------------") + # return stake_amount + # except Exception as exception: + # print(exception) + # return None + # return None diff --git a/Zeus_8d_2.json b/Zeus_8d_2.json new file mode 100644 index 0000000..b466e6c --- /dev/null +++ b/Zeus_8d_2.json @@ -0,0 +1,38 @@ +{ + "strategy_name": "Zeus_8d_2", + "params": { + "roi": { + "0": 0.636, + "541": 0.182, + "2571": 0.063, + "7661": 0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.169, + "trailing_stop_positive_offset": 0.206, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_min_horizon": 46, + "buy_min_max_n": 0.2, + "buy_percent": 1.012, + "buy_rsi": 28, + "decalage": 9 + }, + "sell": { + "sell_b_RSI": 87, + "sell_percent": 0.17, + "sell_profit_percent": 0.3 + }, + "protection": { + "protection_start_buying_rsi_1d": 14, + "protection_stop_buying_rsi_1d": 69 + }, + "stoploss": { + "stoploss": -0.268 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-09-03 22:41:55.642221+00:00" +} \ No newline at end of file diff --git a/Zeus_8d_2.py b/Zeus_8d_2.py new file mode 100644 index 0000000..092d984 --- /dev/null +++ b/Zeus_8d_2.py @@ -0,0 +1,277 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +class Zeus_8d_2(IStrategy): + # Buy hyperspace params: + buy_params = { + "buy_min_horizon": 23, + "buy_min_max_n": 0.16, + "buy_rsi": 10, + "decalage": 8, + } + + # Sell hyperspace params: + sell_params = { + "sell_b_RSI": 75, + "sell_percent": 0.1, + "sell_profit_percent": 0.1, + } + + # Protection hyperspace params: + protection_params = { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 17, + "protection_start_buying_rsi_1d": 17, + "protection_stop_buying_rsi_1d": 51, + } + + # ROI table: # value loaded from strategy + minimal_roi = { + "0": 10 + } + + # Stoploss: + stoploss = -1.0 # value loaded from strategy + + # Trailing stop: + trailing_stop = False # value loaded from strategy + trailing_stop_positive = None # value loaded from strategy + trailing_stop_positive_offset = 0.0 # value loaded from strategy + trailing_only_offset_is_reached = False # value loaded from strategy + + # Buy hypers + timeframe = '4h' + + stop_buying = {} + + # DCA config + # position_adjustment_enable = True + + plot_config = { + "main_plot": { + "min200": { + "color": "#86c932" + }, + "min50": { + "color": "white" + }, + # "max200": { + # "color": "yellow" + # }, + "sma3_1d": { + "color": "pink" + }, + "sma5_1d": { + "color": "blue" + }, + "sma10_1d": { + "color": "orange" + }, + "close_1d": { + "color": "#73e233", + }, + "low": { + "color": "cyan", + }, + "bb_lowerband": { + "color": "#da59a6"}, + "bb_upperband": { + "color": "#da59a6", + } + }, + "subplots": { + # "Ind": { + # "trend_ichimoku_base": { + # "color": "#dd1384" + # }, + # "trend_kst_diff": { + # "color": "#850678" + # } + # }, + # "BB": { + # "bb_width": { + # "color": "white" + # }, + # "bb_lower_5": { + # "color": "yellow" + # } + # }, + "Rsi": { + "rsi_1d": { + "color": "pink" + }, + # "rsi_1h": { + # "color": "green" + # }, + "rsi5": { + "color": "yellow" + }, + "rsi3_1d": { + "color": "red" + } + }, + # "Percent": { + # "pct_change_1_1d": { + # "color": "green" + # }, + # "pct_change_3_1d": { + # "color": "orange" + # }, + # "pct_change_5_1d": { + # "color": "red" + # } + # } + } + } + + buy_min_horizon = IntParameter(1, 100, default=7, space='buy') + buy_rsi = IntParameter(1, 30, default=12, space='buy') + buy_min_max_n = DecimalParameter(0.01, 0.2, decimals=2, default=0.05, space='buy') + buy_percent = DecimalParameter(1.005, 1.02, decimals=3, default=1.01, space='buy') + + decalage = IntParameter(1, 12, default=6, space='buy') + sell_b_RSI = IntParameter(60, 98, default=60, space='sell') + sell_profit_percent = DecimalParameter(0.1, 1.5, decimals=1, default=0.8, space='sell') + + sell_percent = DecimalParameter(0.01, 0.30, decimals=2, default=0.05, space='sell') + # protection_percent_buy_lost = IntParameter(1, 30, default=3, space='protection') + # protection_nb_buy_lost = IntParameter(1, 3, default=3, space='protection') + protection_stop_buying_rsi_1d = IntParameter(50, 100, default=76, space='protection') + protection_start_buying_rsi_1d = IntParameter(1, 50, default=30, space='protection') + + # def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str, + # current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool: + # allow_to_buy = True + # # info_previous_last_candle = informative.iloc[-2].squeeze() + # # dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + # # last_candle = dataframe.iloc[-1].squeeze() + # + # return allow_to_buy + + # def custom_sell(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() + # previous_last_candle = dataframe.iloc[-2].squeeze() + # previous_previous_last_candle = dataframe.iloc[-3].squeeze() + # + # if (current_profit > self.buy_min_max_n.value * self.sell_profit_percent.value): + # # \ + # # & (previous_last_candle['rsi5'] > self.sell_b_RSI.value) \ + # # & (previous_last_candle['rsi5'] > last_candle['rsi5']) \ + # # & (previous_last_candle['rsi5'] > previous_previous_last_candle['rsi5']): + # logger.info("Sell ==> %s ", pair + " " + str(current_time) + " " + str(current_profit) + # + " " + str(self.buy_min_max_n.value * self.sell_profit_percent.value) + # + " " + str(previous_previous_last_candle['rsi5']) + " " + str( + # previous_last_candle['rsi5']) + " " + str(last_candle['rsi5']) + # ) + # return 'profit_1' # + str(self.sell_percent.value) + # + # return None + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + # dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + # dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + # dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + # dataframe['min200_1'] = dataframe['min200'] * 1.005 + # dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + # dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + # dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + # dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + # dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + # dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + # dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + # dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + # dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[ + ( + (dataframe['rsi5'] < self.protection_stop_buying_rsi_1d.value) + & (dataframe['rsi5'] > self.protection_start_buying_rsi_1d.value) + # & (dataframe['rsi5'].shift(1) < self.buy_rsi.value) + # & (dataframe['rsi5'].shift(1) < dataframe['rsi5']) + # & (dataframe['rsi5'].shift(1) < dataframe['rsi5'].shift(2)) + & (dataframe['min_n'].shift(self.decalage.value) == dataframe['min_n']) + & (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['close'] <= dataframe['min_n'] * self.buy_percent.value) + + ), ['buy', 'buy_tag']] = (1, 'buy_adx_inf') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + return dataframe diff --git a/Zeus_9.json b/Zeus_9.json new file mode 100644 index 0000000..17a3321 --- /dev/null +++ b/Zeus_9.json @@ -0,0 +1,81 @@ +{ + "strategy_name": "Zeus_9", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_base": 0.0, + "buy_diff": 0.4, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_rsi": 26, + "buy_rsi_sup": 79 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_lost_candles": 11, + "protection_lost_percent": 0.14 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-05-22 20:03:28.505444+00:00" +} \ No newline at end of file diff --git a/Zeus_9.py b/Zeus_9.py new file mode 100644 index 0000000..eb8a15b --- /dev/null +++ b/Zeus_9.py @@ -0,0 +1,707 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_9(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", " 0.015) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > last_candle['bb_width'] / 1.3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle['percent'] < - self.sell_b_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + if (current_profit > 0.025) & ((last_candle['percent'] < -0.005) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)): + return 'h_percent_quick' + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > last_candle['bb_width'] / 0.8) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle['percent'] < - self.sell_h_RSI2_percent.value): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + + # dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + # dataframe['high'], + # dataframe['low'], + # window1=9, + # window2=26, + # visual=False, + # fillna=False + # ) + # KST = ta.trend.KSTIndicator( + # close=dataframe['close'], + # roc1=10, + # roc2=15, + # roc3=20, + # roc4=30, + # window1=10, + # window2=10, + # window3=10, + # window4=15, + # nsig=9, + # fillna=False + # ) + # + # dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_5'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_max200_5'] = (dataframe['min200'] * (1 + dataframe['min_max200'] / 5)) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma10xpct+'] = dataframe['sma10'] * 1.0075 + dataframe['sma10xpct-'] = dataframe['sma10'] * 0.9925 + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + # 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["bb_percent"] = ( + # (dataframe["close"] - dataframe["bb_lowerband"]) / + # (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + # ) + # dataframe["bb_width"] = ( + # (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + # ) + # + # dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + # dataframe['min1.1'] = 1.01 * dataframe['min'] + + # dataframe['sar'] = talib.SAR(dataframe) + # # Normalization + # tib = dataframe['trend_ichimoku_base'] + # dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + # tkd = dataframe['trend_kst_diff'] + # dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ################### INFORMATIVE BTC 1H + # informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + # informative["rsi"] = talib.RSI(informative) + # informative["rsi_5"] = talib.RSI(informative, timeperiod=5) + # informative['pct_change_1'] = informative['close'].pct_change(1) + # dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['close'] <= dataframe['sma10xpct-']) + & (dataframe['close'].shift(1) <= dataframe['close']) + & (dataframe['min50'].shift(2) == dataframe['min50']) + ), ['buy', 'buy_tag']] = (1, 'buy_sma10') + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe diff --git a/Zeus_AI.json b/Zeus_AI.json new file mode 100644 index 0000000..b0efce1 --- /dev/null +++ b/Zeus_AI.json @@ -0,0 +1,116 @@ +{ + "strategy_name": "Zeus_AI", + "params": { + "roi": { + "0": 10 + }, + "stoploss": { + "stoploss": -1.0 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": 0.254, + "trailing_stop_positive_offset": 0.323, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_b_bb_lowerband": 1.03, + "buy_b_bb_width": 0.02, + "buy_min_max_coef": 1.004, + "buy_min_max_cond1": 0.8, + "buy_min_max_decalage": 2, + "buy_min_max_n": 0.02, + "buy_min_max_nh": 14, + "buy_min_max_rsi": 61, + "buy_b_cat": "R", + "buy_h_pct": 0.016, + "buy_h_real": 0.026, + "buy_0_distance": -0.03, + "buy_0_percent20": -0.03, + "buy_1_bb_lower_5": 0.19, + "buy_1_pente_sma10": 0.48, + "buy_1_pente_sma20": 0.33, + "buy_2_bb_lower_5": 0.59, + "buy_2_distance": 0.08, + "buy_2_pente_sma10": 0.46, + "buy_2_pente_sma20": 0.08, + "buy_2_percent20": 0.06, + "buy_3_bb_lower_5": 0.05, + "buy_3_distance": 0.01, + "buy_3_pente_sma10": 0.12, + "buy_3_pente_sma20": 0.27, + "buy_3_percent20": -0.03, + "buy_4_pente_sma10": 0.35, + "buy_4_pente_sma20": 0.22, + "buy_decalage0": 7, + "buy_decalage2": 6, + "buy_decalage3": 7, + "buy_decalage_deb_0": 1, + "buy_decalage_deb_2": 1, + "buy_decalage_deb_3": 1, + "buy_min_horizon": 192, + "buy_real_num0": 0.61, + "buy_real_num1": 0.34, + "buy_real_num2": 0.35 + }, + "sell": { + "profit_b_no_change": false, + "profit_b_old_sma10": false, + "profit_b_over_rsi": true, + "profit_b_quick_gain": true, + "profit_b_quick_gain_3": false, + "profit_b_quick_lost": false, + "profit_b_short_loss": true, + "profit_b_sma10": false, + "profit_b_sma20": false, + "profit_b_sma5": false, + "profit_b_very_old_sma10": false, + "profit_h_no_change": false, + "profit_h_old_sma10": true, + "profit_h_over_rsi": false, + "profit_h_quick_gain": false, + "profit_h_quick_gain_3": true, + "profit_h_quick_lost": false, + "profit_h_short_loss": false, + "profit_h_sma10": false, + "profit_h_sma20": false, + "profit_h_sma5": false, + "profit_h_very_old_sma10": true, + "sell_b_RSI": 92, + "sell_b_RSI2": 72, + "sell_b_RSI2_percent": 0.002, + "sell_b_RSI3": 75, + "sell_b_candels": 2, + "sell_b_percent": 0.012, + "sell_b_percent3": 0.008, + "sell_b_profit_no_change": 0.01, + "sell_b_profit_percent10": 0.0, + "sell_b_too_old_day": 3000, + "sell_b_too_old_percent": 0.016, + "sell_h_RSI": 98, + "sell_h_RSI2": 82, + "sell_h_RSI2_percent": 0.007, + "sell_h_RSI3": 72, + "sell_h_candels": 24, + "sell_h_percent": 0.013, + "sell_h_percent3": 0.02, + "sell_h_profit_no_change": 0.018, + "sell_h_profit_percent10": 0.0002, + "sell_h_too_old_day": 2000, + "sell_h_too_old_percent": 0.01 + }, + "protection": { + "protection_nb_buy_lost": 3, + "protection_percent_buy_lost": 3, + "protection_strategy": 1, + "protection_strategy_amount": 2 + } + }, + "ft_stratparam_v": 1, + "export_time": "2022-08-17 14:09:36.720609+00:00" +} \ No newline at end of file diff --git a/Zeus_AI.py b/Zeus_AI.py new file mode 100644 index 0000000..65e68bd --- /dev/null +++ b/Zeus_AI.py @@ -0,0 +1,1017 @@ +# Zeus Strategy: First Generation of GodStra Strategy with maximum +# AVG/MID profit in USDT +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus +# --- Do not remove these libs --- +from datetime import timedelta, datetime +from typing import Optional + +from freqtrade import data +from freqtrade.persistence import Trade +from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter + +from numpy.lib import math +from freqtrade.strategy.interface import IStrategy +import pandas +from pandas import DataFrame +import time +import logging +import calendar +from freqtrade.loggers import setup_logging +from freqtrade.strategy.strategy_helper import merge_informative_pair + +# -------------------------------- + +# Add your lib to import here +import ta +from functools import reduce +import numpy as np +import talib.abstract as talib +from freqtrade.strategy.strategy_helper import merge_informative_pair +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from random import shuffle + +logger = logging.getLogger(__name__) + +operators = [ + "D", # Disabled gene + ">", # Indicator, bigger than cross indicator + "<", # Indicator, smaller than cross indicator + "=", # Indicator, equal with cross indicator + "C", # Indicator, crossed the cross indicator + "CA", # Indicator, crossed above the cross indicator + "CB", # Indicator, crossed below the cross indicator + ">R", # Normalized indicator, bigger than real number + "=R", # Normalized indicator, equal with real number + "R", # Normalized indicator devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 10) + + # TODO : it ill callculated in populate indicators. + + dataframe[indicator] = gene_calculator(dataframe, indicator) + dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) + + indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" + if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: + dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) + + if operator == ">": + condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) + elif operator == "=": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "<": + condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) + elif operator == "C": + condition = ( + (qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) | + (qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[crossed_indicator].shift(decalage))) + ) + elif operator == "CA": + condition = ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == "CB": + condition = ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) + elif operator == ">R": + condition = (dataframe[indicator].shift(decalage) > real_num) + elif operator == "=R": + condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) + elif operator == "R": + condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) + elif operator == "/=R": + condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), + real_num)) + elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "DT": + condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) + elif operator == "OT": + condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) + elif operator == "CUT": + condition = ( + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "CDT": + condition = ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) & + ( + dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) + ) + ) + elif operator == "COT": + condition = ( + ( + ( + qtpylib.crossed_below(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) | + ( + qtpylib.crossed_above(dataframe[indicator].shift(decalage), + dataframe[indicator_trend_sma].shift(decalage)) + ) + ) & + ( + np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) + ) + ) + return condition, dataframe + +class Zeus_AI(IStrategy): + + # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "4h", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_b_params = { + "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " -0.03): + # self.stop_buy_for_all = True + # return "btc_fall" + + # bb_width_lim = last_candle['bb_width'] / 4 + # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) + + if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): + max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > 0.01) & \ + (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): + return 'b_percent10' + if (current_profit > max_profit) & \ + ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'b_percent_quick' + + if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ + & (days < self.sell_b_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.01" + if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ + & (days < self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.02" + if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "b_too_old_0.03" + + if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "b_quick_lost" + + if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "b_no_change" + + if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): + return "b_quick_gain_param" + + if self.profit_b_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma5' + + if self.profit_b_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma10' + + if self.profit_b_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_sma20' + + if self.profit_b_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ + (last_candle['close'] >= last_candle['max200']) & (last_candle[ + 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_over_rsi_max' + + if self.profit_b_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'b_short_lost' + else: + max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 + max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 + + if (current_profit > max_profit) & ( + (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( + last_candle['percent5'] < -max_percent)): + return 'h_percent_quick' + + # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ + # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): + # return 'h_bb_width_max' + + if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ + & (days < self.sell_h_too_old_day.value * 2)\ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.01" + if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ + & (days < self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.02" + if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): + return "h_too_old_0.03" + + if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( + last_candle['percent3'] < -max_percent): + return "h_quick_lost" + + if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ + & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ + & ((current_time - trade.open_date_utc).seconds >= 3600): + return "h_no_change" + + if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ + & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): + return "h_quick_gain_param" + + if self.profit_h_sma5.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma5'] > last_candle['sma5']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma5' + + if self.profit_h_sma10.value: + if (current_profit > expected_profit) \ + & ((previous_5_candle['sma10'] > last_candle['sma10']) \ + | (last_candle['percent3'] < -expected_profit) | ( + last_candle['percent5'] < -expected_profit)) \ + & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma10' + + if self.profit_h_sma20.value: + if (current_profit > max_percent) \ + & (previous_last_candle['sma10'] > last_candle['sma10']) \ + & ((current_time - trade.open_date_utc).seconds >= 3600) \ + & ((previous_last_candle['sma20'] > last_candle['sma20']) & + ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( + last_candle['percent20'] < 0))): + # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_sma20' + + if self.profit_h_over_rsi.value: + if (current_profit > 0) & (previous_last_candle[ + 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ + (last_candle[ + 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_2' + + if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ + (last_candle['close'] >= last_candle[ + 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_over_rsi_max' + + if self.profit_h_short_loss.value: + if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( + last_candle['percent'] < 0) \ + & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): + # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) + return 'h_short_lost' + + def informative_pairs(self): + # get access to all pairs available in whitelist. + pairs = self.dp.current_whitelist() + informative_pairs = [(pair, '1d') for pair in pairs] + informative_pairs += [(pair, '4h') for pair in pairs] + informative_pairs += [(pair, '1h') for pair in pairs] + + corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"] + for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]: + for pair in pairs: + informative_pairs.append((pair, tf)) + for pair in corr_pairs: + if pair in pairs: + continue # avoid duplication + informative_pairs.append((pair, tf)) + + return informative_pairs + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # Add all ta features + dataframe = self.freqai.start(dataframe, metadata, self) + return dataframe + + def populate_any_indicators(self, pair, dataframe, tf, informative=None, set_generalized_indicators=False): + dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( + dataframe['high'], + dataframe['low'], + window1=9, + window2=26, + visual=False, + fillna=False + ) + KST = ta.trend.KSTIndicator( + close=dataframe['close'], + roc1=10, + roc2=15, + roc3=20, + roc4=30, + window1=10, + window2=10, + window3=10, + window4=15, + nsig=9, + fillna=False + ) + + dataframe['trend_kst_diff'] = KST.kst_diff() + dataframe['pct_change'] = dataframe['close'].pct_change(5) + dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) + dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) + dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) + dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) + dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) + dataframe['min200_1'] = dataframe['min200'] * 1.005 + dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() + + dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) + dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) + dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] + dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) + dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] + dataframe['rsi'] = talib.RSI(dataframe) + dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) + dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) + dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) + dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) + dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) + dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] + dataframe["percent5"] = dataframe["percent"].rolling(5).sum() + dataframe["percent3"] = dataframe["percent"].rolling(3).sum() + dataframe["percent10"] = dataframe["percent"].rolling(10).sum() + dataframe["percent20"] = dataframe["percent"].rolling(20).sum() + dataframe["percent50"] = dataframe["percent"].rolling(50).sum() + # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() + dataframe["volume10"] = dataframe["volume"].rolling(10).mean() + # Bollinger Bands + 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["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) + dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() + dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) + dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) + + # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) + + dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] + dataframe['min1.1'] = 1.01 * dataframe['min'] + dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) + # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() + # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() + + dataframe['min_max_close'] = ( + (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) + dataframe['sar'] = talib.SAR(dataframe) + # Normalization + tib = dataframe['trend_ichimoku_base'] + dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) + tkd = dataframe['trend_kst_diff'] + dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) + + dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) + dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) + dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) + + dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) + dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) + dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) + + dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) + dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) + + ################### INFORMATIVE 1D + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") + informative["rsi"] = talib.RSI(informative) + informative["max3"] = talib.MAX(informative['close'], timeperiod=3) + informative["min3"] = talib.MIN(informative['close'], timeperiod=3) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + informative['sar'] = talib.SAR(informative) + + bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) + informative['bb_lowerband'] = bollinger['lower'] + informative['bb_middleband'] = bollinger['mid'] + informative['bb_upperband'] = bollinger['upper'] + informative["bb_percent"] = ( + (informative["close"] - informative["bb_lowerband"]) / + (informative["bb_upperband"] - informative["bb_lowerband"]) + ) + informative["bb_width"] = ( + (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] + ) + + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) + + ######################## INFORMATIVE 4h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") + informative["rsi"] = talib.RSI(informative) + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) + + ######################## INFORMATIVE 1h + informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") + informative["rsi"] = talib.RSI(informative) + informative["mrsi3"] = informative["rsi"].rolling(3).mean() + informative['pct_change_1'] = informative['close'].pct_change(1) + informative['pct_change_3'] = informative['close'].pct_change(3) + informative['pct_change_5'] = informative['close'].pct_change(5) + informative['sma3'] = talib.SMA(informative, timeperiod=3) + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma10'] = talib.SMA(informative, timeperiod=10) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) + + """ + Function designed to automatically generate, name and merge features + from user indicated timeframes in the configuration file. User controls the indicators + passed to the training/prediction by prepending indicators with `'%-' + coin ` + (see convention below). I.e. user should not prepend any supporting metrics + (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the + model. + :param pair: pair to be used as informative + :param df: strategy dataframe which will receive merges from informatives + :param tf: timeframe of the dataframe which will modify the feature names + :param informative: the dataframe associated with the informative pair + :param coin: the name of the coin which will modify the feature names. + """ + + coin = pair.split('/')[0] + + if informative is None: + informative = self.dp.get_pair_dataframe(pair, tf) + + # first loop is automatically duplicating indicators for time periods + for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: + t = int(t) + informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) + informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) + informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) + + indicators = [col for col in informative if col.startswith("%")] + # This loop duplicates and shifts all indicators to add a sense of recency to data + for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): + if n == 0: + continue + informative_shift = informative[indicators].shift(n) + informative_shift = informative_shift.add_suffix("_shift-" + str(n)) + informative = pandas.concat((informative, informative_shift), axis=1) + + dataframe = merge_informative_pair(dataframe, informative, self.config["timeframe"], tf, ffill=True) + skip_columns = [ + (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] + ] + dataframe = dataframe.drop(columns=skip_columns) + + # Add generalized indicators here (because in live, it will call this + # function to populate indicators during training). Notice how we ensure not to + # add them multiple times + if set_generalized_indicators: + + # user adds targets here by prepending them with &- (see convention below) + # If user wishes to use multiple targets, a multioutput prediction model + # needs to be used such as templates/CatboostPredictionMultiModel.py + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 + ) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (dataframe['trend_ichimoku_base'] <= self.buy_base.value) + & (dataframe['rsi'] < self.buy_rsi.value) + & (dataframe['close'] < dataframe['sma10']) + & (dataframe['close'] < dataframe['bb_lower_width_5']) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['min50'].shift(2) == dataframe['min50']) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') + + dataframe.loc[ + ( + (dataframe['min_max_n'] >= self.buy_min_max_n.value) + & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) + & (dataframe['rsi'] < self.buy_min_max_rsi.value) + & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) + & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) + & (dataframe['pct_change_1_1d'] > 0) + # & (dataframe['min50'] == dataframe['min50'].shift(3)) + # & (dataframe['close'] <= dataframe['close_1d']) + & (dataframe['close'] <= dataframe['close_1h']) + ), ['buy', 'buy_tag']] = (1, 'buy_min_max') + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + return dataframe + + def adjust_trade_position(self, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, min_stake: float, + max_stake: float, **kwargs): + dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) + if (len(dataframe) < 1): + return None + last_candle = dataframe.iloc[-1].squeeze() + last_candle_5 = dataframe.iloc[-3].squeeze() + + min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) + + filled_buys = trade.select_filled_orders('buy') + count_of_buys = len(filled_buys) + days = (current_time - trade.open_date_utc).days + minutes = (current_time - trade.open_date_utc).seconds / 60 + # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( + # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) + + condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']) + p = self.protection_percent_buy_lost.value + percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] + + if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ + & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): + try: + p = self.config['stake_amount'] + factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] + + stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost + # This then calculates current safety order size + # stake_amount = stake_amount * pow(1.5, count_of_buys) + print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") + return stake_amount + except Exception as exception: + print(exception) + return None + return None diff --git a/__pycache__/BB_RTR_dca.cpython-39.pyc b/__pycache__/BB_RTR_dca.cpython-39.pyc new file mode 100644 index 0000000..09ad8aa Binary files /dev/null and b/__pycache__/BB_RTR_dca.cpython-39.pyc differ diff --git a/__pycache__/BinHV45.cpython-39.pyc b/__pycache__/BinHV45.cpython-39.pyc new file mode 100644 index 0000000..39ba8f5 Binary files /dev/null and b/__pycache__/BinHV45.cpython-39.pyc differ diff --git a/__pycache__/BreakEven.cpython-39.pyc b/__pycache__/BreakEven.cpython-39.pyc new file mode 100644 index 0000000..d59b7e0 Binary files /dev/null and b/__pycache__/BreakEven.cpython-39.pyc differ diff --git a/__pycache__/DevilStra.cpython-39.pyc b/__pycache__/DevilStra.cpython-39.pyc new file mode 100644 index 0000000..669ae5b Binary files /dev/null and b/__pycache__/DevilStra.cpython-39.pyc differ diff --git a/__pycache__/DevilStra2.cpython-39.pyc b/__pycache__/DevilStra2.cpython-39.pyc new file mode 100644 index 0000000..7dfae84 Binary files /dev/null and b/__pycache__/DevilStra2.cpython-39.pyc differ diff --git a/__pycache__/Diamond.cpython-39.pyc b/__pycache__/Diamond.cpython-39.pyc new file mode 100644 index 0000000..ce6c6b1 Binary files /dev/null and b/__pycache__/Diamond.cpython-39.pyc differ diff --git a/__pycache__/Empty.cpython-39.pyc b/__pycache__/Empty.cpython-39.pyc new file mode 100644 index 0000000..ef73efe Binary files /dev/null and b/__pycache__/Empty.cpython-39.pyc differ diff --git a/__pycache__/FractalAtr.cpython-39.pyc b/__pycache__/FractalAtr.cpython-39.pyc new file mode 100644 index 0000000..cf01ef4 Binary files /dev/null and b/__pycache__/FractalAtr.cpython-39.pyc differ diff --git a/__pycache__/FractalAtr2.cpython-39.pyc b/__pycache__/FractalAtr2.cpython-39.pyc new file mode 100644 index 0000000..9a0cbd6 Binary files /dev/null and b/__pycache__/FractalAtr2.cpython-39.pyc differ diff --git a/__pycache__/Genetic.cpython-39.pyc b/__pycache__/Genetic.cpython-39.pyc new file mode 100644 index 0000000..7acd8d4 Binary files /dev/null and b/__pycache__/Genetic.cpython-39.pyc differ diff --git a/__pycache__/GodStra.cpython-39.pyc b/__pycache__/GodStra.cpython-39.pyc new file mode 100644 index 0000000..3494160 Binary files /dev/null and b/__pycache__/GodStra.cpython-39.pyc differ diff --git a/__pycache__/GodStraHo.cpython-39.pyc b/__pycache__/GodStraHo.cpython-39.pyc new file mode 100644 index 0000000..fc1b5a1 Binary files /dev/null and b/__pycache__/GodStraHo.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD.cpython-39.pyc b/__pycache__/GodStraJD.cpython-39.pyc new file mode 100644 index 0000000..6765283 Binary files /dev/null and b/__pycache__/GodStraJD.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD1.cpython-39.pyc b/__pycache__/GodStraJD1.cpython-39.pyc new file mode 100644 index 0000000..0059b69 Binary files /dev/null and b/__pycache__/GodStraJD1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD2.cpython-39.pyc b/__pycache__/GodStraJD2.cpython-39.pyc new file mode 100644 index 0000000..78ac846 Binary files /dev/null and b/__pycache__/GodStraJD2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3.cpython-39.pyc b/__pycache__/GodStraJD3.cpython-39.pyc new file mode 100644 index 0000000..368cd92 Binary files /dev/null and b/__pycache__/GodStraJD3.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_1.cpython-39.pyc b/__pycache__/GodStraJD3_1.cpython-39.pyc new file mode 100644 index 0000000..519fc55 Binary files /dev/null and b/__pycache__/GodStraJD3_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_2.cpython-39.pyc b/__pycache__/GodStraJD3_2.cpython-39.pyc new file mode 100644 index 0000000..f570fc3 Binary files /dev/null and b/__pycache__/GodStraJD3_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_3.cpython-39.pyc b/__pycache__/GodStraJD3_3.cpython-39.pyc new file mode 100644 index 0000000..57d0966 Binary files /dev/null and b/__pycache__/GodStraJD3_3.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_4.cpython-39.pyc b/__pycache__/GodStraJD3_4.cpython-39.pyc new file mode 100644 index 0000000..3528f63 Binary files /dev/null and b/__pycache__/GodStraJD3_4.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_4_1.cpython-39.pyc b/__pycache__/GodStraJD3_4_1.cpython-39.pyc new file mode 100644 index 0000000..cfbdd8d Binary files /dev/null and b/__pycache__/GodStraJD3_4_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_5.cpython-39.pyc b/__pycache__/GodStraJD3_5.cpython-39.pyc new file mode 100644 index 0000000..afe1d66 Binary files /dev/null and b/__pycache__/GodStraJD3_5.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_5_1.cpython-39.pyc b/__pycache__/GodStraJD3_5_1.cpython-39.pyc new file mode 100644 index 0000000..4ed2897 Binary files /dev/null and b/__pycache__/GodStraJD3_5_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_5_2.cpython-39.pyc b/__pycache__/GodStraJD3_5_2.cpython-39.pyc new file mode 100644 index 0000000..f25204e Binary files /dev/null and b/__pycache__/GodStraJD3_5_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_5_3.cpython-39.pyc b/__pycache__/GodStraJD3_5_3.cpython-39.pyc new file mode 100644 index 0000000..4ae3038 Binary files /dev/null and b/__pycache__/GodStraJD3_5_3.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_6.cpython-39.pyc b/__pycache__/GodStraJD3_6.cpython-39.pyc new file mode 100644 index 0000000..5e689f1 Binary files /dev/null and b/__pycache__/GodStraJD3_6.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_6_53.cpython-39.pyc b/__pycache__/GodStraJD3_6_53.cpython-39.pyc new file mode 100644 index 0000000..e8d3b57 Binary files /dev/null and b/__pycache__/GodStraJD3_6_53.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_6_53_1.cpython-39.pyc b/__pycache__/GodStraJD3_6_53_1.cpython-39.pyc new file mode 100644 index 0000000..89b36c1 Binary files /dev/null and b/__pycache__/GodStraJD3_6_53_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_6_53_2.cpython-39.pyc b/__pycache__/GodStraJD3_6_53_2.cpython-39.pyc new file mode 100644 index 0000000..729b7e0 Binary files /dev/null and b/__pycache__/GodStraJD3_6_53_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7.cpython-39.pyc b/__pycache__/GodStraJD3_7.cpython-39.pyc new file mode 100644 index 0000000..f54e120 Binary files /dev/null and b/__pycache__/GodStraJD3_7.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_1.cpython-39.pyc b/__pycache__/GodStraJD3_7_1.cpython-39.pyc new file mode 100644 index 0000000..ce87412 Binary files /dev/null and b/__pycache__/GodStraJD3_7_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_2.cpython-39.pyc b/__pycache__/GodStraJD3_7_2.cpython-39.pyc new file mode 100644 index 0000000..f5ed4a7 Binary files /dev/null and b/__pycache__/GodStraJD3_7_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_3.cpython-39.pyc b/__pycache__/GodStraJD3_7_3.cpython-39.pyc new file mode 100644 index 0000000..476a5c1 Binary files /dev/null and b/__pycache__/GodStraJD3_7_3.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_4.cpython-39.pyc b/__pycache__/GodStraJD3_7_4.cpython-39.pyc new file mode 100644 index 0000000..389f180 Binary files /dev/null and b/__pycache__/GodStraJD3_7_4.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5.cpython-39.pyc b/__pycache__/GodStraJD3_7_5.cpython-39.pyc new file mode 100644 index 0000000..5fabea4 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_1.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_1.cpython-39.pyc new file mode 100644 index 0000000..9b8b9e1 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_10.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_10.cpython-39.pyc new file mode 100644 index 0000000..3304f17 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_10.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_2.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_2.cpython-39.pyc new file mode 100644 index 0000000..75dcabf Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_3.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_3.cpython-39.pyc new file mode 100644 index 0000000..5c608a9 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_3.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_4.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_4.cpython-39.pyc new file mode 100644 index 0000000..d3c68e7 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_4.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_5.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_5.cpython-39.pyc new file mode 100644 index 0000000..deb6043 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_5.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_6.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_6.cpython-39.pyc new file mode 100644 index 0000000..67804b4 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_6.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_7.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_7.cpython-39.pyc new file mode 100644 index 0000000..50618da Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_7.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_8.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_8.cpython-39.pyc new file mode 100644 index 0000000..a1c14c9 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_8.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_9.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_9.cpython-39.pyc new file mode 100644 index 0000000..5605957 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_9.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_9_1.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_9_1.cpython-39.pyc new file mode 100644 index 0000000..60bcace Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_9_1.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_5_9_2.cpython-39.pyc b/__pycache__/GodStraJD3_7_5_9_2.cpython-39.pyc new file mode 100644 index 0000000..2c87511 Binary files /dev/null and b/__pycache__/GodStraJD3_7_5_9_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_6.cpython-39.pyc b/__pycache__/GodStraJD3_7_6.cpython-39.pyc new file mode 100644 index 0000000..e38da0f Binary files /dev/null and b/__pycache__/GodStraJD3_7_6.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_7_6_2.cpython-39.pyc b/__pycache__/GodStraJD3_7_6_2.cpython-39.pyc new file mode 100644 index 0000000..c760b99 Binary files /dev/null and b/__pycache__/GodStraJD3_7_6_2.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_8.cpython-39.pyc b/__pycache__/GodStraJD3_8.cpython-39.pyc new file mode 100644 index 0000000..d29aa4b Binary files /dev/null and b/__pycache__/GodStraJD3_8.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD3_9.cpython-39.pyc b/__pycache__/GodStraJD3_9.cpython-39.pyc new file mode 100644 index 0000000..ece2f35 Binary files /dev/null and b/__pycache__/GodStraJD3_9.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD4.cpython-39.pyc b/__pycache__/GodStraJD4.cpython-39.pyc new file mode 100644 index 0000000..c0d7b6e Binary files /dev/null and b/__pycache__/GodStraJD4.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD5.cpython-39.pyc b/__pycache__/GodStraJD5.cpython-39.pyc new file mode 100644 index 0000000..35a10ee Binary files /dev/null and b/__pycache__/GodStraJD5.cpython-39.pyc differ diff --git a/__pycache__/GodStraJD_P.cpython-39.pyc b/__pycache__/GodStraJD_P.cpython-39.pyc new file mode 100644 index 0000000..9ae19d9 Binary files /dev/null and b/__pycache__/GodStraJD_P.cpython-39.pyc differ diff --git a/__pycache__/GodStraNew.cpython-39.pyc b/__pycache__/GodStraNew.cpython-39.pyc new file mode 100644 index 0000000..669396e Binary files /dev/null and b/__pycache__/GodStraNew.cpython-39.pyc differ diff --git a/__pycache__/Heracles.cpython-39.pyc b/__pycache__/Heracles.cpython-39.pyc new file mode 100644 index 0000000..ec7de16 Binary files /dev/null and b/__pycache__/Heracles.cpython-39.pyc differ diff --git a/__pycache__/Heracles_2.cpython-39.pyc b/__pycache__/Heracles_2.cpython-39.pyc new file mode 100644 index 0000000..cc8a82c Binary files /dev/null and b/__pycache__/Heracles_2.cpython-39.pyc differ diff --git a/__pycache__/HourBasedStrategy.cpython-39.pyc b/__pycache__/HourBasedStrategy.cpython-39.pyc new file mode 100644 index 0000000..616b5e3 Binary files /dev/null and b/__pycache__/HourBasedStrategy.cpython-39.pyc differ diff --git a/__pycache__/InformativeSample.cpython-39.pyc b/__pycache__/InformativeSample.cpython-39.pyc new file mode 100644 index 0000000..100df77 Binary files /dev/null and b/__pycache__/InformativeSample.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_1.cpython-39.pyc b/__pycache__/Ishimoku_1.cpython-39.pyc new file mode 100644 index 0000000..cb88768 Binary files /dev/null and b/__pycache__/Ishimoku_1.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_2.cpython-39.pyc b/__pycache__/Ishimoku_2.cpython-39.pyc new file mode 100644 index 0000000..0fd87db Binary files /dev/null and b/__pycache__/Ishimoku_2.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_3.cpython-39.pyc b/__pycache__/Ishimoku_3.cpython-39.pyc new file mode 100644 index 0000000..11735b4 Binary files /dev/null and b/__pycache__/Ishimoku_3.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_4.cpython-39.pyc b/__pycache__/Ishimoku_4.cpython-39.pyc new file mode 100644 index 0000000..344488f Binary files /dev/null and b/__pycache__/Ishimoku_4.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_5.cpython-39.pyc b/__pycache__/Ishimoku_5.cpython-39.pyc new file mode 100644 index 0000000..3582748 Binary files /dev/null and b/__pycache__/Ishimoku_5.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_6.cpython-39.pyc b/__pycache__/Ishimoku_6.cpython-39.pyc new file mode 100644 index 0000000..5d9b11c Binary files /dev/null and b/__pycache__/Ishimoku_6.cpython-39.pyc differ diff --git a/__pycache__/Ishimoku_7.cpython-39.pyc b/__pycache__/Ishimoku_7.cpython-39.pyc new file mode 100644 index 0000000..e641f72 Binary files /dev/null and b/__pycache__/Ishimoku_7.cpython-39.pyc differ diff --git a/__pycache__/MultiMa.cpython-39.pyc b/__pycache__/MultiMa.cpython-39.pyc new file mode 100644 index 0000000..c57b062 Binary files /dev/null and b/__pycache__/MultiMa.cpython-39.pyc differ diff --git a/__pycache__/MyStrategy.cpython-39.pyc b/__pycache__/MyStrategy.cpython-39.pyc new file mode 100644 index 0000000..7f00ee9 Binary files /dev/null and b/__pycache__/MyStrategy.cpython-39.pyc differ diff --git a/__pycache__/NotAnotherSMAOffsetStrategy.cpython-39.pyc b/__pycache__/NotAnotherSMAOffsetStrategy.cpython-39.pyc new file mode 100644 index 0000000..7cad710 Binary files /dev/null and b/__pycache__/NotAnotherSMAOffsetStrategy.cpython-39.pyc differ diff --git a/__pycache__/NotAnotherSMAOffsetStrategyHO.cpython-39.pyc b/__pycache__/NotAnotherSMAOffsetStrategyHO.cpython-39.pyc new file mode 100644 index 0000000..9ae364e Binary files /dev/null and b/__pycache__/NotAnotherSMAOffsetStrategyHO.cpython-39.pyc differ diff --git a/__pycache__/NotAnotherSMAOffsetStrategyX1.cpython-39.pyc b/__pycache__/NotAnotherSMAOffsetStrategyX1.cpython-39.pyc new file mode 100644 index 0000000..129d761 Binary files /dev/null and b/__pycache__/NotAnotherSMAOffsetStrategyX1.cpython-39.pyc differ diff --git a/__pycache__/NotAnotherSMAOffsetStrategy_uzi2.cpython-39.pyc b/__pycache__/NotAnotherSMAOffsetStrategy_uzi2.cpython-39.pyc new file mode 100644 index 0000000..4d3dd58 Binary files /dev/null and b/__pycache__/NotAnotherSMAOffsetStrategy_uzi2.cpython-39.pyc differ diff --git a/__pycache__/Pierrick_20211201.cpython-39.pyc b/__pycache__/Pierrick_20211201.cpython-39.pyc new file mode 100644 index 0000000..ef46e80 Binary files /dev/null and b/__pycache__/Pierrick_20211201.cpython-39.pyc differ diff --git a/__pycache__/PremiereStrategie.cpython-39.pyc b/__pycache__/PremiereStrategie.cpython-39.pyc new file mode 100644 index 0000000..98a02f3 Binary files /dev/null and b/__pycache__/PremiereStrategie.cpython-39.pyc differ diff --git a/__pycache__/RalliV1.cpython-39.pyc b/__pycache__/RalliV1.cpython-39.pyc new file mode 100644 index 0000000..3fefae5 Binary files /dev/null and b/__pycache__/RalliV1.cpython-39.pyc differ diff --git a/__pycache__/RalliV1_disable56.cpython-39.pyc b/__pycache__/RalliV1_disable56.cpython-39.pyc new file mode 100644 index 0000000..0f6678f Binary files /dev/null and b/__pycache__/RalliV1_disable56.cpython-39.pyc differ diff --git a/__pycache__/Reco_1.cpython-39.pyc b/__pycache__/Reco_1.cpython-39.pyc new file mode 100644 index 0000000..9ace820 Binary files /dev/null and b/__pycache__/Reco_1.cpython-39.pyc differ diff --git a/__pycache__/SMAOG.cpython-39.pyc b/__pycache__/SMAOG.cpython-39.pyc new file mode 100644 index 0000000..59b4edd Binary files /dev/null and b/__pycache__/SMAOG.cpython-39.pyc differ diff --git a/__pycache__/SMAOffsetProtectOptV1Mod2.cpython-39.pyc b/__pycache__/SMAOffsetProtectOptV1Mod2.cpython-39.pyc new file mode 100644 index 0000000..395ec1a Binary files /dev/null and b/__pycache__/SMAOffsetProtectOptV1Mod2.cpython-39.pyc differ diff --git a/__pycache__/Scalp.cpython-39.pyc b/__pycache__/Scalp.cpython-39.pyc new file mode 100644 index 0000000..8f1c862 Binary files /dev/null and b/__pycache__/Scalp.cpython-39.pyc differ diff --git a/__pycache__/SecondeStrategie.cpython-39.pyc b/__pycache__/SecondeStrategie.cpython-39.pyc new file mode 100644 index 0000000..585bc21 Binary files /dev/null and b/__pycache__/SecondeStrategie.cpython-39.pyc differ diff --git a/__pycache__/Solipsis5.cpython-39.pyc b/__pycache__/Solipsis5.cpython-39.pyc new file mode 100644 index 0000000..d064548 Binary files /dev/null and b/__pycache__/Solipsis5.cpython-39.pyc differ diff --git a/__pycache__/StJD01.cpython-39.pyc b/__pycache__/StJD01.cpython-39.pyc new file mode 100644 index 0000000..cf1746e Binary files /dev/null and b/__pycache__/StJD01.cpython-39.pyc differ diff --git a/__pycache__/StJD02.cpython-39.pyc b/__pycache__/StJD02.cpython-39.pyc new file mode 100644 index 0000000..c57915b Binary files /dev/null and b/__pycache__/StJD02.cpython-39.pyc differ diff --git a/__pycache__/Strategy001.cpython-39.pyc b/__pycache__/Strategy001.cpython-39.pyc new file mode 100644 index 0000000..5ec9269 Binary files /dev/null and b/__pycache__/Strategy001.cpython-39.pyc differ diff --git a/__pycache__/Strategy001_custom_sell.cpython-39.pyc b/__pycache__/Strategy001_custom_sell.cpython-39.pyc new file mode 100644 index 0000000..8a00116 Binary files /dev/null and b/__pycache__/Strategy001_custom_sell.cpython-39.pyc differ diff --git a/__pycache__/Strategy002.cpython-39.pyc b/__pycache__/Strategy002.cpython-39.pyc new file mode 100644 index 0000000..63c0f9f Binary files /dev/null and b/__pycache__/Strategy002.cpython-39.pyc differ diff --git a/__pycache__/Strategy003.cpython-39.pyc b/__pycache__/Strategy003.cpython-39.pyc new file mode 100644 index 0000000..55596cd Binary files /dev/null and b/__pycache__/Strategy003.cpython-39.pyc differ diff --git a/__pycache__/Strategy004.cpython-39.pyc b/__pycache__/Strategy004.cpython-39.pyc new file mode 100644 index 0000000..dbbbd94 Binary files /dev/null and b/__pycache__/Strategy004.cpython-39.pyc differ diff --git a/__pycache__/Strategy005.cpython-39.pyc b/__pycache__/Strategy005.cpython-39.pyc new file mode 100644 index 0000000..93a03cd Binary files /dev/null and b/__pycache__/Strategy005.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD.cpython-39.pyc b/__pycache__/StrategyJD.cpython-39.pyc new file mode 100644 index 0000000..da6ebee Binary files /dev/null and b/__pycache__/StrategyJD.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_1.cpython-39.pyc b/__pycache__/StrategyJD_1.cpython-39.pyc new file mode 100644 index 0000000..2fd63ee Binary files /dev/null and b/__pycache__/StrategyJD_1.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_2.cpython-39.pyc b/__pycache__/StrategyJD_2.cpython-39.pyc new file mode 100644 index 0000000..5a801db Binary files /dev/null and b/__pycache__/StrategyJD_2.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_3.cpython-39.pyc b/__pycache__/StrategyJD_3.cpython-39.pyc new file mode 100644 index 0000000..d535e9c Binary files /dev/null and b/__pycache__/StrategyJD_3.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_4.cpython-39.pyc b/__pycache__/StrategyJD_4.cpython-39.pyc new file mode 100644 index 0000000..67f9733 Binary files /dev/null and b/__pycache__/StrategyJD_4.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5.cpython-39.pyc b/__pycache__/StrategyJD_5.cpython-39.pyc new file mode 100644 index 0000000..cb80c95 Binary files /dev/null and b/__pycache__/StrategyJD_5.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_2.cpython-39.pyc b/__pycache__/StrategyJD_5_2.cpython-39.pyc new file mode 100644 index 0000000..41f2f35 Binary files /dev/null and b/__pycache__/StrategyJD_5_2.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_3.cpython-39.pyc b/__pycache__/StrategyJD_5_3.cpython-39.pyc new file mode 100644 index 0000000..173232d Binary files /dev/null and b/__pycache__/StrategyJD_5_3.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_4.cpython-39.pyc b/__pycache__/StrategyJD_5_4.cpython-39.pyc new file mode 100644 index 0000000..7e57fd5 Binary files /dev/null and b/__pycache__/StrategyJD_5_4.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_5.cpython-39.pyc b/__pycache__/StrategyJD_5_5.cpython-39.pyc new file mode 100644 index 0000000..255fbed Binary files /dev/null and b/__pycache__/StrategyJD_5_5.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_6.cpython-39.pyc b/__pycache__/StrategyJD_5_6.cpython-39.pyc new file mode 100644 index 0000000..f5c047f Binary files /dev/null and b/__pycache__/StrategyJD_5_6.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_7.cpython-39.pyc b/__pycache__/StrategyJD_5_7.cpython-39.pyc new file mode 100644 index 0000000..8d74bc4 Binary files /dev/null and b/__pycache__/StrategyJD_5_7.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_8.cpython-39.pyc b/__pycache__/StrategyJD_5_8.cpython-39.pyc new file mode 100644 index 0000000..49ff4c6 Binary files /dev/null and b/__pycache__/StrategyJD_5_8.cpython-39.pyc differ diff --git a/__pycache__/StrategyJD_5_9.cpython-39.pyc b/__pycache__/StrategyJD_5_9.cpython-39.pyc new file mode 100644 index 0000000..69aa161 Binary files /dev/null and b/__pycache__/StrategyJD_5_9.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick.cpython-39.pyc b/__pycache__/StrategyPierrick.cpython-39.pyc new file mode 100644 index 0000000..f643034 Binary files /dev/null and b/__pycache__/StrategyPierrick.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick2.cpython-39.pyc b/__pycache__/StrategyPierrick2.cpython-39.pyc new file mode 100644 index 0000000..52933b6 Binary files /dev/null and b/__pycache__/StrategyPierrick2.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick22.cpython-39.pyc b/__pycache__/StrategyPierrick22.cpython-39.pyc new file mode 100644 index 0000000..4f32b80 Binary files /dev/null and b/__pycache__/StrategyPierrick22.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick23.cpython-39.pyc b/__pycache__/StrategyPierrick23.cpython-39.pyc new file mode 100644 index 0000000..4b8fbf9 Binary files /dev/null and b/__pycache__/StrategyPierrick23.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick3.cpython-39.pyc b/__pycache__/StrategyPierrick3.cpython-39.pyc new file mode 100644 index 0000000..d89e89c Binary files /dev/null and b/__pycache__/StrategyPierrick3.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick31.cpython-39.pyc b/__pycache__/StrategyPierrick31.cpython-39.pyc new file mode 100644 index 0000000..e60018e Binary files /dev/null and b/__pycache__/StrategyPierrick31.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick32.cpython-39.pyc b/__pycache__/StrategyPierrick32.cpython-39.pyc new file mode 100644 index 0000000..9db301a Binary files /dev/null and b/__pycache__/StrategyPierrick32.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4.cpython-39.pyc b/__pycache__/StrategyPierrick4.cpython-39.pyc new file mode 100644 index 0000000..9b114a8 Binary files /dev/null and b/__pycache__/StrategyPierrick4.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41.cpython-39.pyc b/__pycache__/StrategyPierrick41.cpython-39.pyc new file mode 100644 index 0000000..1b4bc99 Binary files /dev/null and b/__pycache__/StrategyPierrick41.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick411.cpython-39.pyc b/__pycache__/StrategyPierrick411.cpython-39.pyc new file mode 100644 index 0000000..e79992b Binary files /dev/null and b/__pycache__/StrategyPierrick411.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4111.cpython-39.pyc b/__pycache__/StrategyPierrick4111.cpython-39.pyc new file mode 100644 index 0000000..ad94710 Binary files /dev/null and b/__pycache__/StrategyPierrick4111.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4112.cpython-39.pyc b/__pycache__/StrategyPierrick4112.cpython-39.pyc new file mode 100644 index 0000000..a8f06fe Binary files /dev/null and b/__pycache__/StrategyPierrick4112.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4113.cpython-39.pyc b/__pycache__/StrategyPierrick4113.cpython-39.pyc new file mode 100644 index 0000000..6759cd3 Binary files /dev/null and b/__pycache__/StrategyPierrick4113.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4114.cpython-39.pyc b/__pycache__/StrategyPierrick4114.cpython-39.pyc new file mode 100644 index 0000000..0cae443 Binary files /dev/null and b/__pycache__/StrategyPierrick4114.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4115.cpython-39.pyc b/__pycache__/StrategyPierrick4115.cpython-39.pyc new file mode 100644 index 0000000..660253d Binary files /dev/null and b/__pycache__/StrategyPierrick4115.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4116.cpython-39.pyc b/__pycache__/StrategyPierrick4116.cpython-39.pyc new file mode 100644 index 0000000..d1ec945 Binary files /dev/null and b/__pycache__/StrategyPierrick4116.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4117.cpython-39.pyc b/__pycache__/StrategyPierrick4117.cpython-39.pyc new file mode 100644 index 0000000..7448e8c Binary files /dev/null and b/__pycache__/StrategyPierrick4117.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4118.cpython-39.pyc b/__pycache__/StrategyPierrick4118.cpython-39.pyc new file mode 100644 index 0000000..5830abf Binary files /dev/null and b/__pycache__/StrategyPierrick4118.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4119.cpython-39.pyc b/__pycache__/StrategyPierrick4119.cpython-39.pyc new file mode 100644 index 0000000..3ecd2a2 Binary files /dev/null and b/__pycache__/StrategyPierrick4119.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick411_02.cpython-39.pyc b/__pycache__/StrategyPierrick411_02.cpython-39.pyc new file mode 100644 index 0000000..0c15a2a Binary files /dev/null and b/__pycache__/StrategyPierrick411_02.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick411_03.cpython-39.pyc b/__pycache__/StrategyPierrick411_03.cpython-39.pyc new file mode 100644 index 0000000..2e64706 Binary files /dev/null and b/__pycache__/StrategyPierrick411_03.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick412.cpython-39.pyc b/__pycache__/StrategyPierrick412.cpython-39.pyc new file mode 100644 index 0000000..73a67c2 Binary files /dev/null and b/__pycache__/StrategyPierrick412.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4120.cpython-39.pyc b/__pycache__/StrategyPierrick4120.cpython-39.pyc new file mode 100644 index 0000000..c2324d7 Binary files /dev/null and b/__pycache__/StrategyPierrick4120.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4121.cpython-39.pyc b/__pycache__/StrategyPierrick4121.cpython-39.pyc new file mode 100644 index 0000000..a56dea2 Binary files /dev/null and b/__pycache__/StrategyPierrick4121.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41211.cpython-39.pyc b/__pycache__/StrategyPierrick41211.cpython-39.pyc new file mode 100644 index 0000000..ac18245 Binary files /dev/null and b/__pycache__/StrategyPierrick41211.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41212.cpython-39.pyc b/__pycache__/StrategyPierrick41212.cpython-39.pyc new file mode 100644 index 0000000..46a63c5 Binary files /dev/null and b/__pycache__/StrategyPierrick41212.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41213.cpython-39.pyc b/__pycache__/StrategyPierrick41213.cpython-39.pyc new file mode 100644 index 0000000..7e86bf2 Binary files /dev/null and b/__pycache__/StrategyPierrick41213.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41214.cpython-39.pyc b/__pycache__/StrategyPierrick41214.cpython-39.pyc new file mode 100644 index 0000000..3058809 Binary files /dev/null and b/__pycache__/StrategyPierrick41214.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41215.cpython-39.pyc b/__pycache__/StrategyPierrick41215.cpython-39.pyc new file mode 100644 index 0000000..3553c82 Binary files /dev/null and b/__pycache__/StrategyPierrick41215.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41216.cpython-39.pyc b/__pycache__/StrategyPierrick41216.cpython-39.pyc new file mode 100644 index 0000000..47b16cf Binary files /dev/null and b/__pycache__/StrategyPierrick41216.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41217.cpython-39.pyc b/__pycache__/StrategyPierrick41217.cpython-39.pyc new file mode 100644 index 0000000..296f617 Binary files /dev/null and b/__pycache__/StrategyPierrick41217.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41218.cpython-39.pyc b/__pycache__/StrategyPierrick41218.cpython-39.pyc new file mode 100644 index 0000000..c091502 Binary files /dev/null and b/__pycache__/StrategyPierrick41218.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41219.cpython-39.pyc b/__pycache__/StrategyPierrick41219.cpython-39.pyc new file mode 100644 index 0000000..23ca360 Binary files /dev/null and b/__pycache__/StrategyPierrick41219.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4122.cpython-39.pyc b/__pycache__/StrategyPierrick4122.cpython-39.pyc new file mode 100644 index 0000000..bf82b81 Binary files /dev/null and b/__pycache__/StrategyPierrick4122.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41220.cpython-39.pyc b/__pycache__/StrategyPierrick41220.cpython-39.pyc new file mode 100644 index 0000000..e7144c3 Binary files /dev/null and b/__pycache__/StrategyPierrick41220.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41221.cpython-39.pyc b/__pycache__/StrategyPierrick41221.cpython-39.pyc new file mode 100644 index 0000000..20680d2 Binary files /dev/null and b/__pycache__/StrategyPierrick41221.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41222.cpython-39.pyc b/__pycache__/StrategyPierrick41222.cpython-39.pyc new file mode 100644 index 0000000..c9e2e51 Binary files /dev/null and b/__pycache__/StrategyPierrick41222.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick41223.cpython-39.pyc b/__pycache__/StrategyPierrick41223.cpython-39.pyc new file mode 100644 index 0000000..ffed2b3 Binary files /dev/null and b/__pycache__/StrategyPierrick41223.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick413.cpython-39.pyc b/__pycache__/StrategyPierrick413.cpython-39.pyc new file mode 100644 index 0000000..f22d6f8 Binary files /dev/null and b/__pycache__/StrategyPierrick413.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick415.cpython-39.pyc b/__pycache__/StrategyPierrick415.cpython-39.pyc new file mode 100644 index 0000000..ea664c5 Binary files /dev/null and b/__pycache__/StrategyPierrick415.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick4151.cpython-39.pyc b/__pycache__/StrategyPierrick4151.cpython-39.pyc new file mode 100644 index 0000000..522260e Binary files /dev/null and b/__pycache__/StrategyPierrick4151.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick416.cpython-39.pyc b/__pycache__/StrategyPierrick416.cpython-39.pyc new file mode 100644 index 0000000..c1216d9 Binary files /dev/null and b/__pycache__/StrategyPierrick416.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick42.cpython-39.pyc b/__pycache__/StrategyPierrick42.cpython-39.pyc new file mode 100644 index 0000000..73ae603 Binary files /dev/null and b/__pycache__/StrategyPierrick42.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick43.cpython-39.pyc b/__pycache__/StrategyPierrick43.cpython-39.pyc new file mode 100644 index 0000000..3b90a51 Binary files /dev/null and b/__pycache__/StrategyPierrick43.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick44.cpython-39.pyc b/__pycache__/StrategyPierrick44.cpython-39.pyc new file mode 100644 index 0000000..8b751eb Binary files /dev/null and b/__pycache__/StrategyPierrick44.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick5.cpython-39.pyc b/__pycache__/StrategyPierrick5.cpython-39.pyc new file mode 100644 index 0000000..d0023c8 Binary files /dev/null and b/__pycache__/StrategyPierrick5.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick51.cpython-39.pyc b/__pycache__/StrategyPierrick51.cpython-39.pyc new file mode 100644 index 0000000..26cec37 Binary files /dev/null and b/__pycache__/StrategyPierrick51.cpython-39.pyc differ diff --git a/__pycache__/StrategyPierrick52.cpython-39.pyc b/__pycache__/StrategyPierrick52.cpython-39.pyc new file mode 100644 index 0000000..0d52a9f Binary files /dev/null and b/__pycache__/StrategyPierrick52.cpython-39.pyc differ diff --git a/__pycache__/Supertrend.cpython-39.pyc b/__pycache__/Supertrend.cpython-39.pyc new file mode 100644 index 0000000..1928b42 Binary files /dev/null and b/__pycache__/Supertrend.cpython-39.pyc differ diff --git a/__pycache__/Swing-High-To-Sky.cpython-39.pyc b/__pycache__/Swing-High-To-Sky.cpython-39.pyc new file mode 100644 index 0000000..0668d72 Binary files /dev/null and b/__pycache__/Swing-High-To-Sky.cpython-39.pyc differ diff --git a/__pycache__/TheForce.cpython-39.pyc b/__pycache__/TheForce.cpython-39.pyc new file mode 100644 index 0000000..35ceb8e Binary files /dev/null and b/__pycache__/TheForce.cpython-39.pyc differ diff --git a/__pycache__/TheForce_1.cpython-39.pyc b/__pycache__/TheForce_1.cpython-39.pyc new file mode 100644 index 0000000..0879dbb Binary files /dev/null and b/__pycache__/TheForce_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus.cpython-39.pyc b/__pycache__/Zeus.cpython-39.pyc new file mode 100644 index 0000000..1d258f5 Binary files /dev/null and b/__pycache__/Zeus.cpython-39.pyc differ diff --git a/__pycache__/Zeus_10.cpython-39.pyc b/__pycache__/Zeus_10.cpython-39.pyc new file mode 100644 index 0000000..7f705d7 Binary files /dev/null and b/__pycache__/Zeus_10.cpython-39.pyc differ diff --git a/__pycache__/Zeus_2.cpython-39.pyc b/__pycache__/Zeus_2.cpython-39.pyc new file mode 100644 index 0000000..c4a14c4 Binary files /dev/null and b/__pycache__/Zeus_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_2_1.cpython-39.pyc b/__pycache__/Zeus_2_1.cpython-39.pyc new file mode 100644 index 0000000..657a256 Binary files /dev/null and b/__pycache__/Zeus_2_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_2_2.cpython-39.pyc b/__pycache__/Zeus_2_2.cpython-39.pyc new file mode 100644 index 0000000..47698b0 Binary files /dev/null and b/__pycache__/Zeus_2_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_3.cpython-39.pyc b/__pycache__/Zeus_3.cpython-39.pyc new file mode 100644 index 0000000..3fa1f7c Binary files /dev/null and b/__pycache__/Zeus_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_4.cpython-39.pyc b/__pycache__/Zeus_4.cpython-39.pyc new file mode 100644 index 0000000..8781b1e Binary files /dev/null and b/__pycache__/Zeus_4.cpython-39.pyc differ diff --git a/__pycache__/Zeus_5.cpython-39.pyc b/__pycache__/Zeus_5.cpython-39.pyc new file mode 100644 index 0000000..c6c2038 Binary files /dev/null and b/__pycache__/Zeus_5.cpython-39.pyc differ diff --git a/__pycache__/Zeus_5_1.cpython-39.pyc b/__pycache__/Zeus_5_1.cpython-39.pyc new file mode 100644 index 0000000..03ec664 Binary files /dev/null and b/__pycache__/Zeus_5_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_5_2.cpython-39.pyc b/__pycache__/Zeus_5_2.cpython-39.pyc new file mode 100644 index 0000000..b518170 Binary files /dev/null and b/__pycache__/Zeus_5_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_5_3.cpython-39.pyc b/__pycache__/Zeus_5_3.cpython-39.pyc new file mode 100644 index 0000000..27e5d7d Binary files /dev/null and b/__pycache__/Zeus_5_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_6.cpython-39.pyc b/__pycache__/Zeus_6.cpython-39.pyc new file mode 100644 index 0000000..d54caf5 Binary files /dev/null and b/__pycache__/Zeus_6.cpython-39.pyc differ diff --git a/__pycache__/Zeus_7.cpython-39.pyc b/__pycache__/Zeus_7.cpython-39.pyc new file mode 100644 index 0000000..fcab664 Binary files /dev/null and b/__pycache__/Zeus_7.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8.cpython-39.pyc b/__pycache__/Zeus_8.cpython-39.pyc new file mode 100644 index 0000000..72d6ac6 Binary files /dev/null and b/__pycache__/Zeus_8.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_1.cpython-39.pyc b/__pycache__/Zeus_8_1.cpython-39.pyc new file mode 100644 index 0000000..1d3dc69 Binary files /dev/null and b/__pycache__/Zeus_8_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_2.cpython-39.pyc b/__pycache__/Zeus_8_2.cpython-39.pyc new file mode 100644 index 0000000..b271aeb Binary files /dev/null and b/__pycache__/Zeus_8_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3.cpython-39.pyc b/__pycache__/Zeus_8_3.cpython-39.pyc new file mode 100644 index 0000000..b96c951 Binary files /dev/null and b/__pycache__/Zeus_8_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_1.cpython-39.pyc b/__pycache__/Zeus_8_3_1.cpython-39.pyc new file mode 100644 index 0000000..e28e0d5 Binary files /dev/null and b/__pycache__/Zeus_8_3_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_1_1.cpython-39.pyc b/__pycache__/Zeus_8_3_1_1.cpython-39.pyc new file mode 100644 index 0000000..bc3e0ad Binary files /dev/null and b/__pycache__/Zeus_8_3_1_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2.cpython-39.pyc b/__pycache__/Zeus_8_3_2.cpython-39.pyc new file mode 100644 index 0000000..af4bece Binary files /dev/null and b/__pycache__/Zeus_8_3_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2_1.cpython-39.pyc b/__pycache__/Zeus_8_3_2_1.cpython-39.pyc new file mode 100644 index 0000000..48fff65 Binary files /dev/null and b/__pycache__/Zeus_8_3_2_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2_B_1.cpython-39.pyc b/__pycache__/Zeus_8_3_2_B_1.cpython-39.pyc new file mode 100644 index 0000000..dbe53ff Binary files /dev/null and b/__pycache__/Zeus_8_3_2_B_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2_B_3.cpython-39.pyc b/__pycache__/Zeus_8_3_2_B_3.cpython-39.pyc new file mode 100644 index 0000000..239f509 Binary files /dev/null and b/__pycache__/Zeus_8_3_2_B_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2_B_4.cpython-39.pyc b/__pycache__/Zeus_8_3_2_B_4.cpython-39.pyc new file mode 100644 index 0000000..3fca938 Binary files /dev/null and b/__pycache__/Zeus_8_3_2_B_4.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_2_B_4_2.cpython-39.pyc b/__pycache__/Zeus_8_3_2_B_4_2.cpython-39.pyc new file mode 100644 index 0000000..c7d8802 Binary files /dev/null and b/__pycache__/Zeus_8_3_2_B_4_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_3.cpython-39.pyc b/__pycache__/Zeus_8_3_3.cpython-39.pyc new file mode 100644 index 0000000..9e79b31 Binary files /dev/null and b/__pycache__/Zeus_8_3_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_3_1.cpython-39.pyc b/__pycache__/Zeus_8_3_3_1.cpython-39.pyc new file mode 100644 index 0000000..dddecbe Binary files /dev/null and b/__pycache__/Zeus_8_3_3_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_3_2.cpython-39.pyc b/__pycache__/Zeus_8_3_3_2.cpython-39.pyc new file mode 100644 index 0000000..598b61c Binary files /dev/null and b/__pycache__/Zeus_8_3_3_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_3_3_3.cpython-39.pyc b/__pycache__/Zeus_8_3_3_3.cpython-39.pyc new file mode 100644 index 0000000..463e53d Binary files /dev/null and b/__pycache__/Zeus_8_3_3_3.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8_4h.cpython-39.pyc b/__pycache__/Zeus_8_4h.cpython-39.pyc new file mode 100644 index 0000000..57445fc Binary files /dev/null and b/__pycache__/Zeus_8_4h.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8d.cpython-39.pyc b/__pycache__/Zeus_8d.cpython-39.pyc new file mode 100644 index 0000000..6d1f383 Binary files /dev/null and b/__pycache__/Zeus_8d.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8d_1.cpython-39.pyc b/__pycache__/Zeus_8d_1.cpython-39.pyc new file mode 100644 index 0000000..5241dc7 Binary files /dev/null and b/__pycache__/Zeus_8d_1.cpython-39.pyc differ diff --git a/__pycache__/Zeus_8d_2.cpython-39.pyc b/__pycache__/Zeus_8d_2.cpython-39.pyc new file mode 100644 index 0000000..d45f99b Binary files /dev/null and b/__pycache__/Zeus_8d_2.cpython-39.pyc differ diff --git a/__pycache__/Zeus_9.cpython-39.pyc b/__pycache__/Zeus_9.cpython-39.pyc new file mode 100644 index 0000000..51ee089 Binary files /dev/null and b/__pycache__/Zeus_9.cpython-39.pyc differ diff --git a/__pycache__/Zeus_AI.cpython-39.pyc b/__pycache__/Zeus_AI.cpython-39.pyc new file mode 100644 index 0000000..601972c Binary files /dev/null and b/__pycache__/Zeus_AI.cpython-39.pyc differ diff --git a/__pycache__/custom_indicators.cpython-39.pyc b/__pycache__/custom_indicators.cpython-39.pyc new file mode 100644 index 0000000..473e402 Binary files /dev/null and b/__pycache__/custom_indicators.cpython-39.pyc differ diff --git a/__pycache__/custom_stoploss_with_psar.cpython-39.pyc b/__pycache__/custom_stoploss_with_psar.cpython-39.pyc new file mode 100644 index 0000000..a5073b8 Binary files /dev/null and b/__pycache__/custom_stoploss_with_psar.cpython-39.pyc differ diff --git a/__pycache__/fixed_riskreward_loss.cpython-39.pyc b/__pycache__/fixed_riskreward_loss.cpython-39.pyc new file mode 100644 index 0000000..c734fda Binary files /dev/null and b/__pycache__/fixed_riskreward_loss.cpython-39.pyc differ diff --git a/__pycache__/hlhb.cpython-39.pyc b/__pycache__/hlhb.cpython-39.pyc new file mode 100644 index 0000000..d2d9445 Binary files /dev/null and b/__pycache__/hlhb.cpython-39.pyc differ diff --git a/__pycache__/jeroen_test.cpython-39.pyc b/__pycache__/jeroen_test.cpython-39.pyc new file mode 100644 index 0000000..1c6825f Binary files /dev/null and b/__pycache__/jeroen_test.cpython-39.pyc differ diff --git a/__pycache__/mabStra.cpython-39.pyc b/__pycache__/mabStra.cpython-39.pyc new file mode 100644 index 0000000..c34e828 Binary files /dev/null and b/__pycache__/mabStra.cpython-39.pyc differ diff --git a/__pycache__/wtc.cpython-39.pyc b/__pycache__/wtc.cpython-39.pyc new file mode 100644 index 0000000..b056877 Binary files /dev/null and b/__pycache__/wtc.cpython-39.pyc differ diff --git a/custom_indicators.py b/custom_indicators.py new file mode 100644 index 0000000..6faa625 --- /dev/null +++ b/custom_indicators.py @@ -0,0 +1,222 @@ +""" +Solipsis Custom Indicators and Maths +""" +import numpy as np +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + +from pandas import DataFrame, Series + +""" +Misc. Helper Functions +""" + + +def same_length(bigger, shorter): + return np.concatenate((np.full((bigger.shape[0] - shorter.shape[0]), np.nan), shorter)) + + +""" +Maths +""" + + +def linear_growth(start: float, end: float, start_time: int, end_time: int, trade_time: int) -> float: + """ + Simple linear growth function. Grows from start to end after end_time minutes (starts after start_time minutes) + """ + time = max(0, trade_time - start_time) + rate = (end - start) / (end_time - start_time) + + return min(end, start + (rate * time)) + + +def linear_decay(start: float, end: float, start_time: int, end_time: int, trade_time: int) -> float: + """ + Simple linear decay function. Decays from start to end after end_time minutes (starts after start_time minutes) + """ + time = max(0, trade_time - start_time) + rate = (start - end) / (end_time - start_time) + + return max(end, start - (rate * time)) + + +""" +TA Indicators +""" + + +def zema(dataframe, period, field='close'): + """ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/overlap_studies.py#L79 + Modified slightly to use ta.EMA instead of technical ema + """ + df = dataframe.copy() + + df['ema1'] = ta.EMA(df[field], timeperiod=period) + df['ema2'] = ta.EMA(df['ema1'], timeperiod=period) + df['d'] = df['ema1'] - df['ema2'] + df['zema'] = df['ema1'] + df['d'] + + return df['zema'] + + +def RMI(dataframe, *, length=20, mom=5): + """ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/indicators.py#L912 + """ + df = dataframe.copy() + + df['maxup'] = (df['close'] - df['close'].shift(mom)).clip(lower=0) + df['maxdown'] = (df['close'].shift(mom) - df['close']).clip(lower=0) + + df.fillna(0, inplace=True) + + df["emaInc"] = ta.EMA(df, price='maxup', timeperiod=length) + df["emaDec"] = ta.EMA(df, price='maxdown', timeperiod=length) + + df['RMI'] = np.where(df['emaDec'] == 0, 0, 100 - 100 / (1 + df["emaInc"] / df["emaDec"])) + + return df["RMI"] + + +def mastreak(dataframe: DataFrame, period: int = 4, field='close') -> Series: + """ + MA Streak + Port of: https://www.tradingview.com/script/Yq1z7cIv-MA-Streak-Can-Show-When-a-Run-Is-Getting-Long-in-the-Tooth/ + """ + df = dataframe.copy() + + avgval = zema(df, period, field) + + arr = np.diff(avgval) + pos = np.clip(arr, 0, 1).astype(bool).cumsum() + neg = np.clip(arr, -1, 0).astype(bool).cumsum() + streak = np.where(arr >= 0, pos - np.maximum.accumulate(np.where(arr <= 0, pos, 0)), + -neg + np.maximum.accumulate(np.where(arr >= 0, neg, 0))) + + res = same_length(df['close'], streak) + + return res + + +def pcc(dataframe: DataFrame, period: int = 20, mult: int = 2): + """ + Percent Change Channel + PCC is like KC unless it uses percentage changes in price to set channel distance. + https://www.tradingview.com/script/6wwAWXA1-MA-Streak-Change-Channel/ + """ + df = dataframe.copy() + + df['previous_close'] = df['close'].shift() + + df['close_change'] = (df['close'] - df['previous_close']) / df['previous_close'] * 100 + df['high_change'] = (df['high'] - df['close']) / df['close'] * 100 + df['low_change'] = (df['low'] - df['close']) / df['close'] * 100 + + df['delta'] = df['high_change'] - df['low_change'] + + mid = zema(df, period, 'close_change') + rangema = zema(df, period, 'delta') + + upper = mid + rangema * mult + lower = mid - rangema * mult + + return upper, rangema, lower + + +def SSLChannels(dataframe, length=10, mode='sma'): + """ + Source: https://www.tradingview.com/script/xzIoaIJC-SSL-channel/ + Source: https://github.com/freqtrade/technical/blob/master/technical/indicators/indicators.py#L1025 + Usage: + dataframe['sslDown'], dataframe['sslUp'] = SSLChannels(dataframe, 10) + """ + if mode not in ('sma'): + raise ValueError(f"Mode {mode} not supported yet") + + df = dataframe.copy() + + if mode == 'sma': + df['smaHigh'] = df['high'].rolling(length).mean() + df['smaLow'] = df['low'].rolling(length).mean() + + 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'] + + +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'] + + +def WaveTrend(dataframe, chlen=10, avg=21, smalen=4): + """ + WaveTrend Ocillator by LazyBear + https://www.tradingview.com/script/2KE8wTuF-Indicator-WaveTrend-Oscillator-WT/ + """ + df = dataframe.copy() + + df['hlc3'] = (df['high'] + df['low'] + df['close']) / 3 + df['esa'] = ta.EMA(df['hlc3'], timeperiod=chlen) + df['d'] = ta.EMA((df['hlc3'] - df['esa']).abs(), timeperiod=chlen) + df['ci'] = (df['hlc3'] - df['esa']) / (0.015 * df['d']) + df['tci'] = ta.EMA(df['ci'], timeperiod=avg) + + df['wt1'] = df['tci'] + df['wt2'] = ta.SMA(df['wt1'], timeperiod=smalen) + df['wt1-wt2'] = df['wt1'] - df['wt2'] + + return df['wt1'], df['wt2'] + + +def T3(dataframe, length=5): + """ + T3 Average by HPotter on Tradingview + https://www.tradingview.com/script/qzoC9H1I-T3-Average/ + """ + df = dataframe.copy() + + df['xe1'] = ta.EMA(df['close'], timeperiod=length) + df['xe2'] = ta.EMA(df['xe1'], timeperiod=length) + df['xe3'] = ta.EMA(df['xe2'], timeperiod=length) + df['xe4'] = ta.EMA(df['xe3'], timeperiod=length) + df['xe5'] = ta.EMA(df['xe4'], timeperiod=length) + df['xe6'] = ta.EMA(df['xe5'], timeperiod=length) + b = 0.7 + c1 = -b * b * b + c2 = 3 * b * b + 3 * b * b * b + c3 = -6 * b * b - 3 * b - 3 * b * b * b + c4 = 1 + 3 * b + b * b * b + 3 * b * b + df['T3Average'] = c1 * df['xe6'] + c2 * df['xe5'] + c3 * df['xe4'] + c4 * df['xe3'] + + return df['T3Average'] + + +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 diff --git a/custom_stoploss_with_psar.py b/custom_stoploss_with_psar.py new file mode 100644 index 0000000..92f3e0e --- /dev/null +++ b/custom_stoploss_with_psar.py @@ -0,0 +1,91 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from datetime import datetime +from freqtrade.persistence import Trade + + +class CustomStoplossWithPSAR(IStrategy): + """ + this is an example class, implementing a PSAR based trailing stop loss + you are supposed to take the `custom_stoploss()` and `populate_indicators()` + parts and adapt it to your own strategy + + the populate_buy_trend() function is pretty nonsencial + """ + timeframe = '1h' + stoploss = -0.2 + custom_info = {} + use_custom_stoploss = True + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + result = 1 + if self.custom_info and pair in self.custom_info and trade: + # using current_time directly (like below) will only work in backtesting/hyperopt. + # in live / dry-run, it'll be really the current time + relative_sl = None + if self.dp: + # so we need to get analyzed_dataframe from dp + dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) + # only use .iat[-1] in callback methods, never in "populate_*" methods. + # see: https://www.freqtrade.io/en/latest/strategy-customization/#common-mistakes-when-developing-strategies + last_candle = dataframe.iloc[-1].squeeze() + relative_sl = last_candle['sar'] + + if (relative_sl is not None): + # print("custom_stoploss().relative_sl: {}".format(relative_sl)) + # calculate new_stoploss relative to current_rate + new_stoploss = (current_rate - relative_sl) / current_rate + # turn into relative negative offset required by `custom_stoploss` return implementation + result = new_stoploss - 1 + + # print("custom_stoploss() -> {}".format(result)) + return result + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['sar'] = ta.SAR(dataframe) + if self.dp.runmode.value in ('backtest', 'hyperopt'): + self.custom_info[metadata['pair']] = dataframe[['date', 'sar']].copy().set_index('date') + + # all "normal" indicators: + # e.g. + # dataframe['rsi'] = ta.RSI(dataframe) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Placeholder Strategy: buys when SAR is smaller then candle before + Based on TA indicators, populates the buy signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + dataframe.loc[ + ( + (dataframe['sar'] < dataframe['sar'].shift()) + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Placeholder Strategy: does nothing + Based on TA indicators, populates the sell signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + # Deactivated sell signal to allow the strategy to work correctly + dataframe.loc[:, 'sell'] = 0 + return dataframe diff --git a/fixed_riskreward_loss.py b/fixed_riskreward_loss.py new file mode 100644 index 0000000..1a8d9fc --- /dev/null +++ b/fixed_riskreward_loss.py @@ -0,0 +1,120 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +# isort: skip_file +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame + +from freqtrade.strategy.interface import IStrategy + +# -------------------------------- +# Add your lib to import here +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +from datetime import datetime +from freqtrade.persistence import Trade + +import logging +logger = logging.getLogger(__name__) + +class FixedRiskRewardLoss(IStrategy): + """ + This strategy uses custom_stoploss() to enforce a fixed risk/reward ratio + by first calculating a dynamic initial stoploss via ATR - last negative peak + + After that, we caculate that initial risk and multiply it with an risk_reward_ratio + Once this is reached, stoploss is set to it and sell signal is enabled + + Also there is a break even ratio. Once this is reached, the stoploss is adjusted to minimize + losses by setting it to the buy rate + fees. + """ + + custom_info = { + 'risk_reward_ratio': 3.5, + 'set_to_break_even_at_profit': 1, + } + use_custom_stoploss = True + stoploss = -0.9 + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + + """ + custom_stoploss using a risk/reward ratio + """ + result = break_even_sl = takeprofit_sl = -1 + custom_info_pair = self.custom_info.get(pair) + if custom_info_pair is not None: + # using current_time/open_date directly via custom_info_pair[trade.open_daten] + # would only work in backtesting/hyperopt. + # in live/dry-run, we have to search for nearest row before it + open_date_mask = custom_info_pair.index.unique().get_loc(trade.open_date_utc, method='ffill') + open_df = custom_info_pair.iloc[open_date_mask] + + # trade might be open too long for us to find opening candle + if(len(open_df) != 1): + return -1 # won't update current stoploss + + initial_sl_abs = open_df['stoploss_rate'] + + # calculate initial stoploss at open_date + initial_sl = initial_sl_abs/current_rate-1 + + # calculate take profit treshold + # by using the initial risk and multiplying it + risk_distance = trade.open_rate-initial_sl_abs + reward_distance = risk_distance*self.custom_info['risk_reward_ratio'] + # take_profit tries to lock in profit once price gets over + # risk/reward ratio treshold + take_profit_price_abs = trade.open_rate+reward_distance + # take_profit gets triggerd at this profit + take_profit_pct = take_profit_price_abs/trade.open_rate-1 + + # break_even tries to set sl at open_rate+fees (0 loss) + break_even_profit_distance = risk_distance*self.custom_info['set_to_break_even_at_profit'] + # break_even gets triggerd at this profit + break_even_profit_pct = (break_even_profit_distance+current_rate)/current_rate-1 + + result = initial_sl + if(current_profit >= break_even_profit_pct): + break_even_sl = (trade.open_rate*(1+trade.fee_open+trade.fee_close) / current_rate)-1 + result = break_even_sl + + if(current_profit >= take_profit_pct): + takeprofit_sl = take_profit_price_abs/current_rate-1 + result = takeprofit_sl + + return result + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['atr'] = ta.ATR(dataframe) + dataframe['stoploss_rate'] = dataframe['close']-(dataframe['atr']*2) + self.custom_info[metadata['pair']] = dataframe[['date', 'stoploss_rate']].copy().set_index('date') + + # all "normal" indicators: + # e.g. + # dataframe['rsi'] = ta.RSI(dataframe) + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Placeholder Strategy: buys when SAR is smaller then candle before + Based on TA indicators, populates the buy signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + # Allways buys + dataframe.loc[:, 'buy'] = 1 + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ + Placeholder Strategy: does nothing + Based on TA indicators, populates the sell signal for the given dataframe + :param dataframe: DataFrame + :return: DataFrame with buy column + """ + + # Never sells + dataframe.loc[:, 'sell'] = 0 + return dataframe diff --git a/hlhb.py b/hlhb.py new file mode 100644 index 0000000..b3103e8 --- /dev/null +++ b/hlhb.py @@ -0,0 +1,128 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement + +import numpy as np # noqa +import pandas as pd # noqa +from pandas import DataFrame +from freqtrade.strategy import IStrategy +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib + + +class hlhb(IStrategy): + """ + The HLHB ("Huck loves her bucks!") System simply aims to catch short-term forex trends. + More information in https://www.babypips.com/trading/forex-hlhb-system-explained + """ + + INTERFACE_VERSION = 2 + + position_stacking = "True" + + # Minimal ROI designed for the strategy. + # This attribute will be overridden if the config file contains "minimal_roi". + minimal_roi = { + "0": 0.6225, + "703": 0.2187, + "2849": 0.0363, + "5520": 0 + } + + # Optimal stoploss designed for the strategy. + # This attribute will be overridden if the config file contains "stoploss". + stoploss = -0.3211 + + # Trailing stoploss + trailing_stop = True + trailing_stop_positive = 0.0117 + trailing_stop_positive_offset = 0.0186 + trailing_only_offset_is_reached = True + + # Optimal timeframe for the strategy. + timeframe = '4h' + + # Run "populate_indicators()" only for new candle. + process_only_new_candles = True + + # 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 = True + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 30 + + # 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' + } + + plot_config = { + # Main plot indicators (Moving averages, ...) + 'main_plot': { + 'ema5': {}, + 'ema10': {}, + }, + 'subplots': { + # Subplots - each dict defines one additional plot + "RSI": { + 'rsi': {'color': 'red'}, + }, + "ADX": { + 'adx': {}, + } + } + } + + def informative_pairs(self): + return [] + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['hl2'] = (dataframe["close"] + dataframe["open"]) / 2 + + # Momentum Indicators + # ------------------------------------ + + # RSI + dataframe['rsi'] = ta.RSI(dataframe, timeperiod=10, price='hl2') + + # # EMA - Exponential Moving Average + dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5) + dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10) + + # ADX + dataframe['adx'] = ta.ADX(dataframe) + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['rsi'], 50)) & + (qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10'])) & + (dataframe['adx'] > 25) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_below(dataframe['rsi'], 50)) & + (qtpylib.crossed_below(dataframe['ema5'], dataframe['ema10'])) & + (dataframe['adx'] > 25) & + (dataframe['volume'] > 0) # Make sure Volume is not 0 + ), + 'sell'] = 1 + return dataframe + diff --git a/jeroen_test.py b/jeroen_test.py new file mode 100644 index 0000000..c582a90 --- /dev/null +++ b/jeroen_test.py @@ -0,0 +1,164 @@ + +from freqtrade.strategy.interface import IStrategy +from typing import Dict, List +from functools import reduce +from pandas import DataFrame +from freqtrade.persistence import Trade +from datetime import datetime, date, timedelta + + +import talib.abstract as ta +import freqtrade.vendor.qtpylib.indicators as qtpylib +import numpy # noqa +import logging + +logger = logging.getLogger(__name__) + +class jeroen_test(IStrategy): + + # Minimal ROI designed for the strategy. + minimal_roi = { + "0": 0.02 + } + + order_types = { + 'buy': 'market', + 'sell': 'market', + 'stoploss': 'market', + 'stoploss_on_exchange': False + } + + # Optimal stoploss designed for the strategy + stoploss = -10 + + # Optimal timeframe for the strategy + timeframe = '1m' + + def calc_profit(self, price: float, current: float) -> float: + fee = 1.0007 + profit = ((current*fee) - + (price*fee)) + + return float(f"{profit:.8f}") + + def calc_percentage_lower(self, price: float, current: float) -> float: + fee = 1.0007 + price = price*fee + current = current*fee + lowerpercent = ((price-current)/(price*fee))*100 + + return float(f"{lowerpercent:.8f}") + + def bot_loop_start(self, **kwargs) -> None: + print(" ") + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + """ Adds several different TA indicators to the given DataFrame + """ + profit = False + profit_percent = False + percent_lower = False + current_price = dataframe['close'].iloc[-1] + + dataframe['should_sell'] = False + dataframe['should_buy'] = False + + # Get the previous trade + trade = Trade.get_trades_proxy(is_open=False, pair=metadata['pair']) + if trade: + trade = trade[-1] + lsp = trade.close_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + # Found a bug? When force selling it doesnt close it + else: + lsp = trade.open_rate + if lsp: + percent_lower = self.calc_percentage_lower(price=lsp, current=current_price) + else: + lsp = 0.00 + + # Get the current Trade + trade = Trade.get_trades_proxy(is_open=True, pair=metadata['pair']) + if trade: + trade = trade[-1] + lbp = trade.open_rate + open_trade = True + profit = self.calc_profit(price=lbp, current=current_price) + profit_percent = (profit/lbp)*100 + else: + lbp = 0.00 + open_trade = False + profit = False + profit_percent = False + + + print("------------") + + print("Last Sold For:", lsp) + + if open_trade: + print("Bought for: ", lbp) + print("Current Price: ", current_price) + if profit: + print("Current Profit: ", profit, " ", float(f"{profit_percent:.8f}"), "%") + if percent_lower and not open_trade: + print("Percent Lower: ", float(f"{percent_lower:.8f}"), "%") + + + # Should we Sell? + if profit_percent: + if profit_percent > 1: + dataframe['should_sell'] = True + + # Should we buy? + if not open_trade: + if (lsp == 0.00 ) & (lbp == 0.00): + dataframe['should_buy'] = True + # Is the percentage of what we sold for and the current price 2% lower + if percent_lower > 2: + dataframe['should_buy'] = True + + + dataframe['last_sell_price'] = lsp + dataframe['last_buy_price'] = lbp + + + print("Current Dataframe:") + print(dataframe.tail(1)) + + + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[( + # We have not bought or sold anything yet, lets buy! + ((dataframe['last_sell_price'] == 0.00) & (dataframe['last_buy_price'] == 0.00) ) | + ( + # Make sure the last selling price is higher than the current price + ((dataframe['last_sell_price']) > dataframe['close']) & + + # Calculated earlier + (dataframe['should_buy'] == True) + ) + ), 'buy' + ] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + dataframe.loc[( + # Make at least profit + (dataframe['last_buy_price'] < (dataframe['close'])) & + + # Calculated earlier + (dataframe['should_sell'] == True) & + + # If we have nothing we bought, there is nothing to sell + (dataframe['last_buy_price'] > 0.00) + ), 'sell' + ] = 1 + + return dataframe \ No newline at end of file diff --git a/mabStra.py b/mabStra.py new file mode 100644 index 0000000..1791c92 --- /dev/null +++ b/mabStra.py @@ -0,0 +1,97 @@ +# Author: @Mablue (Masoud Azizi) +# github: https://github.com/mablue/ +# IMPORTANT: DO NOT USE IT WITHOUT HYPEROPT: +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces all --strategy mabStra --config config.json -e 100 + +# --- Do not remove these libs --- +from freqtrade.strategy.parameters import IntParameter, DecimalParameter +from freqtrade.strategy.interface import IStrategy +from pandas import DataFrame +# -------------------------------- + +# Add your lib to import here +import talib.abstract as ta + + +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 diff --git a/wtc.json b/wtc.json new file mode 100644 index 0000000..7282144 --- /dev/null +++ b/wtc.json @@ -0,0 +1,39 @@ +{ + "strategy_name": "wtc", + "params": { + "roi": { + "0": 0.030873, + "569": 0.016689, + "3211": 0.006473, + "7617": 0 + }, + "stoploss": { + "stoploss": -0.128 + }, + "trailing": { + "trailing_stop": false, + "trailing_stop_positive": null, + "trailing_stop_positive_offset": 0.0, + "trailing_only_offset_is_reached": false + }, + "buy": { + "buy_max": 0.99, + "buy_max0": 0.6186, + "buy_max1": 0.8614, + "buy_min": -0.6307, + "buy_min0": 0.006, + "buy_min1": 0.6576 + }, + "sell": { + "sell_max": -0.7979, + "sell_max0": 0.82, + "sell_max1": 0.9821, + "sell_min": -0.5377, + "sell_min0": 0.0628, + "sell_min1": 0.4461 + }, + "protection": {} + }, + "ft_stratparam_v": 1, + "export_time": "2022-03-30 20:42:52.793044+00:00" +} \ No newline at end of file diff --git a/wtc.py b/wtc.py new file mode 100644 index 0000000..bd48090 --- /dev/null +++ b/wtc.py @@ -0,0 +1,156 @@ +# WTC Strategy: WTC(World Trade Center Tabriz) +# is the biggest skyscraper of Tabriz, city of Iran +# (What you want?it not enough for you?that's just it!) +# No, no, I'm kidding. It's also mean Wave Trend with Crosses +# algo by LazyBare(in TradingView) that I reduce it +# signals noise with dividing it to Stoch-RSI indicator. +# Also thanks from discord: @aurax for his/him +# request to making this strategy. +# hope you enjoy and get profit +# Author: @Mablue (Masoud Azizi) +# IMPORTANT: install sklearn befoure you run this strategy: +# pip install sklearn +# github: https://github.com/mablue/ +# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell --strategy wtc + +import freqtrade.vendor.qtpylib.indicators as qtpylib +import talib.abstract as ta +from freqtrade.strategy import DecimalParameter +from freqtrade.strategy import IStrategy +from pandas import DataFrame +# +# --- Do not remove these libs --- +import numpy as np # noqa +import pandas as pd # noqa +from sklearn import preprocessing + +# -------------------------------- +# Add your lib to import here + + +class wtc(IStrategy): + ################################ SETTINGS ################################ + # 61 trades. 16/0/45 Wins/Draws/Losses. + # * Avg profit: 132.53%. + # Median profit: -12.97%. + # Total profit: 0.80921449 BTC ( 809.21Σ%). + # Avg duration 4 days, 7:47:00 min. + # Objective: -15.73417 + + # Config: + # "max_open_trades": 10, + # "stake_currency": "BTC", + # "stake_amount": 0.01, + # "tradable_balance_ratio": 0.99, + # "timeframe": "30m", + # "dry_run_wallet": 0.1, + + # Buy hyperspace params: + buy_params = { + "buy_max": 0.9609, + "buy_max0": 0.8633, + "buy_max1": 0.9133, + "buy_min": 0.0019, + "buy_min0": 0.0102, + "buy_min1": 0.6864, + } + + # Sell hyperspace params: + sell_params = { + "sell_max": -0.7979, + "sell_max0": 0.82, + "sell_max1": 0.9821, + "sell_min": -0.5377, + "sell_min0": 0.0628, + "sell_min1": 0.4461, + } + minimal_roi = { + "0": 0.030873, + "569": 0.016689, + "3211": 0.006473, + "7617": 0 + } + stoploss = -0.128 + ############################## END SETTINGS ############################## + timeframe = '5m' + + buy_max = DecimalParameter(-1, 1, decimals=4, default=0.4393, space='buy') + buy_min = DecimalParameter(-1, 1, decimals=4, default=-0.4676, space='buy') + sell_max = DecimalParameter(-1, 1, decimals=4, + default=-0.9512, space='sell') + sell_min = DecimalParameter(-1, 1, decimals=4, + default=0.6519, space='sell') + + buy_max0 = DecimalParameter(0, 1, decimals=4, default=0.4393, space='buy') + buy_min0 = DecimalParameter(0, 1, decimals=4, default=-0.4676, space='buy') + sell_max0 = DecimalParameter( + 0, 1, decimals=4, default=-0.9512, space='sell') + sell_min0 = DecimalParameter( + 0, 1, decimals=4, default=0.6519, space='sell') + + buy_max1 = DecimalParameter(0, 1, decimals=4, default=0.4393, space='buy') + buy_min1 = DecimalParameter(0, 1, decimals=4, default=-0.4676, space='buy') + sell_max1 = DecimalParameter( + 0, 1, decimals=4, default=-0.9512, space='sell') + sell_min1 = DecimalParameter( + 0, 1, decimals=4, default=0.6519, space='sell') + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # WAVETREND + try: + ap = (dataframe['high']+dataframe['low'] + dataframe['close'])/3 + + esa = ta.EMA(ap, 10) + + d = ta.EMA((ap - esa).abs(), 10) + ci = (ap - esa).div(0.0015 * d) + tci = ta.EMA(ci, 21) + + wt1 = tci + wt2 = ta.SMA(np.nan_to_num(wt1), 4) + + dataframe['wt1'], dataframe['wt2'] = wt1, wt2 + + stoch = ta.STOCH(dataframe, 14) + slowk = stoch['slowk'] + dataframe['slowk'] = slowk + # print(dataframe.iloc[:, 6:].keys()) + x = dataframe.iloc[:, 6:].values # returns a numpy array + min_max_scaler = preprocessing.MinMaxScaler() + x_scaled = min_max_scaler.fit_transform(x) + dataframe.iloc[:, 6:] = pd.DataFrame(x_scaled) + # print('wt:\t', dataframe['wt'].min(), dataframe['wt'].max()) + # print('stoch:\t', dataframe['stoch'].min(), dataframe['stoch'].max()) + dataframe['def'] = dataframe['slowk']-dataframe['wt1'] + # print('def:\t', dataframe['def'].min(), "\t", dataframe['def'].max()) + except: + dataframe['wt1'], dataframe['wt2'], dataframe['def'], dataframe['slowk'] = 0, 10, 100, 1000 + return dataframe + + def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + ( + (qtpylib.crossed_above(dataframe['wt1'], dataframe['wt2'])) + & (dataframe['wt1'].between(self.buy_min0.value, self.buy_max0.value)) + & (dataframe['slowk'].between(self.buy_min1.value, self.buy_max1.value)) + & (dataframe['def'].between(self.buy_min.value, self.buy_max.value)) + + ), + + 'buy'] = 1 + + return dataframe + + def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # print(dataframe['slowk']/dataframe['wt1']) + # dataframe.loc[ + # ( + # (qtpylib.crossed_below(dataframe['wt1'], dataframe['wt2'])) + # & (dataframe['wt1'].between(self.sell_min0.value, self.sell_max0.value)) + # & (dataframe['slowk'].between(self.sell_min1.value, self.sell_max1.value)) + # & (dataframe['def'].between(self.sell_min.value, self.sell_max.value)) + # + # ), + # 'sell'] = 1 + return dataframe diff --git a/wtc.txt b/wtc.txt new file mode 100644 index 0000000..269aa93 --- /dev/null +++ b/wtc.txt @@ -0,0 +1,84 @@ +Result for strategy wtc +=========================================================== BACKTESTING REPORT =========================================================== +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| AVAX/USDT | 128 | 3.14 | 401.62 | 402.019 | 40.20 | 2 days, 0:00:00 | 82 1 45 64.1 | +| SAND/USDT | 151 | 2.59 | 390.41 | 390.799 | 39.08 | 1 day, 17:30:00 | 86 4 61 57.0 | +| SOL/USDT | 115 | 3.09 | 355.10 | 355.451 | 35.55 | 2 days, 2:56:00 | 73 2 40 63.5 | +| BNB/USDT | 102 | 2.63 | 268.01 | 268.276 | 26.83 | 2 days, 17:16:00 | 61 9 32 59.8 | +| IOTX/USDT | 116 | 2.13 | 247.36 | 247.609 | 24.76 | 2 days, 2:29:00 | 67 5 44 57.8 | +| CELR/USDT | 141 | 1.57 | 221.10 | 221.319 | 22.13 | 1 day, 16:46:00 | 77 4 60 54.6 | +| EGLD/USDT | 98 | 2.17 | 212.36 | 212.577 | 21.26 | 2 days, 16:51:00 | 55 9 34 56.1 | +| ETH/USDT | 90 | 2.07 | 186.13 | 186.314 | 18.63 | 3 days, 4:18:00 | 61 7 22 67.8 | +| ROSE/USDT | 133 | 1.08 | 143.78 | 143.929 | 14.39 | 1 day, 23:51:00 | 75 4 54 56.4 | +| XRP/USDT | 100 | 1.30 | 129.63 | 129.765 | 12.98 | 2 days, 17:02:00 | 56 7 37 56.0 | +| TRX/USDT | 104 | 1.19 | 123.99 | 124.118 | 12.41 | 2 days, 19:17:00 | 64 7 33 61.5 | +| ADA/USDT | 99 | 1.05 | 103.63 | 103.729 | 10.37 | 2 days, 19:35:00 | 53 9 37 53.5 | +| ZEC/USDT | 113 | 0.92 | 103.53 | 103.630 | 10.36 | 2 days, 9:05:00 | 68 4 41 60.2 | +| BTC/USDT | 75 | 0.26 | 19.80 | 19.822 | 1.98 | 3 days, 20:41:00 | 46 7 22 61.3 | +| GALA/USDT | 22 | -0.76 | -16.79 | -16.809 | -1.68 | 2 days, 0:28:00 | 8 2 12 36.4 | +| TOTAL | 1587 | 1.82 | 2889.66 | 2892.547 | 289.25 | 2 days, 9:12:00 | 932 81 574 58.7 | +=========================================================== BUY TAG STATS =========================================================== +| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------| +| TOTAL | 1587 | 1.82 | 2889.66 | 2892.547 | 289.25 | 2 days, 9:12:00 | 932 81 574 58.7 | +===================================================== SELL REASON STATS ===================================================== +| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | +|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------| +| roi | 1007 | 926 81 0 100 | 10.19 | 10259.8 | 10270.1 | 683.99 | +| stop_loss | 568 | 0 0 568 0 | -12.97 | -7369.36 | -7376.73 | -491.29 | +| force_sell | 12 | 6 0 6 50.0 | -0.07 | -0.82 | -0.818 | -0.05 | +======================================================== LEFT OPEN TRADES REPORT ========================================================= +| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------| +| SOL/USDT | 1 | 8.51 | 8.51 | 8.514 | 0.85 | 18:20:00 | 1 0 0 100 | +| TRX/USDT | 1 | 2.87 | 2.87 | 2.873 | 0.29 | 18:20:00 | 1 0 0 100 | +| ETH/USDT | 1 | 2.48 | 2.48 | 2.486 | 0.25 | 2 days, 17:25:00 | 1 0 0 100 | +| SAND/USDT | 1 | 1.97 | 1.97 | 1.969 | 0.20 | 1:55:00 | 1 0 0 100 | +| CELR/USDT | 1 | 1.04 | 1.04 | 1.043 | 0.10 | 1 day, 4:50:00 | 1 0 0 100 | +| BTC/USDT | 1 | 0.35 | 0.35 | 0.355 | 0.04 | 1 day, 5:50:00 | 1 0 0 100 | +| BNB/USDT | 1 | -0.23 | -0.23 | -0.234 | -0.02 | 2 days, 5:00:00 | 0 0 1 0 | +| ZEC/USDT | 1 | -0.70 | -0.70 | -0.701 | -0.07 | 2 days, 15:10:00 | 0 0 1 0 | +| XRP/USDT | 1 | -1.76 | -1.76 | -1.762 | -0.18 | 2 days, 12:00:00 | 0 0 1 0 | +| ADA/USDT | 1 | -2.20 | -2.20 | -2.198 | -0.22 | 3 days, 11:45:00 | 0 0 1 0 | +| EGLD/USDT | 1 | -4.22 | -4.22 | -4.225 | -0.42 | 5:00:00 | 0 0 1 0 | +| ROSE/USDT | 1 | -8.93 | -8.93 | -8.938 | -0.89 | 7:20:00 | 0 0 1 0 | +| TOTAL | 12 | -0.07 | -0.82 | -0.818 | -0.08 | 1 day, 12:15:00 | 6 0 6 50.0 | +=============== SUMMARY METRICS ================ +| Metric | Value | +|------------------------+---------------------| +| Backtesting from | 2021-01-01 00:00:00 | +| Backtesting to | 2021-11-20 00:00:00 | +| Max open trades | 15 | +| | | +| Total/Daily Avg Trades | 1587 / 4.91 | +| Starting balance | 1000.000 USDT | +| Final balance | 3892.547 USDT | +| Absolute profit | 2892.547 USDT | +| Total profit % | 289.25% | +| Trades per day | 4.91 | +| Avg. daily profit % | 0.90% | +| Avg. stake amount | 100.000 USDT | +| Total trade volume | 158700.000 USDT | +| | | +| Best Pair | AVAX/USDT 401.62% | +| Worst Pair | GALA/USDT -16.79% | +| Best trade | XRP/USDT 30.84% | +| Worst trade | ZEC/USDT -12.97% | +| Best day | 183.579 USDT | +| Worst day | -231.257 USDT | +| Days win/draw/lose | 213 / 9 / 102 | +| Avg. Duration Winners | 2 days, 4:26:00 | +| Avg. Duration Loser | 2 days, 3:07:00 | +| Rejected Buy signals | 0 | +| | | +| Min balance | 1007.271 USDT | +| Max balance | 3959.355 USDT | +| Drawdown | 1001.50% | +| Drawdown | 1002.499 USDT | +| Drawdown high | 2542.409 USDT | +| Drawdown low | 1539.911 USDT | +| Drawdown Start | 2021-05-07 00:25:00 | +| Drawdown End | 2021-06-22 13:40:00 | +| Market change | 2716.79% | +================================================ \ No newline at end of file