diff --git a/Empty.json b/Empty.json index a999f22..2f5dfb9 100644 --- a/Empty.json +++ b/Empty.json @@ -16,30 +16,22 @@ "max_open_trades": { "max_open_trades": 20 }, - "buy": { - "buy_crossed_indicator0": "sma24_deriv2", - "buy_crossed_indicator1": "sma48_deriv2", - "buy_crossed_indicator2": "sma60_deriv1", - "buy_indicator0": "sma12_deriv1", - "buy_indicator1": "sma3_score", - "buy_indicator2": "sma5_deriv2", - "buy_operator0": ">", - "buy_operator1": "D", - "buy_operator2": "D", - "buy_real_num0": -0.7, - "buy_real_num1": 1.0, - "buy_real_num2": -0.4 + "protection": { + "drop_from_last_entry": -0.015, + "range_pos_stoploss": 0.1, + "stop_buying_indicator": "stop_buying48_1d", + "stoploss_force": -0.01, + "stoploss_indicator": "sma3_deriv2" }, "sell": { "sell_score_indicator": "sma48_score" }, - "protection": { - "range_pos_stoploss": 0.1, - "stop_buying_indicator": "stop_buying60_1d", - "stoploss_force": -0.01, - "stoploss_indicator": "sma3_deriv2" + "buy": { + "buy_deriv_sma12d": -0.01, + "buy_deriv_sma5d": -0.06, + "buy_deriv_sma60": -0.001 } }, "ft_stratparam_v": 1, - "export_time": "2026-02-21 17:38:15.366827+00:00" + "export_time": "2026-02-23 21:02:56.692173+00:00" } \ No newline at end of file diff --git a/Empty.py b/Empty.py index ac19320..8b98142 100644 --- a/Empty.py +++ b/Empty.py @@ -25,6 +25,7 @@ from random import shuffle import logging logger = logging.getLogger(__name__) +timeperiods = [3, 5, 12, 24, 36, 48, 60] # Couleurs ANSI de base RED = "\033[31m" GREEN = "\033[32m" @@ -34,9 +35,10 @@ MAGENTA = "\033[35m" CYAN = "\033[36m" RESET = "\033[0m" -timeperiods = [3, 5, 12, 24, 48, 60] +timeperiods = [3, 5, 12, 24, 36, 48, 60] score_indicators = list() +stop_buying_indicators = list() god_genes_with_timeperiod = list() for timeperiod in timeperiods: # god_genes_with_timeperiod.append(f'max{timeperiod}') @@ -46,6 +48,10 @@ for timeperiod in timeperiods: god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv1") god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv2") god_genes_with_timeperiod.append(f"sma{timeperiod}_score") + + # stoploss_indicators.append(f"stop_buying{timeperiod}") + stop_buying_indicators.append(f"stop_buying{timeperiod}_1d") + score_indicators.append(f"sma{timeperiod}_score") # score_indicators.append(f"sma{timeperiod}_score_1d") @@ -317,7 +323,8 @@ class Empty(IStrategy): 'force_sell': False, 'force_buy': False, 'current_trade': None, - 'last_trade': None + 'last_trade': None, + 'force_stop': False } for pair in ["BTC/USDC", "BTC/USDT"] } @@ -355,22 +362,26 @@ class Empty(IStrategy): } } + buy_deriv_sma60 = DecimalParameter(-0.005, 0.005, decimals=3, default=0, space='buy') + buy_deriv_sma5d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') + buy_deriv_sma12d = DecimalParameter(-0.07, 0.07, decimals=2, default=0, space='buy') + # 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="/ 10) : # # print(f"adjust {current_time} {stake_amount}") @@ -482,10 +493,11 @@ class Empty(IStrategy): drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price if drop_from_last_entry <= self.drop_from_last_entry.value and last_candle['min60'] == last_candle_3['min60'] \ - and (last_candle['range_pos'] < 0)\ - and last_candle['hapercent'] > 0: + and last_candle['range_pos'] < 0.03 and last_candle['hapercent'] > 0: # stake_amount = trade.stake_amount self.pairs[trade.pair]['last_buy'] = current_rate + self.pairs[trade.pair]['total_amount'] += stake_amount + print(f"adjust {pair} drop={drop_from_last_entry} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}") # print(f"adjust {pair} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}") trade_type = last_candle['enter_tag'] if last_candle['enter_long'] == 1 else 'pct48' @@ -495,7 +507,7 @@ class Empty(IStrategy): last_candle=last_candle, date=current_time, action="🟧 Loss -", - dispo=dispo, + dispo=round(dispo,0), pair=trade.pair, rate=current_rate, trade_type=trade_type, @@ -525,6 +537,11 @@ class Empty(IStrategy): condition = True + if condition and last_candle['range_pos'] > 0.05:# and self.pairs[pair]['force_stop']: + condition = last_candle['sma5'] > last_candle['sma60'] + + # if self.pairs[pair]['force_stop'] and last_candle['range_pos'] < 0.02: + # self.pairs[pair]['force_stop'] = False if False and self.pairs[pair]['last_trade'].close_date is not None: # base cooldown = n bougies / cooldown proportionnel au profit @@ -639,12 +656,61 @@ class Empty(IStrategy): before_last_candle = dataframe.iloc[-2] self.pairs[pair]['current_trade'] = trade momentum = last_candle[self.sell_score_indicator.value] + profit = trade.calc_profit(current_rate) #round(current_profit * trade.stake_amount, 1) + count_of_buys = trade.nr_of_successful_entries + expected_profit = self.expectedProfit(pair, last_candle) + + self.pairs[pair]['max_profit'] = max(self.pairs[pair]['max_profit'], profit) + max_profit = self.pairs[pair]['max_profit'] + baisse = 0 + if profit > 0: + baisse = 1 - (profit / max_profit) + mx = max_profit / 5 + self.pairs[pair]['count_of_buys'] = count_of_buys + self.pairs[pair]['current_profit'] = profit + + dispo = round(self.wallets.get_available_stake_amount()) + self.pairs[pair]['total_amount'] + + self.log_trade( + last_candle=last_candle, + date=current_time, + action=("🔴 NOW" if self.pairs[pair]['stop'] else "🟢 NOW "), + dispo=dispo, + pair=pair, + rate=last_candle['close'], + trade_type='momentum' + str(round(momentum, 2)), + profit=round(profit, 2), + buys=count_of_buys, + stake=0 + ) + + if profit > max(5, expected_profit) and baisse > 0.30: + self.pairs[pair]['force_sell'] = True + self.pairs[pair]['force_buy'] = (self.pairs[pair]['count_of_buys'] - self.pairs[pair]['has_gain'] > 3) + return str(count_of_buys) + '_' + 'B30_' + pair + '_' + str(self.pairs[pair]['has_gain']) + + # if last_candle['range_pos'] > 0.05 and current_profit < - last_candle['range_pos'] /4 : #last_candle['cross_sma60']: + # self.pairs[pair]['force_sell'] = True + # return 'Range' + + # if last_candle['range_pos'] > 0.05 and current_profit < - last_candle['range_pos'] /4 \ + # and last_candle['sma5_deriv1_1d'] < 0 and last_candle['sma5_deriv2_1d'] < 0 \ + # and last_candle['sma60_deriv1'] < 0 and last_candle['sma60_deriv2'] < 0: + # self.pairs[pair]['force_sell'] = True + # self.pairs[pair]['force_stop'] = True + # return 'Deriv'; + + if profit < - (dispo * 0.2): + print(f'dispo={dispo} wallet={round(self.wallets.get_available_stake_amount())} limit={-dispo * 0.1}') + self.pairs[pair]['force_sell'] = True + self.pairs[pair]['force_stop'] = True + return 'Force'; # if self.pairs[pair]['force_sell'] and self.pairs[pair]['last_trade'].close_profit > 0.02: # return "Force" - if last_candle['stop_buying']: - self.pairs[pair]['force_sell'] = True - return 'Stop' + # if last_candle['stop_buying']: + # self.pairs[pair]['force_sell'] = True + # return 'Stop' # Si momentum fort → on laisse courir if momentum > 1: return None @@ -664,11 +730,10 @@ class Empty(IStrategy): candle_at_buy = self.pairs[pair]['last_candle'] - # if profit < - 100 : - # print("stop loss detected") - # self.pairs[pair]['force_sell'] = True - # return 0 + # if candle_at_buy['range_pos'] > self.range_pos_stoploss.value and candle_at_buy[self.stoploss_indicator.value] < 0: + # return self.stoploss_force.value + # # print(f'test stop loss {self.stoploss} {last_candle["stop_buying12_1d"]}') # if last_candle[self.stoploss_indicator.value] and (trade.nr_of_successful_entries >= 4 or self.wallets.get_available_stake_amount() < 300): # and profit < - 30 : # range_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"] # range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"] @@ -740,11 +805,11 @@ class Empty(IStrategy): dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) # ###################################################################################################### - range_min = dataframe[f"min24_1d"] + range_min = dataframe[f"min12_1d"] range_max = dataframe[f"max48"] dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean() - + dataframe['cross_sma60'] = qtpylib.crossed_above(dataframe['sma5'], dataframe['sma60']) dataframe[f'stop_buying'] = qtpylib.crossed_below(dataframe[f"sma12"], dataframe['sma48']) # récupérer le dernier trade fermé @@ -812,15 +877,20 @@ class Empty(IStrategy): # conditions.append(condition) # conditions.append((dataframe[self.stop_buying_indicator.value] == False) | (dataframe['range_pos'] < 0)) + #conditions.append((dataframe[self.stop_buying_indicator.value] == False) | (dataframe['range_pos'] < 0)) + + conditions.append(dataframe['sma60_deriv1'] > self.buy_deriv_sma60.value) + conditions.append(dataframe['sma5_deriv1_1d'] > self.buy_deriv_sma5d.value) + conditions.append(dataframe['sma12_deriv1_1d'] > self.buy_deriv_sma12d.value) conditions.append(dataframe['hapercent'] > 0) # # conditions.append(dataframe[f"range_pos"] <= 0.5) conditions.append(((dataframe[f"range_pos"] < 0.05) ) | ((dataframe['sma12_deriv1'] > 0) & (dataframe['sma12_deriv2'] > 0))) - print(f"BUY indicators tested \n" - f"{self.buy_indicator0.value} {self.buy_crossed_indicator0.value} {self.buy_operator0.value} {self.buy_real_num0.value} \n" - f"{self.buy_indicator1.value} {self.buy_crossed_indicator1.value} {self.buy_operator1.value} {self.buy_real_num1.value} \n" - f"{self.buy_indicator2.value} {self.buy_crossed_indicator2.value} {self.buy_operator2.value} {self.buy_real_num2.value} \n" - ) + # print(f"BUY indicators tested \n" + # f"{self.buy_indicator0.value} {self.buy_crossed_indicator0.value} {self.buy_operator0.value} {self.buy_real_num0.value} \n" + # f"{self.buy_indicator1.value} {self.buy_crossed_indicator1.value} {self.buy_operator1.value} {self.buy_real_num1.value} \n" + # f"{self.buy_indicator2.value} {self.buy_crossed_indicator2.value} {self.buy_operator2.value} {self.buy_real_num2.value} \n" + # ) if conditions: dataframe.loc[ @@ -965,7 +1035,7 @@ class Empty(IStrategy): return [ { "method": "CooldownPeriod", - "stop_duration_candles": 12 + "stop_duration_candles": 6 }, # { # "method": "MaxDrawdown", @@ -1123,3 +1193,12 @@ class Empty(IStrategy): def getPctLastBuy(self, pair, last_candle): return round((last_candle['close'] - self.pairs[pair]['last_buy']) / self.pairs[pair]['last_buy'], 4) + + def expectedProfit(self, pair: str, last_candle: DataFrame): + lim = 0.005 + pct = 0.001 + pct_to_max = lim + pct * self.pairs[pair]['count_of_buys'] + expected_profit = lim * self.pairs[pair]['total_amount'] # min(3 * lim, max(lim, pct_to_max)) # 0.004 + 0.002 * self.pairs[pair]['count_of_buys'] #min(0.01, first_max) + + self.pairs[pair]['expected_profit'] = expected_profit + return expected_profit \ No newline at end of file