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

27
FrictradeLearning.json Normal file
View File

@@ -0,0 +1,27 @@
{
"strategy_name": "FrictradeLearning",
"params": {
"roi": {
"0": 10
},
"stoploss": {
"stoploss": -1.0
},
"trailing": {
"trailing_stop": false,
"trailing_stop_positive": 0.15,
"trailing_stop_positive_offset": 1,
"trailing_only_offset_is_reached": true
},
"max_open_trades": {
"max_open_trades": 80
},
"protection": {
"allow_decrease_rate": 0.8,
"first_adjust_param": 0.004,
"max_steps": 15
}
},
"ft_stratparam_v": 1,
"export_time": "2025-12-07 21:51:14.946942+00:00"
}

View File

@@ -120,7 +120,11 @@ class FrictradeLearning(IStrategy):
-18: 0.30, -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: # ROI table:
minimal_roi = { minimal_roi = {
@@ -139,8 +143,6 @@ class FrictradeLearning(IStrategy):
# Buy hypers # Buy hypers
timeframe = '1m' timeframe = '1m'
max_open_trades = 5
max_amount = 40
parameters = {} parameters = {}
# DCA config # DCA config
@@ -252,12 +254,18 @@ class FrictradeLearning(IStrategy):
# d = n / (p * (p - 1)) # incrément # d = n / (p * (p - 1)) # incrément
# return [round(a + i * d, 3) for i in range(p)] # return [round(a + i * d, 3) for i in range(p)]
def progressive_parts(total, n, first): def progressive_parts(total, n, first):
# solve for r
# S = first * (r^n - 1)/(r - 1) = total # conditions impossibles → on évite le solveur
# numeric solving if total <= 0 or first <= 0 or n <= 1:
return [0] * n
f = lambda r: first * (r ** n - 1) / (r - 1) - total 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)] parts = [round(first * (r ** k), 4) for k in range(n)]
return parts return parts
@@ -272,9 +280,9 @@ class FrictradeLearning(IStrategy):
steps = self.approx_value(last_candle['mid'], self.pairs[pair]['last_ath']) steps = self.approx_value(last_candle['mid'], self.pairs[pair]['last_ath'])
self.pairs[pair]['dca_thresholds'] = progressive_parts( self.pairs[pair]['dca_thresholds'] = progressive_parts(
(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, 0.003) 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))) / last_candle['mid']}") 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']) print(self.pairs[pair]['dca_thresholds'])
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float,
@@ -850,8 +858,8 @@ class FrictradeLearning(IStrategy):
# #
# for val in range(90000, 130000, 10000): # for val in range(90000, 130000, 10000):
# steps = self.approx_value(val, 126000) # steps = self.approx_value(val, 126000)
# print(f"val={val} steps={steps} pct={(val - (126000 * (1 - self.allow_decrease_rate))) / val}") # 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))) / 126000, steps) # dca = split_ratio_one_third((val - (126000 * (1 - self.allow_decrease_rate.value))) / 126000, steps)
# print(dca) # print(dca)
return dataframe return dataframe
@@ -1033,9 +1041,9 @@ class FrictradeLearning(IStrategy):
# return adjusted_stake_amount # return adjusted_stake_amount
def approx_value(self, x, X_max): 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_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 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 b = Y_min - a * X_min # 1 (0,000772595 × 75718,8) = 38
y = a * x + b # 0,000772595 * 115000 - 38 y = a * x + b # 0,000772595 * 115000 - 38
@@ -1112,7 +1120,9 @@ class FrictradeLearning(IStrategy):
if self.pairs[pair]['first_buy']: if self.pairs[pair]['first_buy']:
pct_first = self.getPctFirstBuy(pair, last_candle) 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 stake_amount = trade.stake_amount
self.pairs[pair]['previous_profit'] = profit self.pairs[pair]['previous_profit'] = profit
trade_type = "Sell " + (last_candle['enter_tag'] if last_candle['enter_long'] == 1 else '') 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 # last_fill_price = buy_orders[-1].price
# baisse relative # baisse relative
if minutes % 60 == 0: # if minutes % 60 == 0:
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle)) # ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
self.pairs[pair]['last_ath'] = ath # self.pairs[pair]['last_ath'] = ath
else: # else:
ath = self.pairs[pair]['last_ath'] # ath = self.pairs[pair]['last_ath']
# steps = self.approx_value(last_candle['mid'], 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: if len(self.pairs[pair]['dca_thresholds']) == 0:
self.calculateStepsDcaThresholds(last_candle, pair) self.calculateStepsDcaThresholds(last_candle, pair)
dca_threshold = self.pairs[pair]['dca_thresholds'][min(count_of_buys - 1, len(self.pairs[pair]['dca_thresholds']) - 1)] 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 decline = (last_fill_price - current_rate) / last_fill_price
increase = - decline increase = - decline
@@ -1209,13 +1219,10 @@ class FrictradeLearning(IStrategy):
# return None # return None
# FIN ########################## ALGO ATH # 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 \ condition = last_candle['percent'] > 0 and last_candle['sma24_deriv1'] > 0 \
and last_candle['close'] < self.pairs[pair]['first_buy'] 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): if ((force or decline >= dca_threshold) and condition):
try: try:
if self.pairs[pair]['has_gain'] and profit > 0: if self.pairs[pair]['has_gain'] and profit > 0:
@@ -1224,6 +1231,9 @@ class FrictradeLearning(IStrategy):
return None return None
stake_amount = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle)) 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}") # print(f"profit={profit} previous={self.pairs[pair]['previous_profit']} count_of_buys={trade.nr_of_successful_entries}")
if stake_amount > 0: if stake_amount > 0:
self.pairs[pair]['previous_profit'] = profit 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 ? ----- # ----- 4) OFFSET : faut-il attendre de dépasser trailing_stop_positive_offset ? -----
if current_trailing_only_offset_is_reached: if current_trailing_only_offset_is_reached:
# Max profit pas atteint ET perte < 2 * current_trailing_stop_positive # 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)} " 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']))}") f"{min(2, current_trailing_stop_positive_offset * (count_of_buys - self.pairs[pair]['has_gain']))}")
return None # ne pas activer le trailing encore return None # ne pas activer le trailing encore
@@ -1514,8 +1524,6 @@ class FrictradeLearning(IStrategy):
return dataframe return dataframe
import pandas as pd
def to_utc_ts(self, x): def to_utc_ts(self, x):
return pd.to_datetime(x, utc=True) return pd.to_datetime(x, utc=True)