From bd6699493a74e5272e9f200bca6ec10678b32b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Wed, 5 Nov 2025 20:05:15 +0100 Subject: [PATCH] hyperopt --- Zeus_8_3_2_B_4_2.json | 51 +++++------ Zeus_8_3_2_B_4_2.py | 191 +++++++++++++++++++++++++++++------------- 2 files changed, 158 insertions(+), 84 deletions(-) diff --git a/Zeus_8_3_2_B_4_2.json b/Zeus_8_3_2_B_4_2.json index 8d88c85..bf650cd 100644 --- a/Zeus_8_3_2_B_4_2.json +++ b/Zeus_8_3_2_B_4_2.json @@ -4,40 +4,43 @@ "roi": { "0": 10 }, - "trailing": { - "trailing_stop": true, - "trailing_stop_positive": 0.15, - "trailing_stop_positive_offset": 0.2, - "trailing_only_offset_is_reached": true + "stoploss": { + "stoploss": -1.0 }, "max_open_trades": { "max_open_trades": 80 }, "buy": { - "indic_deriv_5m_slop_sup_buy": "sma12", - "indic_deriv_5m_slop_sup_inf": "sma12", "mises": 5, - "deriv_5m_slope_sup_buy": 0.07, - "deriv_5m_slope_sup_inf": 0.04, - "indic_5m_slope_inf": "sma12", - "indic_5m_slope_sup": "sma24", - "mise_factor_buy": 0.02, - "pct": 0.04, - "pct_inc": 0.0016 + "deriv_5m_slope_sup_buy": 0.0, + "indic_5m_slope_inf_buy": "sma24", + "indic_5m_slope_sup_buy": "sma5", + "indic_deriv_5m_slop_sup_buy": "sma5", + "mise_factor_buy": 0.01, + "pct": 0.016, + "pct_inc": 0.002 }, "sell": { - "deriv_5m_slope_inf_sell": 0.14, - "deriv_5m_slope_sup_sell": 0.41, - "indic_5m_slope_inf_sell": "sma12", - "indic_5m_slope_sup_sell": "sma60", - "indic_deriv_5m_slope_inf_sell": "sma12", - "indic_deriv_5m_slope_sup_sell": "sma5" + "deriv_5m_slope_inf_sell": -0.04, + "deriv_5m_slope_sup_sell": -0.05, + "indic_5m_slope_inf_sell": "sma24", + "indic_5m_slope_sup_sell": "sma24", + "indic_deriv_5m_slope_inf_sell": "sma60", + "indic_deriv_5m_slope_sup_sell": "sma24" }, - "protection": {}, - "stoploss": { - "stoploss": -0.155 + "protection": { + "deriv1_buy_protect": 0.09, + "indic_1h_slope_sup": "sma5", + "indic_5m_slope_sup": "sma12", + "rsi_buy_protect": 51 + }, + "trailing": { + "trailing_stop": true, + "trailing_stop_positive": 0.27, + "trailing_stop_positive_offset": 0.299, + "trailing_only_offset_is_reached": true } }, "ft_stratparam_v": 1, - "export_time": "2025-11-02 16:30:26.419500+00:00" + "export_time": "2025-11-05 02:31:05.384528+00:00" } \ No newline at end of file diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index f2a517b..8578ddc 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -35,6 +35,7 @@ from collections import Counter logger = logging.getLogger(__name__) + from tabulate import tabulate # Couleurs ANSI de base @@ -70,9 +71,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): stakes = 40 # Stoploss: - # stoploss = -1 # 0.256 + stoploss = -1 # 0.256 # Custom stoploss - # use_custom_stoploss = False + use_custom_stoploss = False trailing_stop = True trailing_stop_positive = 0.15 @@ -263,13 +264,13 @@ class Zeus_8_3_2_B_4_2(IStrategy): pct = DecimalParameter(0.005, 0.05, default=0.012, decimals=3, space='buy', optimize=True, load=True) pct_inc = DecimalParameter(0.0001, 0.003, default=0.0022, decimals=4, space='buy', optimize=True, load=True) - indic_5m_slope_sup = CategoricalParameter(indicators, default="sma60", space='buy') - indic_deriv_5m_slop_sup_buy = CategoricalParameter(indicators, default="sma12", space='buy', optimize=False, load=False) + indic_5m_slope_sup_buy = CategoricalParameter(indicators, default="sma60", space='buy') + indic_deriv_5m_slop_sup_buy = CategoricalParameter(indicators, default="sma12", space='buy', optimize=True, load=True) deriv_5m_slope_sup_buy = DecimalParameter(-0.1, 0.5, default=0, decimals=2, space='buy', optimize=True, load=True) - indic_5m_slope_inf = CategoricalParameter(indicators, default="sma60", space='buy') - indic_deriv_5m_slop_sup_inf = CategoricalParameter(indicators, default="sma12", space='buy', optimize=False, load=False) - deriv_5m_slope_sup_inf = DecimalParameter(-0.1, 0.5, default=0, decimals=2, space='buy', optimize=True, load=True) + indic_5m_slope_inf_buy = CategoricalParameter(indicators, default="sma60", space='buy') + indic_deriv_5m_slop_sup_buy = CategoricalParameter(indicators, default="sma12", space='buy', optimize=True, load=True) + deriv_5m_slope_sup_buy = DecimalParameter(-0.1, 0.5, default=0, decimals=2, space='buy', optimize=True, load=True) # indic_deriv1_5m = DecimalParameter(-2, 2, default=0, decimals=2, space='buy', optimize=True, load=True) @@ -294,6 +295,11 @@ class Zeus_8_3_2_B_4_2(IStrategy): indic_deriv_5m_slope_inf_sell = CategoricalParameter(indicators, default="sma60", space='sell') deriv_5m_slope_inf_sell = DecimalParameter(-0.1, 0.5, default=0, decimals=2, space='sell', optimize=True, load=True) + deriv1_buy_protect = DecimalParameter(-0.3, 0.1, default=-0.1, decimals=2, space='protection', optimize=True, load=True) + rsi_buy_protect = IntParameter(50, 90, default=70, space='protection', optimize=True, load=True) + indic_5m_slope_sup = CategoricalParameter(indicators, default="sma60", space='protection') + indic_1h_slope_sup = CategoricalParameter(indicators, default="sma5", space='protection') + # indic_percent_sell = CategoricalParameter(indicators_percent, default="sma60", space='sell') # percent_5m_sell = DecimalParameter(-0.1, -0.0, default=0, decimals=2, space='sell', optimize=True, load=True) @@ -421,12 +427,14 @@ class Zeus_8_3_2_B_4_2(IStrategy): def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float, time_in_force: str, exit_reason: str, current_time, **kwargs, ) -> bool: + # allow_to_sell = (minutes > 30) dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() + profit =trade.calc_profit(rate) force = self.pairs[pair]['force_sell'] - allow_to_sell = (last_candle['hapercent'] < 0 and trade.calc_profit(rate, amount) > 0) or force or (exit_reason == 'force_exit') + allow_to_sell = (last_candle['hapercent'] < 0 and profit > 0) or force or (exit_reason == 'force_exit') or (exit_reason == 'stop_loss') minutes = int(round((current_time - trade.date_last_filled_utc).total_seconds() / 60, 0)) @@ -448,7 +456,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): trade_type=exit_reason, rate=last_candle['close'], dispo=dispo, - profit=round(trade.calc_profit(rate, amount), 2) + profit=round(profit, 2) ) self.pairs[pair]['force_sell'] = False self.pairs[pair]['has_gain'] = 0 @@ -459,8 +467,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): self.pairs[pair]['last_buy'] = 0 self.pairs[pair]['last_date'] = current_time self.pairs[pair]['current_trade'] = None - - return (allow_to_sell) | (exit_reason == 'force_exit') + # else: + # print(f"STOP triggered for {pair} ({exit_reason}) but condition blocked", "warning") + return (allow_to_sell) | (exit_reason == 'force_exit') | (exit_reason == 'stop_loss') def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, @@ -495,7 +504,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): count_of_buys = trade.nr_of_successful_entries - profit = round(current_profit * trade.stake_amount, 1) + profit = trade.calc_profit(current_rate) #round(current_profit * trade.stake_amount, 1) self.pairs[pair]['max_profit'] = max(self.pairs[pair]['max_profit'], profit) max_profit = self.pairs[pair]['max_profit'] baisse = 0 @@ -525,7 +534,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): pair=pair, rate=last_candle['close'], trade_type='', - profit=profit, + profit=round(profit, 2), buys=count_of_buys, stake=0 ) @@ -541,9 +550,9 @@ class Zeus_8_3_2_B_4_2(IStrategy): # if (current_profit > expected_profit) and last_candle['can_sell']: # return 'Can_' + pair_name + '_' + str(count_of_buys) # trend = last_candle['trend_class_1d'] - # if (trend == "BR1" or trend == "BR2") and self.pairs[pair]['has_gain'] == 0: # and (last_candle[f"{indic_5m_sell}_deriv1"] <= indic_deriv1_5m_sell and last_candle[f"{indic_5m_sell}_deriv2"] <= indic_deriv2_5m_sell): + # if (trend == "B-" or trend == "B--") and self.pairs[pair]['has_gain'] == 0: # and (last_candle[f"{indic_5m_sell}_deriv1"] <= indic_deriv1_5m_sell and last_candle[f"{indic_5m_sell}_deriv2"] <= indic_deriv2_5m_sell): # - # if (last_candle['max_rsi_12_1h'] > 75) and last_candle['trend_class_1h'] == 'BU1' and profit > max(5, expected_profit) and (last_candle['hapercent'] < 0): + # if (last_candle['max_rsi_12_1h'] > 75) and last_candle['trend_class_1h'] == 'H+' and profit > max(5, expected_profit) and (last_candle['hapercent'] < 0): # self.pairs[pair]['stop'] = True # self.log_trade( # last_candle=last_candle, @@ -561,7 +570,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # # return None - # if (trend == "BR1" or trend == "BR2") and last_candle[f"{self.indic_5m_sell.value}_deriv1"] <= self.indic_deriv1_5m_sell.value \ + # if (trend == "B-" or trend == "B--") and last_candle[f"{self.indic_5m_sell.value}_deriv1"] <= self.indic_deriv1_5m_sell.value \ # and last_candle[f"{self.indic_5m_sell.value}_deriv2"] <= self.indic_deriv2_5m_sell.value: # return None @@ -781,7 +790,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # f"|{last_candle['min60_1d']}|{last_candle['max60_1d']}" # f"|{last_candle['mid_smooth_tdc_5_1d'] or '-':>3}|{last_candle['mid_smooth_tdc_5_1h'] or '-':>3}|{last_candle['mid_smooth_tdc_5'] or '-':>3}" f"|{last_candle['mid_smooth_5_state_1d'] or '-':>3}|{last_candle['mid_smooth_24_state_1h'] or '-':>3}|{last_candle['mid_smooth_5_state_1h'] or '-':>3}|{last_candle['mid_smooth_5_state'] or '-':>3}" - f"|Params {last_candle['trend_class_1d']} {last_candle['trend_class_1h']} {indic_5m} {indic_deriv1_5m} {indic_deriv2_5m} {indic_5m_sell} {indic_deriv1_5m_sell} {indic_deriv2_5m_sell}" + f"|Params {last_candle['trend_class_1d']} {last_candle['trend_class_1h']}" # {indic_5m} {indic_deriv1_5m} {indic_deriv2_5m} {indic_5m_sell} {indic_deriv1_5m_sell} {indic_deriv2_5m_sell}" ) def getLastLost(self, last_candle, pair): @@ -971,6 +980,34 @@ class Zeus_8_3_2_B_4_2(IStrategy): # indic_2 = 'mid_smooth_1h_deriv2' # self.calculateProbabilite2Index(dataframe, futur_cols, indic_1, indic_2) + # dataframe = dataframe.resample('sma12_1h').ffill() + # dataframe = dataframe.resample('sma24_1h').ffill() + + # mises = IntParameter(1, 50, default=5, space='buy', optimize=False, load=False) + # + # pct = DecimalParameter(0.005, 0.05, default=0.012, decimals=3, space='buy', optimize=True, load=True) + # pct_inc = DecimalParameter(0.0001, 0.003, default=0.0022, decimals=4, space='buy', optimize=True, load=True) + # + # indic_5m_slope_sup = CategoricalParameter(indicators, default="sma60", space='buy') + + indic_5m_protect = self.indic_5m_slope_sup.value + indic_1h_protect = self.indic_1h_slope_sup.value + '_1h' + + dataframe['stop_buying_deb'] = ((dataframe['max_rsi_12_1d'] > self.rsi_buy_protect.value) | (dataframe['sma24_deriv1_1h'] < self.deriv1_buy_protect.value)) & (qtpylib.crossed_below(dataframe[indic_5m_protect], dataframe[indic_1h_protect])) + dataframe['stop_buying_end'] = (dataframe[indic_1h_protect].shift(24) > dataframe[indic_1h_protect].shift(12)) & (dataframe[indic_1h_protect].shift(12) < dataframe[indic_1h_protect]) + + latched = np.zeros(len(dataframe), dtype=bool) + + for i in range(1, len(dataframe)): + if dataframe['stop_buying_deb'].iloc[i]: + latched[i] = True + elif dataframe['stop_buying_end'].iloc[i]: + latched[i] = False + else: + latched[i] = latched[i - 1] + + dataframe['stop_buying'] = latched + return dataframe def populateDataframe(self, dataframe, timeframe='5m'): @@ -988,14 +1025,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): if self.dp.runmode.value in ('backtest'): dataframe['futur_percent'] = 100 * (dataframe['close'].shift(-1) - dataframe['close']) / dataframe['close'] - # dataframe['hapercent3'] = (dataframe['haclose'] - dataframe['haopen'].shift(3)) / dataframe['haclose'].shift(3) - dataframe['sma5'] = dataframe["mid"].rolling(window=5).mean() #talib.SMA(dataframe, timeperiod=5) + dataframe['sma5'] = dataframe['mid'].ewm(span=5, adjust=False).mean() #dataframe["mid"].rolling(window=5).mean() self.calculeDerivees(dataframe, 'sma5', timeframe=timeframe, ema_period=5) - dataframe['sma12'] = dataframe["mid"].rolling(window=12).mean() #talib.SMA(dataframe, timeperiod=12) + dataframe['sma12'] = dataframe['mid'].ewm(span=12, adjust=False).mean() #dataframe["mid"].rolling(window=12).mean() self.calculeDerivees(dataframe, 'sma12', timeframe=timeframe, ema_period=12) - dataframe['sma24'] = dataframe["mid"].rolling(window=24).mean() #talib.SMA(dataframe, timeperiod=24) + dataframe['sma24'] = dataframe['mid'].ewm(span=24, adjust=False).mean() #dataframe["mid"].rolling(window=24).mean() self.calculeDerivees(dataframe, 'sma24', timeframe=timeframe, ema_period=24) - dataframe['sma60'] = dataframe["mid"].rolling(window=60).mean() #talib.SMA(dataframe, timeperiod=60) + dataframe['sma48'] = dataframe['mid'].ewm(span=48, adjust=False).mean() #dataframe["mid"].rolling(window=48).mean() + self.calculeDerivees(dataframe, 'sma48', timeframe=timeframe, ema_period=48) + dataframe['sma60'] = dataframe['mid'].ewm(span=60, adjust=False).mean() #dataframe["mid"].rolling(window=60).mean() self.calculeDerivees(dataframe, 'sma60', timeframe=timeframe, ema_period=60) dataframe = self.calculateDerivation(dataframe, window=3, suffixe="_3",timeframe=timeframe) @@ -1039,21 +1077,22 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['macdsignal'] = macdsignal dataframe['macdhist'] = macdhist - # --- Rendre relatif sur chaque série (-1 → 1) --- - for col in ['macd', 'macdsignal', 'macdhist']: - series = dataframe[col] - valid = series[~np.isnan(series)] # ignorer NaN - min_val = valid.min() - max_val = valid.max() - span = max_val - min_val if max_val != min_val else 1 - dataframe[f'{col}_rel'] = 2 * ((series - min_val) / span) - 1 - - dataframe['tdc_macd'] = self.macd_tendance_int( - dataframe, - macd_col='macd_rel', - signal_col='macdsignal_rel', - hist_col='macdhist_rel' - ) + # Regarde dans le futur + # # --- Rendre relatif sur chaque série (-1 → 1) --- + # for col in ['macd', 'macdsignal', 'macdhist']: + # series = dataframe[col] + # valid = series[~np.isnan(series)] # ignorer NaN + # min_val = valid.min() + # max_val = valid.max() + # span = max_val - min_val if max_val != min_val else 1 + # dataframe[f'{col}_rel'] = 2 * ((series - min_val) / span) - 1 + # + # dataframe['tdc_macd'] = self.macd_tendance_int( + # dataframe, + # macd_col='macd_rel', + # signal_col='macdsignal_rel', + # hist_col='macdhist_rel' + # ) # ------------------------------------------------------------------------------------ # rolling SMA indicators (used for trend detection too) @@ -1348,9 +1387,10 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe.loc[ ( - (dataframe[f"{self.indic_5m_slope_sup.value}"].shift(2) >= dataframe[f"{self.indic_5m_slope_sup.value}"].shift(1)) - & (dataframe[f"{self.indic_5m_slope_sup.value}"].shift(1) <= dataframe[f"{self.indic_5m_slope_sup.value}"]) + (dataframe[f"{self.indic_5m_slope_sup_buy.value}"].shift(2) >= dataframe[f"{self.indic_5m_slope_sup_buy.value}"].shift(1)) + & (dataframe[f"{self.indic_5m_slope_sup_buy.value}"].shift(1) <= dataframe[f"{self.indic_5m_slope_sup_buy.value}"]) & (dataframe['slope_norm_1d'] < dataframe['slope_norm_1h']) + & (dataframe['stop_buying'] == False) # & (dataframe[f"{self.indic_deriv_5m_buy.value}_deriv1"] > self.deriv_5m_buy.value) # & (dataframe[f"sma60_deriv1"] >= -0.2) # & (dataframe[f"hapercent"] >= -0.001) @@ -1358,13 +1398,23 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe.loc[ ( - (dataframe[f"{self.indic_5m_slope_inf.value}"].shift(2) >= dataframe[f"{self.indic_5m_slope_inf.value}"].shift(1)) - & (dataframe[f"{self.indic_5m_slope_inf.value}"].shift(1) <= dataframe[f"{self.indic_5m_slope_inf.value}"]) + (dataframe[f"{self.indic_5m_slope_inf_buy.value}"].shift(2) >= dataframe[f"{self.indic_5m_slope_inf_buy.value}"].shift(1)) + & (dataframe[f"{self.indic_5m_slope_inf_buy.value}"].shift(1) <= dataframe[f"{self.indic_5m_slope_inf_buy.value}"]) & (dataframe['slope_norm_1d'] > dataframe['slope_norm_1h']) + & (dataframe['stop_buying'] == False) # & (dataframe[f"{self.indic_deriv_5m_buy.value}_deriv1"] > self.deriv_5m_buy.value) # & (dataframe[f"sma60_deriv1"] >= -0.2) # & (dataframe[f"hapercent"] >= -0.001) - ), ['enter_long', 'enter_tag']] = (1, f"{self.indic_5m_slope_inf.value}_inf") + ), ['enter_long', 'enter_tag']] = (1, f"{self.indic_5m_slope_inf_buy.value}_inf") + + dataframe.loc[ + ( + (dataframe['stop_buying'] == False) + & (dataframe['stop_buying'].shift(1) == True) + # & (dataframe[f"{self.indic_deriv_5m_buy.value}_deriv1"] > self.deriv_5m_buy.value) + # & (dataframe[f"sma60_deriv1"] >= -0.2) + # & (dataframe[f"hapercent"] >= -0.001) + ), ['enter_long', 'enter_tag']] = (1, f"end") dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.01, np.nan) @@ -1540,6 +1590,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): & (dataframe['slope_norm_1d'] < dataframe['slope_norm_1h']) ), ['exit_long', 'exit_tag']] = (1, f"{self.indic_5m_slope_inf_sell.value}_inf") + dataframe.loc[ + ( + (dataframe['stop_buying'] == True) + & (dataframe['stop_buying'].shift(1) == False) + # & (dataframe[f"{self.indic_deriv_5m_buy.value}_deriv1"] > self.deriv_5m_buy.value) + # & (dataframe[f"sma60_deriv1"] >= -0.2) + # & (dataframe[f"hapercent"] >= -0.001) + ), ['enter_long', 'enter_tag']] = (1, f"start") + # dataframe.loc[ # ( # (dataframe[f"{self.indic_percent_sell.value}"] < self.percent_5m_sell.value) @@ -1576,7 +1635,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): open_date = trade.open_date.astimezone(timezone.utc) days_since_open = (current_time_utc - open_date).days pair = trade.pair - profit = round(current_profit * trade.stake_amount, 1) + profit = trade.calc_profit(current_rate) #round(current_profit * trade.stake_amount, 1) last_lost = self.getLastLost(last_candle, pair) pct_first = 0 @@ -1613,7 +1672,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): if not self.should_enter_trade(pair, last_candle, current_time): return None - condition = (last_candle['enter_long'] and last_candle['sma5_deriv1'] > 0 and last_candle['hapercent'] > 0) or (last_candle['percent3'] < -0.03 and last_candle['percent'] > 0) + condition = (last_candle['enter_long'] and last_candle['sma5_deriv1'] > 0 and last_candle['hapercent'] > 0 and last_candle['stop_buying'] == False) or (last_candle['percent3'] < -0.03 and last_candle['percent'] > 0) # if (self.getShortName(pair) != 'BTC' and count_of_buys > 3): # condition = before_last_candle_24['mid_smooth_3_1h'] > before_last_candle_12['mid_smooth_3_1h'] and before_last_candle_12['mid_smooth_3_1h'] < last_candle['mid_smooth_3_1h'] #and last_candle['mid_smooth_3_deriv1_1h'] < -1.5 @@ -1658,7 +1717,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): pair=trade.pair, rate=current_rate, trade_type=trade_type, - profit=round(current_profit * trade.stake_amount, 1), + profit=round(profit, 1), buys=trade.nr_of_successful_entries + 1, stake=round(stake_amount, 2) ) @@ -1704,7 +1763,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): pair=trade.pair, rate=current_rate, trade_type=str(round(pct_max, 4)), - profit=round(current_profit * trade.stake_amount, 1), + profit=round(profit, 1), buys=trade.nr_of_successful_entries + 1, stake=round(stake_amount, 2) ) @@ -2384,7 +2443,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # return last_candle['slope_norm_1d'] < last_candle['slope_norm_1h'] - if self.pairs[pair]['stop'] and last_candle['max_rsi_12_1h'] <= 60 and last_candle['trend_class_1h'] == 'BR1': + if self.pairs[pair]['stop'] and last_candle['max_rsi_12_1h'] <= 60 and last_candle['trend_class_1h'] == 'B-': dispo = round(self.wallets.get_available_stake_amount()) self.pairs[pair]['stop'] = False self.log_trade( @@ -2594,20 +2653,32 @@ class Zeus_8_3_2_B_4_2(IStrategy): q = df['slope_norm'].quantile([0.125, 0.375, 0.625, 0.875]).values q1, q2, q3, q4 = q - def classify(v): - if v <= q1: - return 'BR2' - elif v <= q2: - return 'BR1' - elif v <= q3: - return 'RG' - elif v <= q4: - return 'BU1' - else: - return 'BU2' + def classify_expanding(series): + trend_class = [] + for i in range(len(series)): + past_values = series[:i + 1] # uniquement le passé + q = past_values.quantile([0.125, 0.375, 0.625, 0.875]).values + q1, q2, q3, q4 = q + v = series.iloc[i] + if v <= q1: + trend_class.append('B--') + elif v <= q2: + trend_class.append('B-') + elif v <= q3: + trend_class.append('P') + elif v <= q4: + trend_class.append('H+') + else: + trend_class.append('H++') + return trend_class dataframe['slope_norm'] = df['slope_norm'] - dataframe['trend_class'] = df['slope_norm'].apply(classify) + # dataframe['trend_class'] = df['slope_norm'].apply(classify) + dataframe['trend_class'] = None + + # Rolling sur la fenêtre passée + dataframe['trend_class'] = classify_expanding(dataframe['slope_norm']) + # # -------------------------- Trend detection (M2) -------------------------- # def getTrend(self, dataframe: DataFrame) -> str: @@ -2730,4 +2801,4 @@ class Zeus_8_3_2_B_4_2(IStrategy): def getParamValue(self, pair, trend, space, param): pair = self.getShortName(pair) - return self.parameters[pair][trend][0]['content']['params'][space][param] \ No newline at end of file + return self.parameters[pair][trend][0]['content']['params'][space][param]