This commit is contained in:
Jérôme Delacotte
2025-11-05 20:05:15 +01:00
parent fd4a487034
commit bd6699493a
2 changed files with 158 additions and 84 deletions

View File

@@ -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"
}

View File

@@ -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):
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:
return 'BR2'
trend_class.append('B--')
elif v <= q2:
return 'BR1'
trend_class.append('B-')
elif v <= q3:
return 'RG'
trend_class.append('P')
elif v <= q4:
return 'BU1'
trend_class.append('H+')
else:
return 'BU2'
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: