From 91bf3ca8ae29ec4b2354274b892003a1b3191e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Tue, 24 Feb 2026 13:36:48 +0100 Subject: [PATCH] Empty logtrade --- Empty.py | 262 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 192 insertions(+), 70 deletions(-) diff --git a/Empty.py b/Empty.py index bc27980..ac19320 100644 --- a/Empty.py +++ b/Empty.py @@ -22,11 +22,21 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib from functools import reduce from random import shuffle +import logging +logger = logging.getLogger(__name__) + +# Couleurs ANSI de base +RED = "\033[31m" +GREEN = "\033[32m" +YELLOW = "\033[33m" +BLUE = "\033[34m" +MAGENTA = "\033[35m" +CYAN = "\033[36m" +RESET = "\033[0m" timeperiods = [3, 5, 12, 24, 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}') @@ -36,10 +46,6 @@ 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") @@ -48,7 +54,6 @@ for timeperiod in timeperiods: # god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_up") # god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_down") -print(stop_buying_indicators) operators = [ "D", # Disabled gene @@ -283,6 +288,7 @@ class Empty(IStrategy): # Number of candles the strategy requires before producing valid signals startup_candle_count: int = 30 + columns_logged = False pairs = { pair: { @@ -388,8 +394,6 @@ class Empty(IStrategy): drop_from_last_entry = DecimalParameter(-0.1, 0, decimals=2, default=-0.025, space='protection') range_pos_stoploss = DecimalParameter(0, 0.1, decimals=2, default=0.05, space='protection') stoploss_force = DecimalParameter(-0.2, 0, decimals=2, default=-0.05, space='protection') - stoploss_indicator = CategoricalParameter(god_genes_with_timeperiod, default="stop_buying12_1d", space='protection') - stop_buying_indicator = CategoricalParameter(stop_buying_indicators, default="stop_buying12_1d", space='protection') # stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection') @@ -478,12 +482,31 @@ 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[self.stop_buying_indicator.value] == False or (last_candle['range_pos'] < 0))\ + and (last_candle['range_pos'] < 0)\ and last_candle['hapercent'] > 0: # stake_amount = trade.stake_amount self.pairs[trade.pair]['last_buy'] = current_rate - print(f"adjust {current_time} {stake_amount}") - print(f"adjust {pair} {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' + self.pairs[trade.pair]['count_of_buys'] += 1 + self.pairs[pair]['total_amount'] += stake_amount + 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(profit, 1), + 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 return None @@ -539,27 +562,26 @@ class Empty(IStrategy): self.pairs[pair]['last_min'] = min(last_candle['close'], self.pairs[pair]['last_min']) self.pairs[pair]['last_date'] = current_time - dispo = round(self.wallets.get_available_stake_amount()) # self.printLineLog() stake_amount = self.adjust_stake_amount(pair, last_candle) self.pairs[pair]['first_amount'] = stake_amount self.pairs[pair]['total_amount'] = stake_amount - print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={stake_amount} rate={rate} rate={rate}") + # print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={stake_amount} rate={rate} rate={rate}") - # self.log_trade( - # last_candle=last_candle, - # date=current_time, - # action=("🟩Buy" if allow_to_buy else "Canceled") + " " + str(minutes), - # pair=pair, - # rate=rate, - # dispo=dispo, - # profit=0, - # trade_type=entry_tag, - # buys=1, - # stake=round(stake_amount, 2) - # ) + self.log_trade( + last_candle=last_candle, + date=current_time, + action=("🟩Buy" if allow_to_buy else "Canceled") + " " + str(minutes), + pair=pair, + rate=rate, + dispo=dispo, + profit=0, + trade_type=entry_tag, + buys=1, + stake=round(stake_amount, 2) + ) return allow_to_buy @@ -584,17 +606,17 @@ class Empty(IStrategy): profit = trade.calc_profit(rate) self.pairs[pair]['previous_profit'] = profit dispo = round(self.wallets.get_available_stake_amount()) - print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} rate={rate} open_rate={trade.open_rate} profit={profit}") - # self.log_trade( - # last_candle=last_candle, - # date=current_time, - # action="🟥Sell " + str(minutes), - # pair=pair, - # trade_type=exit_reason, - # rate=last_candle['close'], - # dispo=dispo, - # profit=round(profit, 2) - # ) + # print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} rate={rate} open_rate={trade.open_rate} profit={profit}") + self.log_trade( + last_candle=last_candle, + date=current_time, + action="🟥Sell " + str(minutes), + pair=pair, + trade_type=exit_reason, + rate=last_candle['close'], + dispo=dispo, + profit=round(profit, 2) + ) self.pairs[pair]['first_amount'] = 0 self.pairs[pair]['force_sell'] = False self.pairs[pair]['has_gain'] = 0 @@ -618,6 +640,11 @@ class Empty(IStrategy): self.pairs[pair]['current_trade'] = trade momentum = last_candle[self.sell_score_indicator.value] + # 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' # Si momentum fort → on laisse courir if momentum > 1: return None @@ -637,10 +664,11 @@ class Empty(IStrategy): candle_at_buy = self.pairs[pair]['last_candle'] - 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 + # if profit < - 100 : + # print("stop loss detected") + # self.pairs[pair]['force_sell'] = True + # return 0 - # # 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"] @@ -682,7 +710,7 @@ class Empty(IStrategy): dataframe['haclose'] = heikinashi['close'] dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] dataframe['mid'] = dataframe['haopen'] + (dataframe['haclose'] - dataframe['haopen']) / 2 - dataframe['zero'] = 0; + dataframe['zero'] = 0 for timeperiod in timeperiods: dataframe[f'max{timeperiod}'] = talib.MAX(dataframe['close'], timeperiod=timeperiod) @@ -691,19 +719,6 @@ class Empty(IStrategy): dataframe[f"sma{timeperiod}"] = dataframe['mid'].ewm(span=timeperiod, adjust=False).mean() self.calculeDerivees(dataframe, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod) - dataframe[f'stop_buying{timeperiod}_deb'] = (dataframe[f'sma{timeperiod}_trend_change_down'] == 1) - dataframe[f'stop_buying{timeperiod}_end'] = (dataframe[f'sma{timeperiod}_trend_change_up'] == 1) - latched = np.zeros(len(dataframe), dtype=bool) - - for i in range(1, len(dataframe)): - if dataframe[f'stop_buying{timeperiod}_deb'].iloc[i]: - latched[i] = True - elif dataframe[f'stop_buying{timeperiod}_end'].iloc[i]: - latched[i] = False - else: - latched[i] = latched[i - 1] - dataframe[f'stop_buying{timeperiod}'] = latched - # ###################################################################################################### ################### INFORMATIVE 1d informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") @@ -721,34 +736,23 @@ class Empty(IStrategy): informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean() self.calculeDerivees(informative, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod) - informative[f'stop_buying_deb{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_down'] == 1) - informative[f'stop_buying_end{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_up'] == 1) - latched = np.zeros(len(informative), dtype=bool) - - for i in range(1, len(informative)): - if informative[f'stop_buying_deb{timeperiod}'].iloc[i]: - latched[i] = True - elif informative[f'stop_buying_end{timeperiod}'].iloc[i]: - latched[i] = False - else: - latched[i] = latched[i - 1] - informative[f'stop_buying{timeperiod}'] = latched dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) # ###################################################################################################### - range_min = dataframe[f"min12_1d"] + range_min = dataframe[f"min24_1d"] range_max = dataframe[f"max48"] dataframe[f"range_pos"] = ((dataframe['mid'] - range_min) / (range_max)).rolling(5).mean() + dataframe[f'stop_buying'] = qtpylib.crossed_below(dataframe[f"sma12"], dataframe['sma48']) # récupérer le dernier trade fermé trades = Trade.get_trades_proxy(pair=pair,is_open=False) if trades: last_trade = trades[-1] self.pairs[pair]['last_profit'] = last_trade.close_profit # ex: 0.12 = +12% - self.pairs[pair]['last_trade'] = last_trade + self.pairs[pair]['last_trade'] = last_trade return dataframe @@ -806,11 +810,11 @@ class Empty(IStrategy): # buy_real_num # ) # 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['hapercent'] > 0) # # conditions.append(dataframe[f"range_pos"] <= 0.5) - # conditions.append((dataframe[f"range_pos"] < 0.01) | ((dataframe[f"sma5_deriv1"] > 0) & (dataframe[f"sma12_deriv1"] > 0) & (dataframe[f"sma24_deriv1"] > 0))) + 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" @@ -993,6 +997,109 @@ class Empty(IStrategy): # } ] + 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' or self.dp.runmode.value in ('hyperopt'): + return + if self.columns_logged % 10 == 0: + self.printLog( + f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} |{'Rate':>8} | {'Dispo':>6} | {'Profit':>8} " + f"| {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>7}| {'last_max':>7}|{'Buys':>5}| {'Stake':>5} |" + f"{'rsi':>6}|Distmax|s201d|s5_1d|s5_2d|s51h|s52h|smt1h|smt2h|tdc1d|tdc1h" + ) + self.printLineLog() + df = pd.DataFrame.from_dict(self.pairs, orient='index') + colonnes_a_exclure = ['last_candle', + 'trade_info', 'last_date', 'last_count_of_buys', 'base_stake_amount', 'stop_buy'] + df_filtered = df[df['count_of_buys'] > 0].drop(columns=colonnes_a_exclure) + # df_filtered = df_filtered["first_buy", "last_max", "max_touch", "last_sell","last_buy", 'count_of_buys', 'current_profit'] + + print(df_filtered) + + 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 = self.getLastLost(last_candle, pair) + + if buys is None: + buys = '' + + max_touch = '' # round(last_candle['max12_1d'], 1) #round(self.pairs[pair]['max_touch'], 1) + pct_max = self.getPctFirstBuy(pair, last_candle) + + total_counts = str(buys) + '/' + str(sum(pair_data['count_of_buys'] for pair_data in self.pairs.values())) + + dist_max = self.getDistMax(last_candle, pair) + + # 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_deriv1_1d'])) + # trade_type = trade_type \ + # + " " + string \ + # + " " + str(int(last_candle['rsi_1h'])) \ + # + " " + str(int(last_candle['rsi_deriv1_1h'])) + + # val144 = self.getProbaHausse144(last_candle) + # val1h = self.getProbaHausse1h(last_candle) + + color = GREEN if profit > 0 else RED + # color_sma24 = GREEN if last_candle['sma24_deriv1_1d'] > 0 else RED + # color_sma24_2 = GREEN if last_candle['sma24_deriv2_1d'] > 0 else RED + # color_sma5 = GREEN if last_candle['mid_smooth_5_deriv1_1d'] > 0 else RED + # color_sma5_2 = GREEN if last_candle['mid_smooth_5_deriv2_1d'] > 0 else RED + # color_sma5_1h = GREEN if last_candle['sma60_deriv1'] > 0 else RED + # color_sma5_2h = GREEN if last_candle['sma60_deriv2'] > 0 else RED + # color_smooth_1h = GREEN if last_candle['mid_smooth_1h_deriv1'] > 0 else RED + # color_smooth2_1h = GREEN if last_candle['mid_smooth_1h_deriv2'] > 0 else RED + + last_max = int(self.pairs[pair]['last_max']) if self.pairs[pair]['last_max'] > 1 else round( + self.pairs[pair]['last_max'], 3) + last_min = int(self.pairs[pair]['last_min']) if self.pairs[pair]['last_min'] > 1 else round( + self.pairs[pair]['last_min'], 3) + + profit = str(profit) + '/' + str(round(self.pairs[pair]['max_profit'], 2)) + + # 🟢 Dérivée 1 > 0 et dérivée 2 > 0: tendance haussière qui s’accélère. + # 🟡 Dérivée 1 > 0 et dérivée 2 < 0: tendance haussière qui ralentit → essoufflement potentiel. + # 🔴 Dérivée 1 < 0 et dérivée 2 < 0: tendance baissière qui s’accélère. + # 🟠 Dérivée 1 < 0 et dérivée 2 > 0: tendance baissière qui ralentit → possible bottom. + + self.printLog( + f"| {date:<16} |{action:<10} | {pair[0:3]:<3} | {trade_type or '-':<18} |{rate or '-':>9}| {dispo or '-':>6} " + f"|{color}{profit or '-':>10}{RESET}| {pct_max or '-':>6} | {round(self.pairs[pair]['max_touch'], 2) or '-':>11} | {last_lost or '-':>12} " + f"| {last_max or '-':>7} | {last_min or '-':>7} |{total_counts or '-':>5}|{stake or '-':>7}" + ) + + def printLineLog(self): + # f"sum1h|sum1d|Tdc|Tdh|Tdd| drv1 |drv_1h|drv_1d|" + self.printLog( + f"+{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 12}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}{'-' * 9}+{'-' * 5}+{'-' * 7}+" + f"+{'-' * 6}+{'-' * 7}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+{'-' * 5}+" + ) + def printLog(self, str): if self.config.get('runmode') == 'hyperopt' or self.dp.runmode.value in ('hyperopt'): return; @@ -1000,4 +1107,19 @@ class Empty(IStrategy): logger.info(str) else: if not self.dp.runmode.value in ('hyperopt'): - print(str) \ No newline at end of file + print(str) + + def getLastLost(self, last_candle, pair): + last_lost = round((last_candle['close'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3) + return last_lost + + def getDistMax(self, last_candle, pair): + mx = last_candle['max12_1d'] + dist_max = round(100 * (mx - last_candle['close']) / mx, 0) + return dist_max + + def getPctFirstBuy(self, pair, last_candle): + return round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) + + def getPctLastBuy(self, pair, last_candle): + return round((last_candle['close'] - self.pairs[pair]['last_buy']) / self.pairs[pair]['last_buy'], 4)