From f47836c4b783a73ef29689aef34be0bcf2cd5494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Thu, 17 Apr 2025 16:48:44 +0200 Subject: [PATCH] Nouvelle version Zeus_8_3_2_B_4_2.py --- Zeus_8_3_2_B_4_2.py | 392 +++++++++++++++++++++++++++----------------- tools/chute.py | 69 ++++++++ 2 files changed, 311 insertions(+), 150 deletions(-) create mode 100644 tools/chute.py diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index feb65b5..e406f50 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -94,7 +94,27 @@ class Zeus_8_3_2_B_4_2(IStrategy): } } } - + columns_logged = False + pairs = { + pair: { + "first_buy": 0, + "last_max": 0, + "trade_info": {}, + "max_touch": 0.0, + "last_sell": 0.0, + "last_buy": 0.0, + 'count_of_buys': 0, + 'current_profit': 0, + 'expected_profit': 0, + "last_candle": {}, + "last_trade": None, + "last_count_of_buys": 0, + 'base_stake_amount': 0, + 'stop_buy': False + } + for pair in ["BTC/USDC", "ETH/USDC", "DOGE/USDC", "XRP/USDC", "SOL/USDC", + "BTC/USDT", "ETH/USDT", "DOGE/USDT", "XRP/USDT", "SOL/USDT"] + } # 20 20 40 60 100 160 260 420 # 50 50 100 300 500 # fibo = [1, 1, 2, 3, 5, 8, 13, 21] @@ -209,7 +229,32 @@ class Zeus_8_3_2_B_4_2(IStrategy): allow_to_buy = True # (rate <= float(limit)) | (entry_tag == 'force_entry') self.trades = list() dispo = round(self.wallets.get_available_stake_amount()) - print(f"BUY {pair} {entry_tag} {current_time} allow_to_buy={allow_to_buy} dispo={dispo}") + + self.pairs[pair]['first_buy'] = rate + self.pairs[pair]['last_buy'] = rate + self.pairs[pair]['max_touch'] = last_candle['close'] + self.pairs[pair]['last_candle'] = last_candle + self.pairs[pair]['count_of_buys'] = 1 + self.pairs[pair]['current_profit'] = 0 + + print( + f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" + ) + + stake_amount = self.adjust_stake_amount(pair, last_candle) + + self.log_trade( + last_candle=last_candle, + date=current_time, + action="START BUY", + pair=pair, + rate=rate, + dispo=dispo, + profit=0, + trade_type=entry_tag, + buys=1, + stake=round(stake_amount, 2) + ) return allow_to_buy @@ -223,11 +268,27 @@ class Zeus_8_3_2_B_4_2(IStrategy): allow_to_sell = (last_candle['percent'] < 0) if allow_to_sell: + self.trades = list() + self.pairs[pair]['last_count_of_buys'] = self.pairs[pair]['count_of_buys'] + self.pairs[pair]['last_sell'] = rate + self.pairs[pair]['last_trade'] = trade + self.pairs[pair]['last_candle'] = last_candle self.trades = list() dispo= round(self.wallets.get_available_stake_amount()) - print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} amount={amount} rate={rate} open_rate={trade.open_rate}") - else: - print('Cancel Sell ' + exit_reason + ' ' + str(current_time) + ' ' + pair) + # print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} amount={amount} rate={rate} open_rate={trade.open_rate}") + self.log_trade( + last_candle=last_candle, + date=current_time, + action="Sell", + pair=pair, + trade_type=exit_reason, + rate=last_candle['close'], + dispo=dispo, + profit=round(trade.calc_profit(rate, amount), 2) + ) + self.pairs[pair]['max_touch'] = 0 + self.pairs[pair]['last_buy'] = 0 + return (allow_to_sell) | (exit_reason == 'force_exit') def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, @@ -247,26 +308,39 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() + before_last_candle = dataframe.iloc[-2].squeeze() - # self.analyze_conditions(pair, dataframe) - - # print("---------------" + pair + "----------------") expected_profit = self.expectedProfit(pair, last_candle) - # Calcul du prix cible basé sur l'ATR - atr_take_profit = trade.open_rate + (last_candle['atr'] * 2) # Prendre profit à 2x l'ATR + max_touch_before = self.pairs[pair]['max_touch'] + self.pairs[pair]['last_max'] = max(last_candle['haclose'], self.pairs[pair]['last_max']) - # print(f"{pair} Custom exit atr_take_profit={atr_take_profit:.4f}") - # if current_rate >= atr_take_profit: - # return 'sell_atr_take_profit' + count_of_buys = trade.nr_of_successful_entries - if (last_candle['percent3'] < -0.002) & (last_candle['percent12'] < 0) & ( - current_profit > last_candle['min_max200'] / 3): + self.pairs[pair]['count_of_buys'] = count_of_buys + self.pairs[pair]['current_profit'] = current_profit + pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) + + # if (last_candle['rsi_1d'] > 50) & (last_candle['percent12'] < 0.0): + if (last_candle['percent3'] < 0.0) & (current_profit > last_candle['min_max200'] / 3): self.trades = list() - return 'min_max200' + return 'mx_' + str(count_of_buys) if (last_candle['percent12'] <= -0.01) & (current_profit >= expected_profit): self.trades = list() - return 'profit' + return 'profit_' + str(count_of_buys) + if (current_profit >= expected_profit) & (last_candle['percent'] < 0.0) \ + and ((last_candle['rsi'] >= 75) or before_last_candle['rsi'] >= 75): + self.trades = list() + return 'rsi_' + str(count_of_buys) + + # if (last_candle['percent3'] < -0.002) & (last_candle['percent12'] < 0) & ( + # current_profit > last_candle['min_max200'] / 3): + # self.trades = list() + # return 'mnmx_' + str(count_of_buys) + # if (last_candle['percent12'] <= -0.01) & (current_profit >= expected_profit): + # self.trades = list() + # return 'profit_' + str(count_of_buys) + self.pairs[pair]['max_touch'] = max(last_candle['haclose'], self.pairs[pair]['max_touch']) def informative_pairs(self): # get access to all pairs available in whitelist. @@ -276,6 +350,63 @@ class Zeus_8_3_2_B_4_2(IStrategy): return informative_pairs + def log_trade(self, action, pair, date, trade_type=None, rate=None, dispo=None, profit=None, buys=None, stake=None, + last_candle=None): + # Afficher les colonnes une seule fois + if self.config.get('runmode') == 'hyperopt': + return + if self.columns_logged % 30 == 0: + # print( + # f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" + # ) + print( + f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>5} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>12} | {'Buys':>5} | {'Stake':>10} |" + ) + print( + f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|" + ) + self.columns_logged += 1 + date = str(date)[:16] if date else "-" + limit = None + # if buys is not None: + # limit = round(last_rate * (1 - self.fibo[buys] / 100), 4) + + rsi = '' + rsi_pct = '' + # if last_candle is not None: + # if (not np.isnan(last_candle['rsi_1d'])) and (not np.isnan(last_candle['rsi_1h'])): + # rsi = str(int(last_candle['rsi_1d'])) + " " + str(int(last_candle['rsi_1h'])) + # if (not np.isnan(last_candle['rsi_pct_1d'])) and (not np.isnan(last_candle['rsi_pct_1h'])): + # rsi_pct = str(int(10000 * last_candle['bb_mid_pct_1d'])) + " " + str( + # int(last_candle['rsi_pct_1d'])) + " " + str(int(last_candle['rsi_pct_1h'])) + + # first_rate = self.percent_threshold.value + # last_rate = self.threshold.value + # action = self.color_line(action, action) + sma5_1d = '' + sma5_1h = '' + + sma5 = str(sma5_1d) + ' ' + str(sma5_1h) + + last_lost = round((last_candle['haclose'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3) + + max_touch = '' #round(last_candle['max12_1d'], 1) #round(self.pairs[pair]['max_touch'], 1) + pct_max = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) # round(100 * self.pairs[pair]['current_profit'], 1) + + if trade_type is not None: + if np.isnan(last_candle['rsi_1d']): + string = ' ' + else: + string = (str(int(last_candle['rsi_1d']))) + " " + str(int(last_candle['rsi_diff_1d'])) + trade_type = trade_type \ + + " " + string \ + + " " + str(int(last_candle['rsi_1h'])) \ + + " " + str(int(last_candle['rsi_diff_1h'])) + + print( + f"| {date:<16} | {action:<10} | {pair[0:3]:<3} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} | {profit or '-':>8} | {pct_max or '-':>5} | {max_touch or '-':>11} | {last_lost or '-':>12} | {round(self.pairs[pair]['last_max'], 2) or '-':>12} | {buys or '-':>5} | {stake or '-':>10} |" + ) + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Add all ta features pair = metadata['pair'] @@ -333,7 +464,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): (dataframe["close"] - dataframe["bb_lowerband"]) / (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) ) - + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_upperband"] + ) # Normalization dataframe['average_line'] = dataframe['close'].mean() @@ -357,18 +490,18 @@ class Zeus_8_3_2_B_4_2(IStrategy): # # 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 + # Compter les baisses consécutives + dataframe['down'] = dataframe['hapercent'] <= 0.001 + dataframe['up'] = dataframe['hapercent'] >= 0.0001 + dataframe['down_count'] = - dataframe['down'].astype(int) * ( + dataframe['down'].groupby((dataframe['down'] != dataframe['down'].shift()).cumsum()).cumcount() + 1) + dataframe['up_count'] = dataframe['up'].astype(int) * ( + dataframe['up'].groupby((dataframe['up'] != dataframe['up'].shift()).cumsum()).cumcount() + 1) + dataframe['down_tag'] = (dataframe['down_count'] < -7) + dataframe['up_tag'] = (dataframe['up_count'] > 7) + # Créer une colonne vide + dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count') + dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count') # Normaliser les données de 'close' # normalized_close = self.min_max_scaling(dataframe['close']) @@ -376,10 +509,21 @@ class Zeus_8_3_2_B_4_2(IStrategy): 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'] + informative['rsi'] = talib.RSI(informative['close'], length=7) + informative['rsi_diff'] = informative['rsi'] - informative['rsi'].shift(1) + + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma5_pct'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5'] 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'] = talib.RSI(informative['close'], length=7) + informative['rsi_diff'] = informative['rsi'] - informative['rsi'].shift(1) + + informative['sma5'] = talib.SMA(informative, timeperiod=5) + informative['sma5_pct'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5'] + sorted_close_prices = informative['close'].tail(365).sort_values() lowest_4 = sorted_close_prices.head(4) informative['lowest_4'] = lowest_4.mean() @@ -461,7 +605,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # # for buy in filled_buys: # # print(filled_buys) - dataframe['buy_level'] = dataframe['lowest_4_average'] * (1 - self.levels[count_buys] / 100) + # 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() @@ -540,71 +684,20 @@ class Zeus_8_3_2_B_4_2(IStrategy): # 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) + buy_level = dataframe['average_line_50'] #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['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']) - ), ['enter_long', '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) - ) - ), ['enter_long', 'enter_tag']] = (1, 'buy_count_buy') + & (dataframe['min12'].shift(2) == dataframe['min12']) + & (dataframe['up_count'] > 0) + & (dataframe["bb_width"] > 0.01) + ), ['enter_long', 'enter_tag']] = (1, 'mx200') dataframe.loc[ ( @@ -626,51 +719,20 @@ class Zeus_8_3_2_B_4_2(IStrategy): | (dataframe['percent12'] < -0.022) | (dataframe['percent24'] < -0.022) ) - ), ['enter_long', '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']) - ), ['enter_long', 'enter_tag']] = (1, 'buy_percent12') + & (dataframe['up_count'] > 0) + & (dataframe["bb_width"] > 0.01) + ), ['enter_long', 'enter_tag']] = (1, 'pct12') - 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']) - ), ['enter_long', 'enter_tag']] = (1, 'buy_percent_max_144') dataframe.loc[ ( (dataframe['close'] <= dataframe['min200'] * 1.002) + & (dataframe["bb_width"] > 0.01) & (dataframe['min_max200'] > 0.015) - & (dataframe['pct_change'] < 0) + # & (dataframe['pct_change'] < 0) & (dataframe['haopen'] < buy_level) & (dataframe['open'] < dataframe['average_line_288']) - ), ['enter_long', '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) - ), ['enter_long', 'enter_tag']] = (1, 'buy_close_02') - - 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) - ), ['enter_long', 'enter_tag']] = (1, 'buy_average_line_288_098') + & (dataframe['up_count'] > 0) + ), ['enter_long', 'enter_tag']] = (1, 'mnmx200') dataframe.loc[ ( (dataframe['close'].shift(2) <= dataframe['min200']) @@ -680,7 +742,18 @@ class Zeus_8_3_2_B_4_2(IStrategy): & (dataframe['count_buys'] == 0 | ((dataframe['count_buys'] > 0) & (dataframe['close'] <= dataframe['limit'])) ) - ), ['enter_long', 'enter_tag']] = (1, 'buy_min200') + & (dataframe['up_count'] > 0) + ), ['enter_long', 'enter_tag']] = (1, 'min200') + + dataframe.loc[ + ( + # (dataframe['rsi_1h'] < 70) + # & (dataframe['rsi_diff_1h'] > -5) + (dataframe["bb_width"] > 0.01) + & (dataframe['down_count'].shift(1) < - 6) + & (dataframe['down_count'] == 0) + & (dataframe['down_pct'].shift(1) <= -0.5) + ), ['enter_long', 'enter_tag']] = (1, 'down') dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.01, np.nan) @@ -701,7 +774,6 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() # prépare les données - count_of_buys = trade.nr_of_successful_entries current_time = current_time.astimezone(timezone.utc) open_date = trade.open_date.astimezone(timezone.utc) dispo = round(self.wallets.get_available_stake_amount()) @@ -712,12 +784,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): 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 + count_of_buys = trade.nr_of_successful_entries # if 'buy' in last_candle: # condition = (last_candle['buy'] == 1) @@ -725,43 +792,58 @@ class Zeus_8_3_2_B_4_2(IStrategy): # condition = False # self.protection_nb_buy_lost.value limit = last_candle['limit'] - stake_amount = min(200, self.adjust_stake_amount(pair, last_candle) * self.fibo[count_of_buys]) current_time_utc = current_time.astimezone(timezone.utc) open_date = trade.open_date.astimezone(timezone.utc) days_since_open = (current_time_utc - open_date).days + pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) + pct_max = round((last_candle['close'] - self.pairs[trade.pair]['last_buy']) / self.pairs[trade.pair]['last_buy'], 4) + + pct = 0.012 + stake_amount = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle) - 20 * pct_first / pct) #min(200, self.adjust_stake_amount(pair, last_candle) * self.fibo[count_of_buys]) # if (days_since_open > count_of_buys) & (0 < count_of_buys <= max_buys) & (current_rate <= limit) & (last_candle['enter_long'] == 1): - limit_buy = 5 + limit_buy = 20 if (count_of_buys < limit_buy) \ - and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03) \ - and (current_profit < -0.015 * count_of_buys) \ - and (last_candle['enter_long'] == 1): + and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03) \ + and (last_candle['enter_long'] == 1) \ + and (pct_max < - pct - (count_of_buys * 0.001)): try: - # This then calculates current safety order size - # stake_amount = stake_amount * pow(1.5, count_of_buys) - print( - f"Adjust {current_time} price={trade.pair} rate={current_rate:.4f} buys={count_of_buys} limit={limit:.4f} stake={stake_amount:.4f}") - + trade_type = last_candle['enter_tag'] if last_candle['enter_long'] == 1 else 'pct48' + self.log_trade( + last_candle=last_candle, + date=current_time, + action="Loss -", + dispo=dispo, + pair=trade.pair, + rate=current_rate, + trade_type=trade_type, + profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2), + buys=trade.nr_of_successful_entries + 1, + stake=round(stake_amount, 2) + ) + self.pairs[trade.pair]['last_buy'] = current_rate + self.pairs[trade.pair]['max_touch'] = last_candle['close'] + self.pairs[trade.pair]['last_candle'] = last_candle return stake_amount except Exception as exception: print(exception) return None return None - def adjust_stake_amount(self, pair: str, dataframe: DataFrame): + def adjust_stake_amount(self, pair: str, last_candle: DataFrame): # Calculer le minimum des 14 derniers jours - current_price = dataframe['close'] + current_price = last_candle['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é + base_stake_amount = self.config.get('stake_amount', 100) # 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'] + min_14_days_4 = last_candle['lowest_4_1d'] + max_14_days_4 = last_candle['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 @@ -773,7 +855,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # 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(100, base_stake_amount * percent_4)) + adjusted_stake_amount = max(base_stake_amount, min(100, base_stake_amount * percent_4)) # if pair in ('BTC/USDT', 'ETH/USDT'): # if percent_4 > 0.5: # adjusted_stake_amount = 300 @@ -1236,3 +1318,13 @@ class Zeus_8_3_2_B_4_2(IStrategy): # print(asks_with_sma) return asks_with_sma, bids_with_sma + + def calculateUpDownPct(self, dataframe, key): + down_pct_values = np.full(len(dataframe), np.nan) + # Remplir la colonne avec les bons calculs + for i in range(len(dataframe)): + shift_value = abs(int(dataframe[key].iloc[i])) # Récupérer le shift actuel + if i - shift_value > 1: # Vérifier que le shift ne dépasse pas l'index + down_pct_values[i] = 100 * (dataframe['close'].iloc[i] - dataframe['close'].iloc[i - shift_value]) / \ + dataframe['close'].iloc[i - shift_value] + return down_pct_values diff --git a/tools/chute.py b/tools/chute.py new file mode 100644 index 0000000..fafc473 --- /dev/null +++ b/tools/chute.py @@ -0,0 +1,69 @@ +import pandas as pd + + +def detect_btc_crashes_and_rebounds(df, drop_threshold=-10, rebound_threshold=5): + """ + Identifie les plus grosses chutes du BTC et le rebond suivant. + + Paramètres : + - df : DataFrame contenant une colonne 'close' avec les prix du BTC. + - drop_threshold : Seuil de chute en % (ex: -10 pour une chute > 10%). + - rebound_threshold : Seuil de rebond en % après la chute. + + Retourne : + - Une liste des chutes avec le pourcentage de rebond correspondant. + """ + df['return'] = df['close'].pct_change() * 100 # Variation en % + crashes = [] + + in_crash = False + crash_start, crash_end, bottom, rebound_end = None, None, None, None + + for i in range(1, len(df)): + change = df.loc[i, 'return'] + + # Début d'une chute + if change < drop_threshold and not in_crash: + crash_start = i - 1 + in_crash = True + + # En pleine chute, trouver le creux + if in_crash: + if bottom is None or df.loc[i, 'close'] < df.loc[bottom, 'close']: + bottom = i + + # Fin de la chute et début du rebond + if in_crash and change > 0: + crash_end = i + + # Identifier un rebond + if in_crash and crash_end: + rebound_percent = (df.loc[i, 'close'] - df.loc[bottom, 'close']) / df.loc[bottom, 'close'] * 100 + if rebound_percent > rebound_threshold: + rebound_end = i + crashes.append({ + 'crash_start': df.index[crash_start], + 'crash_end': df.index[crash_end], + 'bottom': df.index[bottom], + 'rebound_end': df.index[rebound_end], + 'drop_percent': (df.loc[bottom, 'close'] - df.loc[crash_start, 'close']) / df.loc[ + crash_start, 'close'] * 100, + 'rebound_percent': rebound_percent + }) + in_crash = False # Reset pour détecter une nouvelle chute + + return crashes + +import yfinance as yf + +df = yf.download("BTC-USD", start="2020-01-01", end="2025-01-01", interval="1d") +df.to_csv("btc_prices.csv") +print("Données enregistrées !") + + +# Exemple d'utilisation avec un DataFrame BTC (OHLCV) +df = pd.read_csv("btc_prices.csv", parse_dates=["date"], index_col="date") +crashes = detect_btc_crashes_and_rebounds(df) + +for crash in crashes: + print(crash)