From 3cac030f10df7970bb8fb5ebf0084f4e5ff2bb3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Sun, 7 Dec 2025 19:13:55 +0100 Subject: [PATCH] Frictrade progression adjust exponentielle / correction trailing --- FrictradeLearning.py | 62 ++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/FrictradeLearning.py b/FrictradeLearning.py index 5902809..21777ad 100644 --- a/FrictradeLearning.py +++ b/FrictradeLearning.py @@ -27,6 +27,7 @@ import ta import talib.abstract as talib import freqtrade.vendor.qtpylib.indicators as qtpylib from datetime import timezone, timedelta +import mpmath as mp # Machine Learning from sklearn.ensemble import RandomForestClassifier,RandomForestRegressor @@ -133,7 +134,7 @@ class FrictradeLearning(IStrategy): trailing_stop = False trailing_stop_positive = 0.15 - trailing_stop_positive_offset = 0.5 + trailing_stop_positive_offset = 1 trailing_only_offset_is_reached = True # Buy hypers @@ -246,19 +247,33 @@ class FrictradeLearning(IStrategy): return allow_to_buy def calculateStepsDcaThresholds(self, last_candle, pair): - def split_ratio_one_third(n, p): - a = n / (2 * p) # première valeur - d = n / (p * (p - 1)) # incrément - return [round(a + i * d, 3) for i in range(p)] + # def split_ratio_one_third(n, p): + # a = n / (2 * p) # première valeur + # d = n / (p * (p - 1)) # incrément + # return [round(a + i * d, 3) for i in range(p)] + def progressive_parts(total, n, first): + # solve for r + # S = first * (r^n - 1)/(r - 1) = total + # numeric solving + + f = lambda r: first * (r ** n - 1) / (r - 1) - total + r = mp.findroot(f, 1.05) # initial guess + + parts = [round(first * (r ** k), 4) for k in range(n)] + return parts + + # r, parts = progressive_parts(0.4, 40, 0.004) + # print("r =", r) + # print(parts) if self.pairs[pair]['last_ath'] == 0 : ath = max(last_candle['mid'], self.get_last_ath_before_candle(last_candle)) self.pairs[pair]['last_ath'] = ath steps = self.approx_value(last_candle['mid'], self.pairs[pair]['last_ath']) - self.pairs[pair]['dca_thresholds'] = split_ratio_one_third( + self.pairs[pair]['dca_thresholds'] = progressive_parts( (last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate))) / last_candle['mid'], - steps) + steps, 0.003) print(f"val={last_candle['mid']} steps={steps} pct={(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate))) / last_candle['mid']}") print(self.pairs[pair]['dca_thresholds']) @@ -895,9 +910,11 @@ class FrictradeLearning(IStrategy): # Buy = prediction > threshold dataframe["buy"] = 0 dataframe.loc[ - (dataframe["ml_prob"].shift(3) < 0.2) - & (dataframe['low'].shift(3) < dataframe['min180'].shift(3)) - & (dataframe['min180'].shift(3) == dataframe['min180']), + (dataframe["ml_prob"].shift(1) < dataframe["ml_prob"]) + & (dataframe['sma24_deriv1'] > 0) + & (dataframe['sma12_deriv1'] > 0) + & (dataframe['open'] < dataframe['max180'] * 0.997), + # & (dataframe['min180'].shift(3) == dataframe['min180']), ['enter_long', 'enter_tag'] ] = (1, f"future") dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.003, np.nan) @@ -1310,6 +1327,8 @@ class FrictradeLearning(IStrategy): # if current_profit > 0: # print(f"profit={profit} max_profit={max_profit} current_profit={current_profit}") + if profit < 0: + return None baisse = 0 if profit > 0: @@ -1318,11 +1337,11 @@ class FrictradeLearning(IStrategy): self.pairs[pair]['count_of_buys'] = count_of_buys self.pairs[pair]['current_profit'] = profit - dispo = round(self.wallets.get_available_stake_amount()) - hours_since_first_buy = (current_time - trade.open_date_utc).seconds / 3600.0 - days_since_first_buy = (current_time - trade.open_date_utc).days - hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0 - minutes = (current_time - trade.date_last_filled_utc).total_seconds() / 60.0 + # dispo = round(self.wallets.get_available_stake_amount()) + # hours_since_first_buy = (current_time - trade.open_date_utc).seconds / 3600.0 + # days_since_first_buy = (current_time - trade.open_date_utc).days + # hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0 + # minutes = (current_time - trade.date_last_filled_utc).total_seconds() / 60.0 # ----- 2) Mise à jour du max_price ----- self.pairs[pair]['max_touch'] = max(last_candle['close'], self.pairs[pair]['max_touch']) @@ -1383,14 +1402,23 @@ class FrictradeLearning(IStrategy): # ----- 4) OFFSET : faut-il attendre de dépasser trailing_stop_positive_offset ? ----- if current_trailing_only_offset_is_reached: # Max profit pas atteint ET perte < 2 * current_trailing_stop_positive - if max_profit < min(2, current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain']))\ - and (max_profit > current_trailing_stop_positive_offset): #2 * current_trailing_stop_positive: + if max_profit < min(2, max_profit * current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain'])): #2 * current_trailing_stop_positive: + print(f"{current_time} trailing non atteint trailing_stop={round(trailing_stop,4)} profit={round(profit, 4)} max={round(max_profit, 4)} " + f"{min(2, current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain']))}") return None # ne pas activer le trailing encore + else: + print(f"{current_time} trailing atteint trailing_stop={round(trailing_stop,4)} profit={round(profit, 4)} max={round(max_profit, 4)} " + f"{min(2, current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain']))}") + # Sinon : trailing actif dès le début # ----- 6) Condition de vente ----- if 0 < profit <= trailing_stop and last_candle['mid'] < last_candle['sma5']: self.pairs[pair]['force_buy'] = True + print( + f"{current_time} Condition de vente trailing_stop={round(trailing_stop,4)} profit={round(profit, 4)} max={round(max_profit, 4)} " + f"{round(min(2, current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain'])), 4)}") + return f"stop_{count_of_buys}_{self.pairs[pair]['has_gain']}" return None