From 4d37361bc64c7405fb369ef675897d47e3d1e788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Tue, 15 Jul 2025 13:45:23 +0200 Subject: [PATCH] Multiple paire detection / limit 3 --- Zeus_8_3_2_B_4_2.py | 146 +++++++++++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 49 deletions(-) diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index fca70d5..e5c7c7a 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -27,6 +27,7 @@ import requests from datetime import timezone, timedelta from scipy.signal import savgol_filter from ta.trend import SMAIndicator, EMAIndicator, MACD, ADXIndicator +from collections import Counter logger = logging.getLogger(__name__) @@ -261,6 +262,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): # if count < 3: # allow_to_buy = False + if not self.should_enter_trade(pair): + allow_to_buy = False + if allow_to_buy: self.trades = list() self.pairs[pair]['first_buy'] = rate @@ -925,6 +929,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): days_since_open = (current_time_utc - open_date).days pair = trade.pair + if not self.should_enter_trade(pair): + return None + pct_first = 0 if self.pairs[pair]['first_buy']: pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) @@ -950,10 +957,12 @@ class Zeus_8_3_2_B_4_2(IStrategy): if (len(dataframe) < 1): print("skip dataframe") return None - if self.dp.runmode.value in ('dry_run'): - if pair not in ('BTC/USDT', 'BTC/USDC', 'XRP/USDT', 'XRP/USDC', 'ETH/USDT', 'ETH/USDC'): - # print(f"skip pair {pair}") - return None + + # if self.dp.runmode.value in ('dry_run'): + # if pair not in ('BTC/USDT', 'BTC/USDC', 'XRP/USDT', 'XRP/USDC', 'ETH/USDT', 'ETH/USDC', 'SOL/USDT', 'SOL/USDT'): + # # print(f"skip pair {pair}") + # return None + # else: # if pair not in ('BTC/USDT', 'BTC/USDC'): # btc_count = self.pairs['BTC/USDT']['count_of_buys'] + self.pairs['BTC/USDC']['count_of_buys'] @@ -1166,6 +1175,8 @@ class Zeus_8_3_2_B_4_2(IStrategy): def adjust_stake_amount(self, pair: str, last_candle: DataFrame): # Calculer le minimum des 14 derniers jours base_stake_amount = self.config.get('stake_amount') # Montant de base configuré + if not pair.startswith('BTC'): + base_stake_amount = base_stake_amount * 0.75 first_price = self.pairs[pair]['first_buy'] if (first_price == 0): @@ -1371,50 +1382,50 @@ class Zeus_8_3_2_B_4_2(IStrategy): return numeric_matrice[row_idx, col_idx] - # @property - # def protections(self): - # return [ - # { - # "method": "CooldownPeriod", - # "stop_duration_candles": 12 - # } - # # { - # # "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": "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 - # # } - # ] + @property + def protections(self): + return [ + { + "method": "CooldownPeriod", + "stop_duration_candles": 12 + } + # { + # "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": "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 conditional_smoothing(self, series, threshold=0.002): smoothed = [series.iloc[0]] @@ -1696,4 +1707,41 @@ class Zeus_8_3_2_B_4_2(IStrategy): # Résultat print("Moyenne des valeurs par double-tranche :") - print(pivot_mean.round(2)) \ No newline at end of file + print(pivot_mean.round(2)) + + def should_enter_trade(self, pair: str) -> bool: + + limit = 3 + + if pair.startswith('BTC'): + return True # BTC toujours autorisé + + # Filtrer les paires non-BTC + non_btc_pairs = [p for p in self.pairs if not p.startswith('BTC')] + + # Compter les positions actives sur les paires non-BTC + has_more_than_3 = False + total_non_btc = 0 + for p in non_btc_pairs: + nb_trades = self.pairs[p]['count_of_buys'] + if nb_trades > 0: + if nb_trades > limit and pair != p: + has_more_than_3 = True + total_non_btc += nb_trades + + this_pair_count = self.pairs[p]['count_of_buys'] + + if total_non_btc >= 12: + # print("total_non_btc > 10") + return False + + if this_pair_count >= limit: + # Si une autre paire non-BTC a aussi >3 trades, blocage + # for other_pair, count in pair_counts.items(): + # if other_pair != pair and count >= 3: + # return False + if not has_more_than_3: + print(f"{pair} Cette paire est la seule avec >=3 / {this_pair_count}") + return not has_more_than_3 + else: + return True