Zeus_8_3_2_B_4_2 optimisations

This commit is contained in:
Jérôme Delacotte
2025-05-05 16:07:54 +02:00
parent d9f6d160f6
commit 8d3f2b0bff

View File

@@ -41,6 +41,7 @@ def normalize(df):
class Zeus_8_3_2_B_4_2(IStrategy):
levels = [1, 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
startup_candle_count = 24
# ROI table:
minimal_roi = {
@@ -66,15 +67,21 @@ class Zeus_8_3_2_B_4_2(IStrategy):
plot_config = {
"main_plot": {
"min200": {
"color": "#86c932"
},
"max50": {
"sma5_1h": {
"color": "white"
},
"max200": {
"sma20": {
"color": "yellow"
},
"sma20_smooth": {
"color": "green"
},
"sma20_smooth_2": {
"color": "red",
},
"sma20_smooth_3": {
"color": "blue",
},
"bb_lowerband": {
"color": "#da59a6"},
"bb_upperband": {
@@ -82,22 +89,48 @@ class Zeus_8_3_2_B_4_2(IStrategy):
}
},
"subplots": {
"Rsi": {
"rsi": {
"color": "pink"
"Pct": {
"sma20_pct": {
'color': "green"
}
},
"Percent": {
"max_min": {
"color": "#74effc"
"Rsi": {
"rsi60": {
"color": "red"
},
'rsi60_diff': {
"color": "blue"
},
'rsi60_diff2': {
'color': "green"
}
},
"Rsi_diff": {
"rsi_diff_1h": {
"color": "red"
},
"rsi_diff_2_1h": {
"color": "blue"
}
},
"smooth": {
'mid_smooth_deriv1': {
'sma5_diff_sum_1h': {
"color": "green"
},
'sma5_diff2_sum_1h': {
"color": "blue"
},
# 'mid_smooth_deriv1': {
# "color": "blue"
# },
'mid_smooth_deriv1_1h': {
"color": "red"
},
# 'mid_smooth_deriv2': {
# "color": "pink"
# },
'mid_smooth_deriv2_1h': {
"color": "#da59a6"
}
}
}
@@ -175,8 +208,9 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.pairs[pair]['current_profit'] = 0
self.printLog(
f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+"
f"{'-' * 14}+{'-' * 14}+{'-' * 4}+{'-' * 7}|"
f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}"
f"+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}|"
)
stake_amount = self.adjust_stake_amount(pair, last_candle)
@@ -184,7 +218,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.log_trade(
last_candle=last_candle,
date=current_time,
action="START BUY" if allow_to_buy else "Canceled",
action="Buy" if allow_to_buy else "Canceled",
pair=pair,
rate=rate,
dispo=dispo,
@@ -246,6 +280,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
last_candle_1h = dataframe.iloc[-13].squeeze()
before_last_candle = dataframe.iloc[-2].squeeze()
expected_profit = self.expectedProfit(pair, last_candle)
@@ -260,7 +295,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.pairs[pair]['current_profit'] = current_profit
pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3)
if (last_candle['tendency'] in ('H++', 'H+')) :
if (last_candle['tendency'] in ('H++', 'H+')) and (last_candle['rsi'] < 80):
# and (last_candle['tendency_1h'] in ('H++', 'H+')):
# and (last_candle['tendency_1d'] in ('H++', 'H+')) :
return None
@@ -331,10 +366,10 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|"
# )
self.printLog(
f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>12} |{'Buys':>4}| {'Stake':>5} |"
f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} | {'Rate':>8} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>7} |{'Buys':>4}| {'Stake':>5} |"
)
self.printLog(
f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 4}+{'-' * 7}|"
f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}|"
)
self.columns_logged += 1
date = str(date)[:16] if date else "-"
@@ -375,12 +410,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
+ " " + str(int(last_candle['rsi_diff_1h']))
self.printLog(
f"| {date:<16} | {action:<10} | {pair[0:3]:<3} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} "
f"| {date:<16} | {action:<10} | {pair[0:3]:<3} | {trade_type or '-':<18} |{rate or '-':>9}| {dispo or '-':>6} "
f"| {profit or '-':>8} | {pct_max or '-':>6} | {round(self.pairs[pair]['max_touch'], 2) or '-':>11} | {last_lost or '-':>12} "
f"| {round(self.pairs[pair]['last_max'], 2) or '-':>12} |{buys or '-':>4}|{stake or '-':>7}"
f"|{round(last_candle['sma5_1d'], 2) or '-':>8}"
f"| {round(self.pairs[pair]['last_max'], 0) or '-':>7} |{buys or '-':>4}|{stake or '-':>7}"
f"|{round(last_candle['sma5_diff_sum_1h'], 2) or '-':>6}|{round(last_candle['sma5_diff_sum_1d'], 2) or '-':>6}"
f"|{last_candle['tendency'] or '-':>3}|{last_candle['tendency_1h'] or '-':>3}|{last_candle['tendency_1d'] or '-':>3}"
f"|{round(last_candle['mid_smooth_deriv1']):>3}|{round(last_candle['mid_smooth_deriv1_1h']):>5}|"
f"|{round(last_candle['mid_smooth_deriv1']):>3}|{round(last_candle['mid_smooth_deriv1_1h']):>5}|{round(last_candle['mid_smooth_deriv1_1d']):>5}|"
)
def printLog(self, str):
@@ -440,6 +475,11 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5)
dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10)
dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20)
dataframe['sma20_pct'] = 100 * dataframe['sma20'].diff() / dataframe['sma20']
dataframe['sma20_smooth'] = dataframe['sma20'].ewm(span=5).mean()
dataframe['sma20_smooth_2'] = dataframe['sma20'].rolling(window=5, center=True).median()
dataframe['sma20_smooth_3'] = self.smooth_series(dataframe['sma20'], alpha_low=0.05, alpha_high=0.3, threshold=0.2)
dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
dataframe["percent3"] = (dataframe["close"] - dataframe["open"].shift(3)) / dataframe["open"].shift(3)
dataframe["percent5"] = (dataframe["close"] - dataframe["open"].shift(5)) / dataframe["open"].shift(5)
@@ -449,10 +489,14 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe["percent_max_144"] = (dataframe["close"] - dataframe["max144"]) / dataframe["close"]
# print(metadata['pair'])
dataframe['rsi'] = talib.RSI(dataframe['close'], length=14)
dataframe['rsi'] = talib.RSI(dataframe['close'], timeperiod=14)
dataframe['rsi_diff'] = dataframe['rsi'].diff()
dataframe['rsi_diff_2'] = dataframe['rsi_diff'].diff()
dataframe['rsi60'] = talib.RSI(dataframe['close'], timeperiod=60)
dataframe['rsi60_diff'] = dataframe['rsi60'].rolling(60).mean().diff()
dataframe['rsi60_diff2'] = dataframe['rsi60_diff'].rolling(60).mean().diff()
# Bollinger Bands
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
@@ -500,21 +544,26 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# Créer une colonne vide
dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count')
dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count')
dataframe = self.apply_regression_derivatives(dataframe, column='mid', window=24, degree=3)
# Normaliser les données de 'close'
# normalized_close = self.min_max_scaling(dataframe['close'])
################### INFORMATIVE 1h
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h")
informative = self.calculateTendency(informative, 3)
informative = self.apply_regression_derivatives(informative, column='mid', window=50, degree=3)
informative = self.apply_regression_derivatives(informative, column='mid', window=5, degree=3)
informative['volatility'] = talib.STDDEV(informative['close'], timeperiod=14) / informative['close']
informative['atr'] = (talib.ATR(informative['high'], informative['low'], informative['close'], timeperiod=14)) / informative['close']
informative['rsi'] = talib.RSI(informative['close'], length=7)
informative['rsi_diff'] = informative['rsi'].diff()
informative['rsi_sum'] = (informative['rsi'].rolling(7).sum() - 350) / 7
informative['rsi_sum_diff'] = informative['rsi_sum'].diff()
informative['rsi_diff_2'] = informative['rsi_diff'].diff()
informative['sma5'] = talib.SMA(informative, timeperiod=5)
informative['sma5_pct'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5']
informative['sma5_diff_sum'] = (informative['sma5_pct'].rolling(5).sum()) / 5
informative['sma5_diff2_sum'] = informative['sma5_diff_sum'].diff()
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True)
@@ -522,13 +571,16 @@ class Zeus_8_3_2_B_4_2(IStrategy):
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
informative = self.calculateTendency(informative, 3)
informative = self.apply_regression_derivatives(informative, column='mid', window=50, degree=3)
informative = self.apply_regression_derivatives(informative, column='mid', window=5, degree=3)
informative['rsi'] = talib.RSI(informative['close'], length=7)
informative['rsi_diff'] = informative['rsi'].diff()
informative['rsi_sum'] = (informative['rsi'].rolling(7).sum() - 350) / 7
informative['rsi_diff_2'] = informative['rsi_diff'].diff()
informative['sma5'] = talib.SMA(informative, timeperiod=5)
informative['sma5_pct'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5']
informative['sma5_diff_sum'] = (informative['sma5_pct'].rolling(5).sum()) / 5
informative['sma5_diff2_sum'] = informative['sma5_diff_sum'].diff()
sorted_close_prices = informative['close'].tail(365).sort_values()
lowest_4 = sorted_close_prices.head(4)
@@ -550,7 +602,6 @@ class Zeus_8_3_2_B_4_2(IStrategy):
informative['middle'] = informative['lowest_4'] + (informative['highest_4'] - informative['lowest_4']) / 2
informative['mid_min_max_0.98'] = informative['mid_min_max'] * 0.98
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
dataframe['count_buys'] = 0
@@ -769,7 +820,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# (dataframe['rsi_1h'] < 70)
# & (dataframe['rsi_diff_1h'] > -5)
# (dataframe["bb_width"] > 0.01)
(dataframe['down_count'].shift(1) < - 6)
(dataframe['down_count'].shift(1) < - 1)
& (dataframe['down_count'] == 0)
# & (dataframe['tendency'] != "B--")
# & (dataframe['tendency'] != "B-")
@@ -782,6 +833,13 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# & (dataframe['tendency'] != "B--")
# & (dataframe['tendency'] != "B-")
), ['enter_long', 'enter_tag']] = (1, 'low')
# dataframe.loc[
# (
# (dataframe['mid_smooth_deriv1'] > 0)
# & (dataframe['rsi'] < 50)
# & (dataframe['mid_smooth_deriv1'] > dataframe['mid_smooth_deriv1'].shift(1) * 1.5)
# ), ['enter_long', 'enter_tag']] = (1, 'mid')
dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.01, np.nan)
return dataframe
@@ -853,12 +911,16 @@ class Zeus_8_3_2_B_4_2(IStrategy):
) \
and (last_candle['rsi_diff_1h'] >= -5) \
and (last_candle['tendency'] in ('P', 'H++', 'DH', 'H+')) \
and ((pct_max < lim)):
and (last_candle['sma5_diff_sum_1d'] > -1 or count_of_buys <= 9) \
and (pct_max < lim):
try:
# print(self.adjust_stake_amount(pair, last_candle))
# print(pct_first)
# print(pct)
stake_amount = min(self.wallets.get_available_stake_amount(),
# and (last_candle['mid_smooth_deriv1_1d'] > -1000 or last_candle['mid_smooth_deriv1_1h'] > 200) \
# and (last_candle['mid_smooth_deriv1_1d'] > -1500) \
# and not (last_candle['mid_smooth_deriv1_1d'] < - 500 and last_candle['mid_smooth_deriv1_1h'] < 0) \
max_amount = self.config.get('stake_amount', 100) * 2.5
stake_amount = min(min(max_amount, self.wallets.get_available_stake_amount()),
self.adjust_stake_amount(pair, last_candle) - 10 * pct_first / pct) # min(200, self.adjust_stake_amount(pair, last_candle) * self.fibo[count_of_buys])
trade_type = last_candle['enter_tag'] if last_candle['enter_long'] == 1 else 'pct48'
@@ -975,7 +1037,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
first_price = last_candle['first_price']
first_max = (last_candle['max200'] - first_price) / first_price
expected_profit = min(0.01, first_max * 0.5)
expected_profit = min(0.01, first_max)
# print(
# f"Expected profit price={current_price:.4f} min_max={min_max:.4f} min_14={min_14_days:.4f} max_14={max_14_days:.4f} percent={percent:.4f} expected_profit={expected_profit:.4f}")
@@ -1350,6 +1412,25 @@ class Zeus_8_3_2_B_4_2(IStrategy):
print(f"update all col {col} {value}")
df[col] = value
def smooth_series(self, series, alpha_low=0.1, alpha_high=0.5, threshold=0.2):
"""
Applique un lissage adaptatif sur une série Pandas.
- alpha_low : lissage fort (forte inertie, pour petites variations)
- alpha_high : lissage faible (rapide réaction, pour grandes variations)
- threshold : variation (%) à partir de laquelle on considère le mouvement significatif
"""
smoothed = [series.iloc[0]]
for i in range(1, len(series)):
prev = smoothed[-1]
current = series.iloc[i]
variation = abs(current - prev) / prev * 100 if prev != 0 else 0
alpha = alpha_high if variation > threshold else alpha_low
new_val = prev + alpha * (current - prev)
smoothed.append(new_val)
return pd.Series(smoothed, index=series.index)
# def update_last_record(self, dataframe: DataFrame, new_data):
# # Vérifiez si de nouvelles données ont été reçues
# if new_data is not None:
@@ -1397,37 +1478,80 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe['close'].iloc[i - shift_value]
return down_pct_values
def apply_regression_derivatives(self, dataframe: DataFrame, column: str = 'close', window: int = 50, degree: int = 3):
# ✅ Première dérivée(variation ou pente)
# Positive: la courbe est croissante → tendance haussière.
# Négative: la courbe est décroissante → tendance baissière.
# Proche de 0: la courbe est plate → marché stable ou en transition.
#
# Applications:
# Détecter les points dinflexion(changement de tendance) quand elle sannule.\
# Analyser la vitesse dun mouvement(plus elle est forte, plus le mouvement est impulsif).
#
# ✅ Seconde dérivée(accélération ou concavité)
# Positive: la pente augmente → accélération de la hausse ou ralentissement de la baisse.
# Négative: la pente diminue → accélération de la baisse ou ralentissement de la hausse.
# Changement de signe: indique souvent un changement de courbure, utile pour prévoir des retournements.
#
# Exemples:
# 🟢 Dérivée 1 > 0 et dérivée 2 > 0: tendance haussière qui saccélère.
# 🟡 Dérivée 1 > 0 et dérivée 2 < 0: tendance haussière qui ralentit → essoufflement potentiel.
# 🔴 Dérivée 1 < 0 et dérivée 2 < 0: tendance baissière qui saccélère.
# 🟠 Dérivée 1 < 0 et dérivée 2 > 0: tendance baissière qui ralentit → possible bottom.
#
# Filtrer les signaux: ne prendre un signal haussier que si dérivée1 > 0 et dérivée2 > 0.
# Détecter les zones de retournement: quand dérivée1 ≈ 0 et que dérivée2 change de signe.
def apply_regression_derivatives(self,
dataframe: DataFrame,
column: str = 'close',
window: int = 50,
degree: int = 3,
future_offset: int = 10 # projection à n bougies après
) -> DataFrame:
df = dataframe.copy()
regression_fit = []
deriv1 = []
deriv2 = []
regression_future_fit = []
regression_future_deriv1 = []
regression_future_deriv2 = []
for i in range(len(df)):
if i < window:
if i < window or i + future_offset >= len(df):
regression_fit.append(np.nan)
deriv1.append(np.nan)
deriv2.append(np.nan)
regression_future_fit.append(np.nan)
regression_future_deriv1.append(np.nan)
regression_future_deriv2.append(np.nan)
continue
y = df[column].iloc[i - window:i].values
x = np.arange(window)
# Régression polynomiale
coeffs = np.polyfit(x, y, degree)
poly = np.poly1d(coeffs)
# Dérivées
d1 = np.polyder(poly, 1) # première dérivée
d2 = np.polyder(poly, 2) # seconde dérivée
x_now = window - 1
x_future = x_now + future_offset
# On calcule les valeurs de la dérivée à la dernière bougie
val_d1 = d1(window - 1)
val_d2 = d2(window - 1)
regression_fit.append(poly(x_now))
deriv1.append(np.polyder(poly, 1)(x_now))
deriv2.append(np.polyder(poly, 2)(x_now))
deriv1.append(val_d1)
deriv2.append(val_d2)
regression_future_fit.append(poly(x_future))
regression_future_deriv1.append(np.polyder(poly, 1)(x_future))
regression_future_deriv2.append(np.polyder(poly, 2)(x_future))
df['regression_fit'] = regression_fit
df['regression_deriv1'] = deriv1
df['regression_deriv2'] = deriv2
df['regression_future_fit'] = regression_future_fit
df['regression_future_deriv1'] = regression_future_deriv1
df['regression_future_deriv2'] = regression_future_deriv2
return df