TEST HYPEROPTS

This commit is contained in:
Jérôme Delacotte
2026-03-07 15:36:28 +01:00
parent 5ce48130f4
commit 2885cf05b1
5 changed files with 1547 additions and 125 deletions

View File

@@ -852,28 +852,28 @@ class FrictradeLearning(IStrategy):
short_pair = self.getShortName(pair)
# path=f"user_data/strategies/plots/{short_pair}/"
self.model = joblib.load(f"{self.path}/{short_pair}_rf_model.pkl")
# Préparer les features pour la prédiction
features = dataframe[self.model_indicators].fillna(0)
# Prédiction : probabilité que le prix monte
# Affichage des colonnes intérressantes dans le model
features_pruned, kept_features = self.prune_features(
model=self.model,
dataframe=dataframe,
feature_columns=self.model_indicators,
importance_threshold=0.005 # enlever features < % importance
)
probs = self.model.predict_proba(features)[:, 1]
# Sauvegarder la probabilité pour lanalyse
dataframe['ml_prob'] = probs
if False and self.dp.runmode.value in ('backtest'):
self.inspect_model(self.model)
# self.model = joblib.load(f"{self.path}/{short_pair}_rf_model.pkl")
#
# # Préparer les features pour la prédiction
# features = dataframe[self.model_indicators].fillna(0)
#
# # Prédiction : probabilité que le prix monte
#
# # Affichage des colonnes intérressantes dans le model
# features_pruned, kept_features = self.prune_features(
# model=self.model,
# dataframe=dataframe,
# feature_columns=self.model_indicators,
# importance_threshold=0.005 # enlever features < % importance
# )
#
# probs = self.model.predict_proba(features)[:, 1]
#
# # Sauvegarder la probabilité pour lanalyse
# dataframe['ml_prob'] = probs
#
# if False and self.dp.runmode.value in ('backtest'):
# self.inspect_model(self.model)
#
# absolute_min = dataframe['absolute_min'].min()
@@ -910,6 +910,9 @@ class FrictradeLearning(IStrategy):
horizon = 180
self.calculateScores(dataframe, horizon)
dataframe['cross_sma60'] = qtpylib.crossed_below(dataframe["sma12"], dataframe['sma60'])
# val = 90000
# steps = 12
# [0.018, 0.022, 0.025, 0.028, 0.032, 0.035, 0.038, 0.042, 0.045, 0.048, 0.052, 0.055]
@@ -1066,22 +1069,34 @@ class FrictradeLearning(IStrategy):
# threshold = 0.4 #self.buy_threshold # ex: 0.80 or 1.10 depending on your model
# 20% des signaux les plus forts
threshold = np.percentile(dataframe["ml_prob"], 80)
# threshold = np.percentile(dataframe["ml_prob"], 80)
# Buy = prediction > threshold
dataframe["buy"] = 0
# dataframe.loc[
# # (dataframe["ml_prob"].shift(1) < dataframe["ml_prob"])
# (dataframe['sma60_deriv1'] > -0.0000)
# & (dataframe['sma12_deriv1'] > 0)
# & (dataframe['sma12'] < dataframe['sma60'])
# # & (dataframe['rsi'] < 77)
# # & (dataframe['heat_score_1h'] < 0.5)
# # & (dataframe['sma180_deriv1'] > 0)
# # & (dataframe['open'] < dataframe['max180'] * 0.997)
# # & (dataframe['min180'].shift(3) == dataframe['min180'])
# , ['enter_long', 'enter_tag']
# ] = (1, f"future")
dataframe.loc[
(dataframe["ml_prob"].shift(1) < dataframe["ml_prob"])
& (dataframe['sma24_deriv1'] > 0)
& (dataframe['sma5_deriv1'] > 0)
& (dataframe['sma5_deriv2'] > 0)
& (dataframe['rsi'] < 77)
& (dataframe['heat_score_1h'] < 0.5)
# & (dataframe['sma180_deriv1'] > 0)
# & (dataframe['open'] < dataframe['max180'] * 0.997)
# & (dataframe['min180'].shift(3) == dataframe['min180'])
# (dataframe["ml_prob"].shift(1) < dataframe["ml_prob"])
(
(dataframe['close'].shift(3) < dataframe['min180'].shift(3)) |
(dataframe['close'].shift(4) < dataframe['min180'].shift(4)) |
(dataframe['close'].shift(5) < dataframe['min180'].shift(5))
)
& (dataframe['hapercent'] > 0)
, ['enter_long', 'enter_tag']
] = (1, f"future")
] = (1, f"min180")
dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.01, np.nan)
return dataframe
@@ -1210,18 +1225,14 @@ class FrictradeLearning(IStrategy):
return max(round(y), 1) # évite les valeurs négatives
def adjust_stake_amount(self, pair: str, last_candle: DataFrame):
if self.pairs[pair]['first_amount'] > 0:
mises = self.pairs[pair]['mises']
count = self.pairs[pair]['count_of_buys'] - self.pairs[pair]['has_gain']
return mises[count] if count < len(mises) else self.pairs[pair]['first_amount']
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
full, mises, steps = self.calculateMises(pair, ath, last_candle['mid'])
base_stake = mises[self.pairs[pair]['count_of_buys']] if self.pairs[pair]['count_of_buys'] < len(
mises) else full / (steps * 2)
return base_stake
if (self.pairs[pair]['first_amount'] > 0):
amount = min(self.wallets.get_available_stake_amount(), self.pairs[pair]['first_amount'])
else:
if last_candle['enter_tag'] in ['fall', 'bear', 'Force', 'Range-']:
amount = self.wallets.get_available_stake_amount() / 5
else:
amount = self.wallets.get_available_stake_amount() / 3# / (2 * self.pairs[pair]['count_of_lost'] + 1)
return min(amount, self.wallets.get_available_stake_amount())
def calculateMises(self, pair, ath, val):
# ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
@@ -1515,8 +1526,19 @@ class FrictradeLearning(IStrategy):
# buys=count_of_buys,
# stake=0
# )
if profit < 0.65: #5 or last_candle['rsi_1d'] < 30:
return None
if current_profit < - 0.02 and last_candle[f"close"] <= last_candle['sma60']:
self.pairs[pair]['force_sell'] = True
return 'sma60'
if profit > 5 and \
(baisse > 0.25 and last_candle[f"close"] <= last_candle['sma24']) \
and last_candle['hapercent'] <0 :
self.pairs[pair]['force_sell'] = True
return 'B30'
if profit > 0 and last_candle['cross_sma60']: #5 or last_candle['rsi_1d'] < 30:
return 'Cross'
if last_candle['max_rsi_24'] > 88 and last_candle['hapercent'] < 0\
and last_candle['sma5_deriv2'] < -0.1:
@@ -1535,44 +1557,48 @@ class FrictradeLearning(IStrategy):
# if (minutes > 1440 and last_candle['sma60_deriv1'] > 0) :
# return None
# ----- 4) OFFSET : faut-il attendre de dépasser trailing_stop_positive_offset ? -----
if current_trailing_only_offset_is_reached and max_profit > current_trailing_stop_positive_offset:
# Max profit pas atteint ET perte < 2 * current_trailing_stop_positive
if profit > limit: # 2 * current_trailing_stop_positive:
print(
f"{current_time} trailing non atteint trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} "
f"max={round(max_profit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} baisse={round(baisse,2)}")
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)} "
f"max={round(max_profit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} baisse={round(baisse,2)}")
else:
# print(
# f"1 - {current_time} trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} max={round(max_profit, 4)} "
# f"limit={round(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)}"
# f" baisse={round(baisse,2)} {round(last_candle['sma180_deriv1'], 4)} {round(last_candle['sma60_deriv1'], 4)} {round(last_candle['sma24_deriv1'], 4)}")
# # ----- 4) OFFSET : faut-il attendre de dépasser trailing_stop_positive_offset ? -----
# if current_trailing_only_offset_is_reached and max_profit > current_trailing_stop_positive_offset:
# # Max profit pas atteint ET perte < 2 * current_trailing_stop_positive
# if profit > limit: # 2 * current_trailing_stop_positive:
# print(
# f"{current_time} trailing non atteint trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} "
# f"max={round(max_profit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} baisse={round(baisse,2)}")
# 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)} "
# f"max={round(max_profit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} baisse={round(baisse,2)}")
# else:
# # print(
# # f"1 - {current_time} trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} max={round(max_profit, 4)} "
# # f"limit={round(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)}"
# # f" baisse={round(baisse,2)} {round(last_candle['sma180_deriv1'], 4)} {round(last_candle['sma60_deriv1'], 4)} {round(last_candle['sma24_deriv1'], 4)}")
#
# return None
# # Sinon : trailing actif dès le début
#
# # ----- 6) Condition de vente -----
# if 0 < profit <= trailing_stop: # and last_candle['mid'] < last_candle['sma5']: # and profit > current_trailing_stop_positive_offset:
# 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(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} "
# f"baisse={round(baisse,2)}")
#
# return f"stop_{count_of_buys}_{self.pairs[pair]['has_gain']}"
return None
# Sinon : trailing actif dès le début
# ----- 6) Condition de vente -----
if 0 < profit <= trailing_stop: # and last_candle['mid'] < last_candle['sma5']: # and profit > current_trailing_stop_positive_offset:
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(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} "
f"baisse={round(baisse,2)}")
return f"stop_{count_of_buys}_{self.pairs[pair]['has_gain']}"
# print(
# f"2 - {current_time} trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} max={round(max_profit, 4)} "
# f"{round(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} "
# f"baisse={round(baisse,2)} {round(last_candle['sma180_deriv1'], 4)} {round(last_candle['sma60_deriv1'], 4)} {round(last_candle['sma24_deriv1'], 4)}")
return None
print(
f"2 - {current_time} trailing_stop={round(trailing_stop, 4)} profit={round(profit, 4)} max={round(max_profit, 4)} "
f"{round(limit, 4)} offset={round(current_trailing_stop_positive_offset, 4)} "
f"baisse={round(baisse,2)} {round(last_candle['sma180_deriv1'], 4)} {round(last_candle['sma60_deriv1'], 4)} {round(last_candle['sma24_deriv1'], 4)}")
return None
def informative_pairs(self):
# get access to all pairs available in whitelist.
pairs = self.dp.current_whitelist()
@@ -2440,6 +2466,21 @@ class FrictradeLearning(IStrategy):
# d2s_col = f"{name}{suffixe}_deriv2_smooth"
tendency_col = f"{name}{suffixe}_state"
d1_col = f"{name}{suffixe}_deriv1"
d2_col = f"{name}{suffixe}_deriv2"
tendency_col = f"{name}{suffixe}_state"
series = dataframe[f"{name}{suffixe}"]
d1 = series.diff()
d2 = d1.diff()
pmin = int(ema_period / 3)
cond_bas = (d1.rolling(pmin).mean() > d1.rolling(ema_period).mean())
cond_haut = (d1.rolling(pmin).mean() < d1.rolling(ema_period).mean())
dataframe[d1_col] = (dataframe[name] - dataframe[name].shift(3)) / dataframe[name].shift(3)
dataframe[d2_col] = (dataframe[d1_col] - dataframe[d1_col].shift(1))
factor1 = 100 * (ema_period / 5)
factor2 = 10 * (ema_period / 5)
@@ -2450,15 +2491,15 @@ class FrictradeLearning(IStrategy):
dataframe[f"{name}{suffixe}_dist"] = (dataframe['close'] - dataframe[f"{name}{suffixe}"]) / dataframe[
f"{name}{suffixe}"]
# dérivée relative simple
dataframe[d1_col] = (dataframe[name] - dataframe[name].shift(1)) / dataframe[name].shift(1)
# lissage EMA
dataframe[d1_col] = factor1 * dataframe[d1_col].ewm(span=ema_period, adjust=False).mean()
# dataframe[d1_col] = dataframe[d1_col].rolling(window=ema_period, center=True).median()
dataframe[d2_col] = dataframe[d1_col] - dataframe[d1_col].shift(1)
dataframe[d2_col] = factor2 * dataframe[d2_col].ewm(span=ema_period, adjust=False).mean()
# # dérivée relative simple
# dataframe[d1_col] = (dataframe[name] - dataframe[name].shift(1)) / dataframe[name].shift(1)
# # lissage EMA
# dataframe[d1_col] = factor1 * dataframe[d1_col].ewm(span=ema_period, adjust=False).mean()
#
# # dataframe[d1_col] = dataframe[d1_col].rolling(window=ema_period, center=True).median()
#
# dataframe[d2_col] = dataframe[d1_col] - dataframe[d1_col].shift(1)
# dataframe[d2_col] = factor2 * dataframe[d2_col].ewm(span=ema_period, adjust=False).mean()
# epsilon adaptatif via rolling percentile
p_low_d1 = dataframe[d1_col].rolling(window=window, min_periods=1).quantile(0.05)