Frictrade progression adjust exponentielle / correction trailing / Hyperopt

This commit is contained in:
Jérôme Delacotte
2025-12-07 23:44:17 +01:00
parent 3cac030f10
commit 11bb59636e
2 changed files with 66 additions and 31 deletions

View File

@@ -120,7 +120,11 @@ class FrictradeLearning(IStrategy):
-18: 0.30,
}
allow_decrease_rate = 0.4
allow_decrease_rate = DecimalParameter(0.1, 0.8, decimals=1, default=0.4, space='protection')
first_adjust_param = DecimalParameter(0.001, 0.01, decimals=3, default=0.003, space='protection')
max_steps = IntParameter(10, 50, default=40, space='protection', optimize=True, load=True)
hours_force = IntParameter(1, 48, default=24, space='buy', optimize=True, load=True)
# ROI table:
minimal_roi = {
@@ -139,8 +143,6 @@ class FrictradeLearning(IStrategy):
# Buy hypers
timeframe = '1m'
max_open_trades = 5
max_amount = 40
parameters = {}
# DCA config
@@ -252,12 +254,18 @@ class FrictradeLearning(IStrategy):
# 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
# conditions impossibles → on évite le solveur
if total <= 0 or first <= 0 or n <= 1:
return [0] * n
f = lambda r: first * (r ** n - 1) / (r - 1) - total
r = mp.findroot(f, 1.05) # initial guess
try:
r = mp.findroot(f, 1.2) # 1.2 = plus stable que 1.05
except Exception:
# fallback en cas d'échec
return [first] * n
parts = [round(first * (r ** k), 4) for k in range(n)]
return parts
@@ -272,9 +280,9 @@ class FrictradeLearning(IStrategy):
steps = self.approx_value(last_candle['mid'], self.pairs[pair]['last_ath'])
self.pairs[pair]['dca_thresholds'] = progressive_parts(
(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate))) / last_candle['mid'],
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']}")
(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate.value))) / last_candle['mid'],
steps, self.first_adjust_param.value)
print(f"val={last_candle['mid']} steps={steps} pct={(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate.value))) / last_candle['mid']}")
print(self.pairs[pair]['dca_thresholds'])
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float,
@@ -468,9 +476,9 @@ class FrictradeLearning(IStrategy):
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}"
f"{round(last_candle['max_rsi_24'], 1) or '-' :>6}|{round(last_candle['rsi_1h'], 1) or '-' :>6}|{round(last_candle['rsi_1d'], 1) or '-' :>6}|"
f"{round(last_candle['max_rsi_24'], 1) or '-':>6}|{round(last_candle['rsi_1h'], 1) or '-':>6}|{round(last_candle['rsi_1d'], 1) or '-':>6}|"
# f"{round(last_candle['rtp_1h'] * 100, 0) or '-' :>6}|{round(last_candle['rtp_1d'] * 100, 0) or '-' :>6}|"
f"{round(last_candle['ml_prob'], 1) or '-' :>6}|"
f"{round(last_candle['ml_prob'], 1) or '-':>6}|"
)
def printLineLog(self):
@@ -850,8 +858,8 @@ class FrictradeLearning(IStrategy):
#
# for val in range(90000, 130000, 10000):
# steps = self.approx_value(val, 126000)
# print(f"val={val} steps={steps} pct={(val - (126000 * (1 - self.allow_decrease_rate))) / val}")
# dca = split_ratio_one_third((val - (126000 * (1 - self.allow_decrease_rate))) / 126000, steps)
# print(f"val={val} steps={steps} pct={(val - (126000 * (1 - self.allow_decrease_rate.value))) / val}")
# dca = split_ratio_one_third((val - (126000 * (1 - self.allow_decrease_rate.value))) / 126000, steps)
# print(dca)
return dataframe
@@ -1033,9 +1041,9 @@ class FrictradeLearning(IStrategy):
# return adjusted_stake_amount
def approx_value(self, x, X_max):
X_min = X_max * (1 - self.allow_decrease_rate) # 126198 * 0.4 = 75718,8
X_min = X_max * (1 - self.allow_decrease_rate.value) # 126198 * 0.4 = 75718,8
Y_min = 1
Y_max = 40
Y_max = self.max_steps.value
a = (Y_max - Y_min) / (X_max - X_min) # 39 ÷ (126198 126198×0,6) = 0,000772595
b = Y_min - a * X_min # 1 (0,000772595 × 75718,8) = 38
y = a * x + b # 0,000772595 * 115000 - 38
@@ -1112,7 +1120,9 @@ class FrictradeLearning(IStrategy):
if self.pairs[pair]['first_buy']:
pct_first = self.getPctFirstBuy(pair, last_candle)
if profit > - self.pairs[pair]['first_amount'] and count_of_buys > 15 and last_candle['sma24_deriv1_1h'] < 0:
if profit > - self.pairs[pair]['first_amount'] \
and self.wallets.get_available_stake_amount() < self.pairs[pair]['first_amount'] \
and last_candle['sma24_deriv1_1h'] < 0:
stake_amount = trade.stake_amount
self.pairs[pair]['previous_profit'] = profit
trade_type = "Sell " + (last_candle['enter_tag'] if last_candle['enter_long'] == 1 else '')
@@ -1155,21 +1165,21 @@ class FrictradeLearning(IStrategy):
# last_fill_price = buy_orders[-1].price
# baisse relative
if minutes % 60 == 0:
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
self.pairs[pair]['last_ath'] = ath
else:
ath = self.pairs[pair]['last_ath']
# if minutes % 60 == 0:
# ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
# self.pairs[pair]['last_ath'] = ath
# else:
# ath = self.pairs[pair]['last_ath']
# steps = self.approx_value(last_candle['mid'], ath)
# dca_thresholds = split_ratio_one_third((last_candle['mid'] - (ath * self.allow_decrease_rate)) / last_candle['mid'], steps) #((last_candle['mid'] - (ath * self.allow_decrease_rate)) / steps) / last_candle['mid'] # 0.0025 + 0.0005 * count_of_buys
# dca_thresholds = split_ratio_one_third((last_candle['mid'] - (ath * self.allow_decrease_rate.value)) / last_candle['mid'], steps) #((last_candle['mid'] - (ath * self.allow_decrease_rate.value)) / steps) / last_candle['mid'] # 0.0025 + 0.0005 * count_of_buys
if len(self.pairs[pair]['dca_thresholds']) == 0:
self.calculateStepsDcaThresholds(last_candle, pair)
dca_threshold = self.pairs[pair]['dca_thresholds'][min(count_of_buys - 1, len(self.pairs[pair]['dca_thresholds']) - 1)]
# print(f"{count_of_buys} {ath * (1 - self.allow_decrease_rate)} {round(last_candle['mid'], 2)} {round((last_candle['mid'] - (ath * self.allow_decrease_rate)) / last_candle['mid'], 2)} {steps} {round(dca_threshold, 4)}")
# print(f"{count_of_buys} {ath * (1 - self.allow_decrease_rate.value)} {round(last_candle['mid'], 2)} {round((last_candle['mid'] - (ath * self.allow_decrease_rate.value)) / last_candle['mid'], 2)} {steps} {round(dca_threshold, 4)}")
decline = (last_fill_price - current_rate) / last_fill_price
increase = - decline
@@ -1209,13 +1219,10 @@ class FrictradeLearning(IStrategy):
# return None
# FIN ########################## ALGO ATH
force = hours > 24 and last_candle['sma60_deriv1_1h'] > 0
force = hours > self.hours_force.value and last_candle['sma60_deriv1_1h'] > 0
condition = last_candle['percent'] > 0 and last_candle['sma24_deriv1'] > 0 \
and last_candle['close'] < self.pairs[pair]['first_buy']
# and last_candle['ml_prob'] > 0.65
limit_buy = 40
# or (last_candle['close'] <= last_candle['min180'] and hours > 3)
if ((force or decline >= dca_threshold) and condition):
try:
if self.pairs[pair]['has_gain'] and profit > 0:
@@ -1224,6 +1231,9 @@ class FrictradeLearning(IStrategy):
return None
stake_amount = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle))
if force:
stake_amount = stake_amount / 4
# print(f"profit={profit} previous={self.pairs[pair]['previous_profit']} count_of_buys={trade.nr_of_successful_entries}")
if stake_amount > 0:
self.pairs[pair]['previous_profit'] = profit
@@ -1402,7 +1412,7 @@ 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, max_profit * current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain'])): #2 * current_trailing_stop_positive:
if profit > 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
@@ -1514,8 +1524,6 @@ class FrictradeLearning(IStrategy):
return dataframe
import pandas as pd
def to_utc_ts(self, x):
return pd.to_datetime(x, utc=True)