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

@@ -14,12 +14,7 @@
"trailing_only_offset_is_reached": false
},
"max_open_trades": {
"max_open_trades": 20
},
"protection": {
"b30_indicateur": "sma36",
"baisse": 0.3,
"drop_from_last_entry": -0.03
"max_open_trades": 1
},
"buy": {
"buy_deriv1_sma12d": -0.04,
@@ -30,17 +25,25 @@
"buy_deriv2_sma60": -0.001,
"buy_longue": 160,
"buy_longue_derive": "sma80_deriv1_1d",
"start_bear_deriv1": -0.004,
"start_bear_deriv2": 0.002,
"start_bear_indicator": "sma80",
"start_bull_deriv1": 0.001,
"start_bull_deriv2": -0.002,
"start_bull_indicator": "sma120"
"start_bear_deriv1": 0.003,
"start_bear_deriv2": 0.003,
"start_bear_indicator": "sma24",
"start_bull_deriv1": -0.005,
"start_bull_deriv2": 0.0,
"start_bull_indicator": "sma3"
},
"protection": {
"drop_from_last_entry": -0.03,
"mises": 1
},
"sell": {
"sell_score_indicator": "sma24_score"
"b30_indicateur": "sma36",
"baisse": 0.25,
"sell_force_sell": -0.169,
"sell_indicator": "sma3",
"sell_score_indicator": "sma3_score"
}
},
"ft_stratparam_v": 1,
"export_time": "2026-02-28 17:28:20.867470+00:00"
"export_time": "2026-03-07 11:58:51.712499+00:00"
}

View File

@@ -216,8 +216,12 @@ class Empty(IStrategy):
# baisses = list()
# for i in range(0, 0.5, 0.05):
# baisses.append(i)
baisse = DecimalParameter(0, 0.5, decimals=2, default=0.3, space='protection', optimize=True, load=True)
b30_indicateur = CategoricalParameter(sma_indicators_h, default="sma36", space='protection', optimize=True, load=True)
mises = IntParameter(1, 10, default=1, space='protection')
sell_force_sell = DecimalParameter(-0.2, 0, decimals=3, default=-0.02, space='sell')
sell_indicator = CategoricalParameter(sma_indicators, default="sma36", space='sell', optimize=True, load=True)
baisse = DecimalParameter(0.1, 0.5, decimals=2, default=0.3, space='sell', optimize=True, load=True)
b30_indicateur = CategoricalParameter(sma_indicators_h, default="sma36", space='sell', optimize=True, load=True)
# lost_indicator = CategoricalParameter(sma_deriv1_indicators, default="sma5_deriv1", space='protection')
@@ -250,10 +254,10 @@ class Empty(IStrategy):
# sl_max = self.wallets.get_available_stake_amount() / 2
#
# amount = sl_min + (1 - range_pos) * (sl_max - sl_min)
if last_candle['enter_tag'] == 'fall':
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() # / (2 * self.pairs[pair]['count_of_lost'] + 1)
amount = self.wallets.get_available_stake_amount() / self.mises.value # / (2 * self.pairs[pair]['count_of_lost'] + 1)
# factor = 1
#
@@ -364,6 +368,8 @@ class Empty(IStrategy):
last_candle_2 = dataframe.iloc[-2].squeeze()
last_candle_3 = dataframe.iloc[-3].squeeze()
if entry_tag == 'Range-':
self.pairs[pair]['count_of_lost'] = 0
if entry_tag == 'Force':
if self.pairs[pair]['count_of_lost'] >= 1:
self.pairs[pair]['count_of_lost'] = 0
@@ -546,15 +552,15 @@ class Empty(IStrategy):
# buys=count_of_buys,
# stake=0
# )
# if self.pairs[pair]['current_trade'].enter_tag == 'fall':
# if current_profit < - 0.02 and last_candle[f"close"] <= last_candle['sma60'] and self.wallets.get_available_stake_amount() < 50:
# self.pairs[pair]['force_sell'] = True
# return 'sma60'
# else:
if current_profit < - 0.02 and last_candle[f"close"] <= last_candle['sma60']:
if self.pairs[pair]['current_trade'].enter_tag in ['bear', 'Force', 'Range-']:
if current_profit < - 0.02 and last_candle[f"close"] <= last_candle['sma60'] and self.wallets.get_available_stake_amount() < 50:
self.pairs[pair]['force_sell'] = True
return 'sma60'
return 'smaBF'
else:
if current_profit < self.sell_force_sell.value \
and last_candle[f"close"] <= last_candle[self.sell_indicator.value]:
self.pairs[pair]['force_sell'] = True
return 'sma'
if profit > max(5, expected_profit) and \
(baisse > self.baisse.value and last_candle[f"close"] <= last_candle[self.b30_indicateur.value]) \
@@ -743,8 +749,8 @@ class Empty(IStrategy):
# #####################################################################################
# CA MONTE !!
# #####################################################################################
# conditions.append(dataframe[f"{self.start_bull_indicator.value}_deriv1_1d" ] > self.start_bull_deriv1.value)
# conditions.append(dataframe[f"{self.start_bull_indicator.value}_deriv2_1d"] > self.start_bull_deriv2.value)
conditions.append(dataframe[f"{self.start_bull_indicator.value}_deriv1_1d" ] > self.start_bull_deriv1.value)
conditions.append(dataframe[f"{self.start_bull_indicator.value}_deriv2_1d"] > self.start_bull_deriv2.value)
conditions.append(dataframe['sma12_deriv1'] > self.buy_deriv1_sma60.value)
conditions.append(dataframe['sma5_deriv1_1d'] > self.buy_deriv1_sma5d.value)
conditions.append(dataframe['sma12_deriv1_1d'] > self.buy_deriv1_sma12d.value)
@@ -791,11 +797,11 @@ class Empty(IStrategy):
conditions.append(dataframe['mid_smooth12'] > dataframe['mid_smooth12'].shift(1))
conditions.append(dataframe['sma100_deriv1_1d'] > 0)
conditions.append(dataframe[f"range_pos"] < 0.01)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
['enter_long', 'enter_tag']
] = (1, 'dist')
# if conditions:
# dataframe.loc[
# reduce(lambda x, y: x & y, conditions),
# ['enter_long', 'enter_tag']
# ] = (1, 'dist')
# #####################################################################################
# CA BAISSE !!
@@ -866,16 +872,17 @@ class Empty(IStrategy):
conditions.append(dataframe['sma12_deriv1_1d'] > 0.0)
conditions.append(dataframe['sma24_deriv1_1d'] > 0.0)
conditions.append(dataframe['sma100_deriv1_1d'] > 0.0)
conditions.append(dataframe[f"range_pos"] < 0.025)
# conditions.append(dataframe['sma12_deriv1_1d'] > 0.0)
# # conditions.append(dataframe['close_1d'] < dataframe[f'sma{self.buy_longue.value}_1d'])
# # conditions.append(dataframe['has_cross_min'].rolling(6).max() == 1)
# # conditions.append(dataframe['mid_smooth5'] > dataframe['mid_smooth5'].shift(1))
# conditions.append(dataframe['min12'] == dataframe['min12'].shift(3))
# conditions.append((dataframe['percent24'] < -0.025) | (dataframe['percent12'] < -0.025))
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
['enter_long', 'enter_tag']
] = (1, 'Rise')
# dataframe.loc[
# reduce(lambda x, y: x & y, conditions),
# ['enter_long', 'enter_tag']
# ] = (1, 'Rise')
# conditions = list()
# conditions.append(dataframe['has_cross_min_6'] == True)
@@ -885,6 +892,14 @@ class Empty(IStrategy):
# ['enter_long', 'enter_tag']
# ] = (1, 'Force')
# conditions = list()
# conditions.append(dataframe['range_pos'] < -0.03)
# conditions.append(dataframe['min36'] == dataframe['min36'].shift(3))
# dataframe.loc[
# reduce(lambda x, y: x & y, conditions),
# ['enter_long', 'enter_tag']
# ] = (1, 'Range-')
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

46
Empty5m.json Normal file
View File

@@ -0,0 +1,46 @@
{
"strategy_name": "Empty5m",
"params": {
"roi": {
"0": 5
},
"stoploss": {
"stoploss": -1.0
},
"trailing": {
"trailing_stop": false,
"trailing_stop_positive": null,
"trailing_stop_positive_offset": 0.0,
"trailing_only_offset_is_reached": false
},
"max_open_trades": {
"max_open_trades": 1
},
"buy": {
"buy_longue_derive": "sma60_deriv1_1h",
"buy_deriv1_sma12d": 0.0002,
"buy_deriv1_sma5d": -0.0006,
"buy_deriv1_sma60": -0.0003,
"buy_longue": 180,
"start_bear_deriv1": 0.005,
"start_bear_deriv2": -0.003,
"start_bear_indicator": "sma60",
"start_bull_deriv1": -0.001,
"start_bull_deriv2": 0.0,
"start_bull_indicator": "sma12"
},
"protection": {
"drop_from_last_entry": -0.03,
"mises_bear": 5,
"mises_bull": 1
},
"sell": {
"b30_indicateur": "sma24",
"baisse": 0.14,
"sell_force_sell": -0.135,
"sell_indicator": "sma12"
}
},
"ft_stratparam_v": 1,
"export_time": "2026-03-07 14:31:15.874478+00:00"
}

1317
Empty5m.py Normal file

File diff suppressed because it is too large Load Diff

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:
# # ----- 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"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"{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']}"
# 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
# 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
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)