Calcul 20240101-20250514 2635.892 199.501$ => 13,21 max 11 mises BTC / 14 mises DOGE

This commit is contained in:
Jérôme Delacotte
2025-07-15 20:42:52 +02:00
parent 501f5507ca
commit d1cf9ab72f
2 changed files with 390 additions and 189 deletions

View File

@@ -42,6 +42,7 @@ def normalize(df):
df = (df - df.min()) / (df.max() - df.min())
return 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 = 12 * 24 * 2
@@ -156,15 +157,19 @@ class Zeus_8_3_2_B_4_2(IStrategy):
pair: {
"first_buy": 0,
"last_max": 0,
"trade_info": {},
"max_touch": 0.0,
"last_min": 0.0,
"last_sell": 0.0,
"last_buy": 0.0,
'total_amount': 0.0,
'count_of_buys': 0,
'current_profit': 0,
'expected_profit': 0,
"last_candle": {},
"last_trade": None,
"last_count_of_buys": 0,
'base_stake_amount': 0,
'stop_buy': False,
'last_date': 0,
'stop': False,
'max_profit': 0,
@@ -201,27 +206,28 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# =========================================================================
# variables pour probabilité
# Bornes des quantiles pour
sma5_deriv1_1h = [-2.2582, -0.2665, -0.1475, -0.0860, -0.0428, -0.0084, 0.0244, 0.0592, 0.1038, 0.1656, 0.2766, 1.8331]
ema_volume = [-8.9178, -0.0196, -0.0096, -0.0053, -0.0026, -0.0007, 0.0009, 0.0029, 0.0056, 0.0101, 0.0200, 3.8009]
# Bornes des quantiles pour
mid_smooth_3_deriv1 = [-1.5837, -0.0765, -0.0451, -0.0280, -0.0155, -0.0046, 0.0058, 0.0167, 0.0298, 0.0472, 0.0785, 1.1362]
mid_smooth_1h_deriv1 = [-1.0482, -0.0571, -0.0336, -0.0206, -0.0113, -0.0033, 0.0044, 0.0127, 0.0225, 0.0356, 0.0591, 0.8335]
ema_volume_mid_smooth_1h_deriv1_matrice = {
'B5': [28.0, 32.8, 33.6, 36.4, 35.5, 35.6, 40.1, 40.9, 45.9, 49.7, 52.2],
'B4': [33.9, 37.2, 38.6, 40.7, 39.7, 43.0, 46.2, 47.1, 51.9, 55.9, 61.1],
'B3': [36.4, 41.3, 39.1, 41.8, 44.6, 46.1, 50.3, 47.9, 47.6, 57.0, 58.5],
'B2': [40.7, 40.6, 40.9, 44.6, 48.0, 48.4, 48.5, 53.5, 53.0, 54.8, 53.3],
'B1': [37.5, 41.4, 48.0, 46.3, 48.5, 49.1, 53.7, 53.4, 56.4, 56.7, 62.8],
'N0': [47.0, 44.3, 45.6, 47.0, 52.9, 52.2, 55.7, 53.0, 57.6, 58.1, 63.4],
'H1': [44.1, 46.2, 49.4, 49.3, 52.2, 53.7, 58.2, 57.1, 59.0, 61.6, 61.3],
'H2': [51.0, 44.7, 49.4, 51.3, 54.9, 57.9, 56.7, 58.1, 60.3, 60.6, 65.6],
'H3': [50.5, 48.3, 49.9, 60.4, 57.8, 56.3, 60.2, 61.9, 62.2, 65.3, 68.3],
'H4': [43.1, 53.6, 58.1, 61.4, 58.7, 62.6, 61.3, 65.4, 67.5, 68.2, 71.4],
'H5': [56.6, 56.2, 57.7, 63.8, 64.8, 64.7, 66.5, 68.8, 70.9, 72.8, 76.6],
sma5_deriv1_1h_mid_smooth_3_deriv1_matrice = {
'B5': [6.1, 11.7, 15.6, 20.6, 24.0, 26.0, 30.9, 40.7, 51.4, 54.9, 76.2],
'B4': [10.4, 13.2, 19.6, 22.7, 31.9, 36.8, 44.5, 50.8, 68.0, 74.6, 88.2],
'B3': [10.2, 16.7, 24.4, 25.1, 32.2, 42.6, 53.7, 60.0, 74.3, 78.8, 88.2],
'B2': [11.5, 18.0, 24.8, 29.1, 35.6, 44.9, 54.1, 66.4, 75.5, 81.3, 90.0],
'B1': [10.2, 18.8, 26.0, 31.6, 39.3, 48.7, 60.7, 71.4, 78.5, 83.4, 90.5],
'N0': [12.5, 22.6, 26.4, 34.3, 42.2, 56.8, 63.3, 71.4, 80.7, 83.3, 89.5],
'H1': [14.4, 24.5, 28.7, 40.0, 49.2, 60.2, 68.0, 72.3, 82.2, 83.4, 92.5],
'H2': [12.7, 26.3, 33.5, 42.6, 53.6, 61.9, 68.8, 75.1, 80.9, 83.8, 92.0],
'H3': [13.2, 26.9, 40.9, 46.8, 56.9, 65.7, 72.5, 75.8, 84.4, 86.9, 93.2],
'H4': [15.8, 31.3, 43.6, 49.9, 64.2, 68.6, 75.9, 77.0, 85.4, 88.9, 95.0],
'H5': [18.8, 39.1, 54.7, 64.0, 70.1, 79.6, 77.7, 81.8, 89.9, 89.4, 96.4]
}
sma5_deriv1_1h_mid_smooth_3_deriv1_matrice_df = pd.DataFrame(sma5_deriv1_1h_mid_smooth_3_deriv1_matrice, index=index_labels)
ema_volume_mid_smooth_1h_deriv1_matrice_df = pd.DataFrame(ema_volume_mid_smooth_1h_deriv1_matrice, index=index_labels)
# Extraction de la matrice numérique
sma5_deriv1_1h_mid_smooth_3_deriv1__numeric_matrice = sma5_deriv1_1h_mid_smooth_3_deriv1_matrice_df.reindex(index=ordered_labels, columns=ordered_labels).values
ema_volume_mid_smooth_1h_deriv1_numeric_matrice = ema_volume_mid_smooth_1h_deriv1_matrice_df.reindex(index=ordered_labels, columns=ordered_labels).values
# paliers = {}
@@ -231,6 +237,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# buy_mid_smooth_3_deriv1 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.06, space='buy')
# buy_mid_smooth_24_deriv1 = DecimalParameter(-0.6, 0, decimals=2, default=-0.03, space='buy')
buy_horizon_predict_1h = IntParameter(1, 6, default=2, space='buy')
# buy_level_predict_1h = IntParameter(2, 5, default=4, space='buy')
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str,
@@ -247,7 +254,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# val = self.getProbaHausse144(last_candle)
# allow_to_buy = True #(not self.stop_all) #& (not self.all_down)
allow_to_buy = not self.pairs[pair]['stop'] #and val > self.buy_val.value #not last_candle['tendency'] in ('B-', 'B--') # (rate <= float(limit)) | (entry_tag == 'force_entry')
allow_to_buy = not self.pairs[pair][
'stop'] # and val > self.buy_val.value #not last_candle['tendency'] in ('B-', 'B--') # (rate <= float(limit)) | (entry_tag == 'force_entry')
# if allow_to_buy:
# poly_func, x_future, y_future, count = self.polynomial_forecast(
@@ -306,13 +314,13 @@ class Zeus_8_3_2_B_4_2(IStrategy):
if allow_to_sell:
self.trades = list()
self.pairs[pair]['last_count_of_buys'] = trade.nr_of_successful_entries #self.pairs[pair]['count_of_buys']
self.pairs[pair]['last_count_of_buys'] = trade.nr_of_successful_entries # self.pairs[pair]['count_of_buys']
self.pairs[pair]['last_sell'] = rate
self.pairs[pair]['last_trade'] = trade
self.pairs[pair]['last_candle'] = last_candle
self.pairs[pair]['max_profit'] = 0
self.trades = list()
dispo= round(self.wallets.get_available_stake_amount())
dispo = round(self.wallets.get_available_stake_amount())
# print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} amount={amount} rate={rate} open_rate={trade.open_rate}")
self.log_trade(
last_candle=last_candle,
@@ -351,12 +359,15 @@ class Zeus_8_3_2_B_4_2(IStrategy):
last_candle_1h = dataframe.iloc[-13].squeeze()
before_last_candle = dataframe.iloc[-2].squeeze()
before_last_candle_2 = dataframe.iloc[-3].squeeze()
before_last_candle_12 = dataframe.iloc[-13].squeeze()
before_last_candle_24 = dataframe.iloc[-25].squeeze()
expected_profit = self.expectedProfit(pair, last_candle)
# print(f"current_time={current_time} current_profit={current_profit} expected_profit={expected_profit}")
max_touch_before = self.pairs[pair]['max_touch']
self.pairs[pair]['last_max'] = max(last_candle['haclose'], self.pairs[pair]['last_max'])
self.pairs[pair]['last_min'] = min(last_candle['haclose'], self.pairs[pair]['last_min'])
count_of_buys = trade.nr_of_successful_entries
@@ -375,11 +386,23 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# if (last_candle['sma20_deriv1'] < 0 and before_last_candle['sma20_deriv1'] >= 0) and (current_profit > expected_profit):
# return 'Drv_' + str(count_of_buys)
if 1 <= count_of_buys <= 3:
if ((before_last_candle_2['mid_smooth_3_deriv1'] <= before_last_candle['mid_smooth_3_deriv1'])
& (before_last_candle['mid_smooth_3_deriv1'] >= last_candle['mid_smooth_3_deriv1'])) \
and (current_profit > expected_profit):
return 'Drv3_' + pair + '_' + str(count_of_buys)
if ((before_last_candle_2['mid_smooth_3_deriv1'] <= before_last_candle['mid_smooth_3_deriv1'])
& (before_last_candle['mid_smooth_3_deriv1'] >= last_candle['mid_smooth_3_deriv1'])) \
and (current_profit > expected_profit):
return 'Drv_' + str(count_of_buys)
if 4 <= count_of_buys <= 6:
if ((before_last_candle_2['mid_smooth_12_deriv1'] <= before_last_candle['mid_smooth_12_deriv1'])
& (before_last_candle['mid_smooth_12_deriv1'] >= last_candle['mid_smooth_12_deriv1'])) \
and (current_profit > expected_profit):
return 'Drv13_' + pair + '_' + str(count_of_buys)
if 7 <= count_of_buys:
if ((before_last_candle_24['sma24_deriv1_1h'] <= before_last_candle_12['sma24_deriv1_1h'])
& (before_last_candle_12['sma24_deriv1_1h'] >= last_candle['sma24_deriv1_1h'])) \
and (current_profit > expected_profit):
return 'Drv24_' + pair + '_' + str(count_of_buys)
# if (baisse > mx) & (current_profit > expected_profit):
# self.trades = list()
@@ -410,7 +433,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
if pct <= thresholds[i]:
# interpolation linéaire entre thresholds[i-1] et thresholds[i]
return factors[i - 1] + (pct - thresholds[i - 1]) * (factors[i] - factors[i - 1]) / (
thresholds[i] - thresholds[i - 1])
thresholds[i] - thresholds[i - 1])
# Juste au cas où (devrait jamais arriver)
return factors[-1]
@@ -461,8 +484,15 @@ class Zeus_8_3_2_B_4_2(IStrategy):
last_lost = round((last_candle['haclose'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3)
max_touch = '' #round(last_candle['max12_1d'], 1) #round(self.pairs[pair]['max_touch'], 1)
pct_max = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3) # round(100 * self.pairs[pair]['current_profit'], 1)
if buys is None:
buys = ''
max_touch = '' # round(last_candle['max12_1d'], 1) #round(self.pairs[pair]['max_touch'], 1)
pct_max = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'],
3) # round(100 * self.pairs[pair]['current_profit'], 1)
total_counts = str(buys) + '/' + str(sum(pair_data['count_of_buys'] for pair_data in
self.pairs.values())) # if not pair in ('BTC/USDT', 'BTC/USDC'))
# if trade_type is not None:
# if np.isnan(last_candle['rsi_1d']):
@@ -481,8 +511,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.printLog(
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"| {int(self.pairs[pair]['last_max']) or '-':>7} |{buys or '-':>4}|{stake or '-':>7}"
f"|{last_candle['tendency_12'] or '-':>3}|" #{last_candle['tendency_1h'] or '-':>3}|{last_candle['tendency_1d'] or '-':>3}"
f"| {int(self.pairs[pair]['last_max']) or '-':>7} |{total_counts or '-':>4}|{stake or '-':>7}"
f"|{last_candle['tendency_12'] or '-':>3}|" # {last_candle['tendency_1h'] or '-':>3}|{last_candle['tendency_1d'] or '-':>3}"
# f"|{round(last_candle['mid_smooth_24_deriv1'],3) or '-':>6}|{round(last_candle['mid_smooth_1h_deriv1'],3) or '-':>6}|{round(last_candle['mid_smooth_deriv1_1d'],3) or '-' :>6}|"
# f"{round(last_candle['mid_smooth_24_deriv2'],3) or '-' :>6}|{round(last_candle['mid_smooth_1h_deriv2'],3) or '-':>6}|{round(last_candle['mid_smooth_deriv2_1d'],3) or '-':>6}|"
f"{round(val, 1) or '-' :>6}|"
@@ -494,7 +524,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.printLog(
f"+{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}+"
f"{'-' * 3}"
#"+{'-' * 3}+{'-' * 3}
# "+{'-' * 3}+{'-' * 3}
f"+{'-' * 6}+{'-' * 7}+{'-' * 7}+"
)
@@ -511,14 +541,14 @@ class Zeus_8_3_2_B_4_2(IStrategy):
d2 = row[f"mid_smooth{suffixe}_deriv2"]
d1_lim_inf = -0.01
d1_lim_sup = 0.01
if d1 >= d1_lim_inf and d1 <= d1_lim_sup: # and d2 >= d2_lim_inf and d2 <= d2_lim_sup:
return 'P' # Palier
if d1 >= d1_lim_inf and d1 <= d1_lim_sup: # and d2 >= d2_lim_inf and d2 <= d2_lim_sup:
return 'P' # Palier
if d1 == 0.0:
return 'DH' if d2 > 0 else 'DB' #Depart Hausse / Départ Baisse
return 'DH' if d2 > 0 else 'DB' # Depart Hausse / Départ Baisse
if d1 > d1_lim_sup:
return 'H++' if d2 > 0 else 'H+' #Acceleration Hausse / Ralentissement Hausse
return 'H++' if d2 > 0 else 'H+' # Acceleration Hausse / Ralentissement Hausse
if d1 < d1_lim_inf:
return 'B--' if d2 < 0 else 'B-' # Accéleration Baisse / Ralentissement Baisse
return 'B--' if d2 < 0 else 'B-' # Accéleration Baisse / Ralentissement Baisse
return 'Mid'
dataframe[f"tendency{suffixe}"] = dataframe.apply(tag_by_derivatives, axis=1)
@@ -532,6 +562,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe['haopen'] = heikinashi['open']
dataframe['haclose'] = heikinashi['close']
dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose']
dataframe['hapercent3'] = (dataframe['haclose'] - dataframe['haopen'].shift(3)) / dataframe['haclose'].shift(3)
dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5)
dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10)
@@ -547,7 +578,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe["percent12"] = (dataframe["close"] - dataframe["open"].shift(12)) / dataframe["open"].shift(12)
dataframe = self.calculateDerivation(dataframe, window=3, suffixe="_3")
dataframe["mid_re_smooth_3"] = self.conditional_smoothing(dataframe['mid_smooth_3'].dropna(), threshold=0.0005).dropna()
dataframe["mid_re_smooth_3"] = self.conditional_smoothing(dataframe['mid_smooth_3'].dropna(),
threshold=0.0005).dropna()
self.calculeDerivees(dataframe, "mid_re_smooth_3")
dataframe = self.calculateDerivation(dataframe, window=12, suffixe="_12")
dataframe = self.calculateDerivation(dataframe, window=24, suffixe="_24", factor_1=1000, factor_2=10)
@@ -583,9 +615,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# informative = self.calculateDerivation(informative, window=12)
# informative = self.apply_regression_derivatives(informative, column='mid', window=5, degree=4)
# 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']) #, timeperiod=7)
informative['volatility'] = talib.STDDEV(informative['close'], timeperiod=14) / informative['close']
self.calculeDerivees(informative, 'volatility')
informative['atr'] = (talib.ATR(informative['high'], informative['low'], informative['close'], timeperiod=14)) / \
informative['close']
self.calculeDerivees(informative, 'atr')
informative['rsi'] = talib.RSI(informative['close']) # , timeperiod=7)
informative['sma5'] = talib.SMA(informative, timeperiod=5)
informative['sma24'] = talib.SMA(informative, timeperiod=24)
self.calculeDerivees(informative, 'sma5')
@@ -611,6 +646,9 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# informative = self.apply_regression_derivatives(informative, column='mid', window=5, degree=4)
informative['max12'] = talib.MAX(informative['close'], timeperiod=12)
informative['max60'] = talib.MAX(informative['close'], timeperiod=60)
informative['min12'] = talib.MIN(informative['close'], timeperiod=12)
informative['min60'] = talib.MIN(informative['close'], timeperiod=60)
# informative['rsi'] = talib.RSI(informative['close']) #, timeperiod=7)
# self.calculeDerivees(informative, 'rsi')
@@ -619,7 +657,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
self.calculeDerivees(informative, 'sma5', factor_1=10, factor_2=1)
informative['futur_percent_3'] = 100 * ((informative['sma5'].shift(-3) - informative['sma5']) / informative['sma5'])
informative['futur_percent_3'] = 100 * (
(informative['sma5'].shift(-3) - informative['sma5']) / informative['sma5'])
# if self.dp.runmode.value in ('backtest'):
# print("##################")
@@ -655,11 +694,13 @@ class Zeus_8_3_2_B_4_2(IStrategy):
for buy in filled_buys:
if count == 0:
dataframe['first_price'] = buy.price
self.pairs[pair]['first_buy'] = buy.price
# dataframe['close01'] = buy.price * 1.01
# Order(id=2396, trade=1019, order_id=29870026652, side=buy, filled=0.00078, price=63921.01,
# status=closed, date=2024-08-26 02:20:11)
dataframe['last_price'] = buy.price
self.pairs[pair]['last_buy'] = buy.price
count = count + 1
amount += buy.price * buy.filled
# dataframe['mid_price'] = (dataframe['last_price'] + dataframe['first_price']) / 2
@@ -688,7 +729,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
horizon_h = 12
dataframe['sma5_1h'] = dataframe['sma5_1h'].rolling(window=horizon_h).mean()
# dataframe['sma5_deriv1_1h'] = dataframe['sma5_deriv1_1h'].rolling(window=horizon_h).mean()
# dataframe['ema_volume'] = dataframe['ema_volume'].rolling(window=horizon_h).mean()
# dataframe['sma24_1h'] = dataframe['sma24_1h'].rolling(window=horizon_h).mean()
# dataframe['sma24_deriv1_1h'] = dataframe['sma24_deriv1_1h'].rolling(window=horizon_h).mean()
@@ -701,8 +742,10 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# dataframe['smooth_24_deriv1'] = 100 * dataframe['smooth_24_deriv1'] / dataframe['mid_smooth_24']
# dataframe['smooth_24_deriv2'] = 100 * dataframe['smooth_24_deriv2'] / dataframe['mid_smooth_24']
dataframe['close_smooth'] = self.conditional_smoothing(dataframe['mid'].rolling(3).mean().dropna(), threshold=0.001)
dataframe['smooth'], dataframe['deriv1'], dataframe['deriv2'] = self.smooth_and_derivatives(dataframe['close_smooth'])
dataframe['close_smooth'] = self.conditional_smoothing(dataframe['mid'].rolling(3).mean().dropna(),
threshold=0.001)
dataframe['smooth'], dataframe['deriv1'], dataframe['deriv2'] = self.smooth_and_derivatives(
dataframe['close_smooth'])
dataframe['deriv1'] = 100 * dataframe['deriv1'] / dataframe['mid']
dataframe['deriv2'] = 100 * dataframe['deriv2'] / dataframe['mid']
@@ -724,7 +767,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
#
# horizon_h = 24 * 5
# dataframe['futur_percent_1h'] = 100 * ((dataframe['mid_smooth_1h'].shift(-12) - dataframe['mid_smooth_1h']) / dataframe['mid_smooth_1h']).rolling(horizon_h).mean()
# dataframe['futur_percent_3h'] = 100 * ((dataframe['mid_smooth_1h'].shift(-36) - dataframe['mid_smooth_1h']) / dataframe['mid_smooth_1h']).rolling(horizon_h).mean()
dataframe['futur_percent_3h'] = 100 * (
(dataframe['close'].shift(-36) - dataframe['close']) / dataframe['close']).rolling(horizon_h).mean()
# dataframe['futur_percent_5h'] = 100 * ((dataframe['mid_smooth_1h'].shift(-60) - dataframe['mid_smooth_1h']) / dataframe['mid_smooth_1h']).rolling(horizon_h).mean()
# dataframe['futur_percent_12h'] = 100 * ((dataframe['mid_smooth_1h'].shift(-144) - dataframe['mid_smooth_1h']) / dataframe['mid_smooth_1h']).rolling(horizon_h).mean()
#
@@ -733,13 +777,18 @@ class Zeus_8_3_2_B_4_2(IStrategy):
#
# self.calculateProbabilite2Index(dataframe, ['futur_percent_1d'], 'sma24_deriv1_1h', 'sma5_1d')
# if self.dp.runmode.value in ('backtest'):
# print("##################")
# print("# STAT DAY vs HOUR")
# print("##################")
# self.calculateProbabilite2Index(dataframe, futur_cols=['futur_percent_3_1h'], indic_1='sma5_deriv1_1h', indic_2='mid_smooth_3_deriv1')
dataframe['ema_volume'] = 20 * (dataframe['volume'] * dataframe['hapercent']) / (
abs(dataframe['volume'].shift(1)) + abs(dataframe['volume'].shift(2)))
dataframe['ema_volume'] = EMAIndicator(dataframe['volume'] * dataframe['hapercent'], window=5).ema_indicator()
self.calculeDerivees(dataframe, 'ema_volume', factor_1=10, factor_2=1)
if self.dp.runmode.value in ('backtest'):
print("##################")
print("# STAT DAY vs HOUR")
print("##################")
self.calculateProbabilite2Index(dataframe, futur_cols=['futur_percent_3h'], indic_1='ema_volume',
indic_2='mid_smooth_1h_deriv1')
dataframe['proba_hausse'] = dataframe.apply(lambda row: self.getProbaHausse(row), axis=1)
return dataframe
@@ -748,8 +797,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe[f"{indic}_deriv2"] = factor_2 * dataframe[f"{indic}_deriv1"].diff()
def calculateDownAndUp(self, dataframe, limit=0.0001):
dataframe['down'] = dataframe['mid_smooth_1h_deriv1'] < limit #dataframe['hapercent'] <= limit
dataframe['up'] = dataframe['mid_smooth_1h_deriv1'] > limit #dataframe['hapercent'] >= limit
dataframe['down'] = dataframe['mid_smooth_1h_deriv1'] < limit # dataframe['hapercent'] <= limit
dataframe['up'] = dataframe['mid_smooth_1h_deriv1'] > limit # dataframe['hapercent'] >= limit
dataframe['down_count'] = - dataframe['down'].astype(int) * (
dataframe['down'].groupby((dataframe['down'] != dataframe['down'].shift()).cumsum()).cumcount() + 1)
dataframe['up_count'] = dataframe['up'].astype(int) * (
@@ -763,10 +812,13 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# 1. Calcul du lissage par moyenne mobile médiane
dataframe[f"mid_smooth{suffixe}"] = dataframe['haclose'].rolling(window=window).mean()
# 2. Dérivée première = différence entre deux bougies successives
dataframe[f"mid_smooth{suffixe}_deriv1"] = round(factor_1 * dataframe[f"mid_smooth{suffixe}"].rolling(window=3).mean().diff() / dataframe[f"mid_smooth{suffixe}"], 4)
dataframe[f"mid_smooth{suffixe}_deriv1"] = round(
factor_1 * dataframe[f"mid_smooth{suffixe}"].rolling(window=3).mean().diff() / dataframe[
f"mid_smooth{suffixe}"], 4)
# 3. Dérivée seconde = différence de la dérivée première
dataframe[f"mid_smooth{suffixe}_deriv2"] = round(factor_2 * dataframe[f"mid_smooth{suffixe}_deriv1"].rolling(window=3).mean().diff(), 4)
dataframe[f"mid_smooth{suffixe}_deriv2"] = round(
factor_2 * dataframe[f"mid_smooth{suffixe}_deriv1"].rolling(window=3).mean().diff(), 4)
dataframe = self.add_tendency_column(dataframe, suffixe)
return dataframe
@@ -795,8 +847,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# & (dataframe['deriv2_1h'].shift(1) <= dataframe['deriv2_1h'])
# (dataframe['deriv1_1h'] >= -0.01)
# & (dataframe['deriv2_1h'] >= -0.00)
(dataframe['mid_smooth_3_deriv1'].shift(2) >= dataframe['mid_smooth_3_deriv1'].shift(1))
& (dataframe['mid_smooth_3_deriv1'].shift(1) <= dataframe['mid_smooth_3_deriv1'])
(dataframe['mid_smooth_3_deriv1'].shift(2) >= dataframe['mid_smooth_3_deriv1'].shift(1))
& (dataframe['mid_smooth_3_deriv1'].shift(1) <= dataframe['mid_smooth_3_deriv1'])
#
#
# (dataframe['mid_smooth_1h_deriv1'] >= 0)
@@ -806,6 +858,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
), ['enter_long', 'enter_tag']] = (1, 'smth')
dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.01, np.nan)
dataframe['perte_02'] = np.where((dataframe['hapercent3'] * 100 < -0.2), dataframe['close'], np.nan)
# self.paliers = self.get_dca_stakes()
@@ -912,8 +965,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
before_last_candle = dataframe.iloc[-2].squeeze()
last_candle_2 = dataframe.iloc[-3].squeeze()
before_last_candle_12 = dataframe.iloc[-13].squeeze()
before_last_candle_24 = dataframe.iloc[-25].squeeze()
last_candle_3 = dataframe.iloc[-4].squeeze()
last_candle_previous_1h = dataframe.iloc[-13].squeeze()
# prépare les données
@@ -930,6 +983,10 @@ class Zeus_8_3_2_B_4_2(IStrategy):
pair = trade.pair
pct_first = 0
total_counts = sum(
pair_data['count_of_buys'] for pair_data in self.pairs.values() if not pair in ('BTC/USDT', 'BTC/USDC'))
if self.pairs[pair]['first_buy']:
pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3)
@@ -938,14 +995,15 @@ class Zeus_8_3_2_B_4_2(IStrategy):
pct_max = current_profit
else:
if self.pairs[trade.pair]['last_buy']:
pct_max = round((last_candle['close'] - self.pairs[trade.pair]['last_buy']) / self.pairs[trade.pair]['last_buy'], 4)
pct_max = round(
(last_candle['close'] - self.pairs[trade.pair]['last_buy']) / self.pairs[trade.pair]['last_buy'], 4)
else:
pct_max = - pct
if pair in ('BTC/USDT', 'BTC/USDC') or count_of_buys <= 2:
lim = - pct - (count_of_buys * 0.001)
# lim = - (0.012 * (1 + round(count_of_buys / 5)) + 0.001 * (count_of_buys - 1))
#lim = - (0.012 + 0.001 * (count_of_buys - 1) + (0.002 * count_of_buys if count_of_buys > 10 else 0.001 * count_of_buys if count_of_buys > 5 else 0))
# lim = - (0.012 + 0.001 * (count_of_buys - 1) + (0.002 * count_of_buys if count_of_buys > 10 else 0.001 * count_of_buys if count_of_buys > 5 else 0))
else:
pct = 0.05
@@ -1067,13 +1125,14 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# > - 0.015 ==>Avg. stake amount 249.107 USDT │ Total trade volume 138186.861 USDT 275 │ 1.20 │ 901.976 │ 45.1 │ 1 day, 19:17:00 │ 274 0 1 99.6 │ 0.684 USDT 0.02%
condition = (last_candle['sma5_deriv1_1h'] > 0 or count_of_buys <= 5)
#last_candle['mid_smooth_1h_deriv1'] > - 0.05 #(last_candle['mid_smooth_3_deriv1'] > self.buy_mid_smooth_3_deriv1.value) and (last_candle['mid_smooth_24_deriv1'] > self.buy_mid_smooth_24_deriv1.value)
# (last_candle['enter_long'] == 1 & (count_of_buys < 3)) \
# or ((before_last_candle['mid_re_smooth_3_deriv1'] <= 0) & (last_candle['mid_re_smooth_3_deriv1'] >= 0) & (3 <= count_of_buys < 6)) \
# or ((before_last_candle['mid_smooth_1h_deriv1'] <= 0) & (last_candle['mid_smooth_1h_deriv1'] >= 0) & (6 <= count_of_buys))
# last_candle['mid_smooth_1h_deriv1'] > - 0.05 #(last_candle['mid_smooth_3_deriv1'] > self.buy_mid_smooth_3_deriv1.value) and (last_candle['mid_smooth_24_deriv1'] > self.buy_mid_smooth_24_deriv1.value)
# (last_candle['enter_long'] == 1 & (count_of_buys < 3)) \
# or ((before_last_candle['mid_re_smooth_3_deriv1'] <= 0) & (last_candle['mid_re_smooth_3_deriv1'] >= 0) & (3 <= count_of_buys < 6)) \
# or ((before_last_candle['mid_smooth_1h_deriv1'] <= 0) & (last_candle['mid_smooth_1h_deriv1'] >= 0) & (6 <= count_of_buys))
limit_buy = 20
if (count_of_buys < limit_buy) and condition and (pct_max < lim): # and val > self.buy_val_adjust.value and last_candle['mid_smooth_deriv1_1d'] > - 1):
if (count_of_buys < limit_buy) and condition and (
pct_max < lim): # and val > self.buy_val_adjust.value and last_candle['mid_smooth_deriv1_1d'] > - 1):
try:
# print(f"{trade.pair} current_profit={current_profit} count_of_buys={count_of_buys} pct_first={pct_first:.3f} pct_max={pct_max:.3f} lim={lim:.3f} index={index}")
# self.pairs[trade.pair]['last_palier_index'] = index
@@ -1090,7 +1149,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
max_amount = self.config.get('stake_amount') * 2.5
# stake_amount = min(stake_amount, self.wallets.get_available_stake_amount())
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])
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'
self.pairs[trade.pair]['count_of_buys'] += 1
@@ -1118,7 +1178,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# print(f" {key:20}: {value}")
df = pd.DataFrame.from_dict(self.pairs, orient='index')
colonnes_a_exclure = ['last_candle', 'last_trade', 'last_palier_index', 'stop']
colonnes_a_exclure = ['last_candle', 'last_trade', 'last_palier_index', 'stop',
'trade_info', 'last_date', 'expected_profit', 'last_count_of_buys', 'base_stake_amount', 'stop_buy']
df_filtered = df[df['count_of_buys'] > 0].drop(columns=colonnes_a_exclure)
# df_filtered = df_filtered["first_buy", "last_max", "max_touch", "last_sell","last_buy", 'count_of_buys', 'current_profit']
@@ -1175,21 +1236,24 @@ class Zeus_8_3_2_B_4_2(IStrategy):
return None
def getProbaHausse(self, last_candle):
value_1 = self.getValuesFromTable(self.sma5_deriv1_1h, last_candle['sma5_deriv1_1h'])
value_2 = self.getValuesFromTable(self.mid_smooth_3_deriv1, last_candle['mid_smooth_3_deriv1'])
value_1 = self.getValuesFromTable(self.ema_volume, last_candle['ema_volume'])
value_2 = self.getValuesFromTable(self.mid_smooth_1h_deriv1, last_candle['mid_smooth_1h_deriv1'])
val = self.approx_val_from_bins(
matrice=self.sma5_deriv1_1h_mid_smooth_3_deriv1_matrice_df,
numeric_matrice=self.sma5_deriv1_1h_mid_smooth_3_deriv1__numeric_matrice,
row_label=value_1,
col_label=value_2
matrice=self.ema_volume_mid_smooth_1h_deriv1_matrice_df,
numeric_matrice=self.ema_volume_mid_smooth_1h_deriv1_numeric_matrice,
row_label=value_2,
col_label=value_1
)
return val
def adjust_stake_amount(self, pair: str, last_candle: DataFrame):
# Calculer le minimum des 14 derniers jours
base_stake_amount = self.config.get('stake_amount') # Montant de base configuré
if not pair.startswith('BTC'):
factors = [1, 1.25, 1.5, 2.0]
if not pair in ('BTC/USDT', 'BTC/USDC'):
factors = [1, 1.2, 1.3, 1.4]
base_stake_amount = base_stake_amount * 0.75
first_price = self.pairs[pair]['first_buy']
@@ -1201,17 +1265,20 @@ class Zeus_8_3_2_B_4_2(IStrategy):
if last_max > 0:
pct = 100 * (last_max - first_price) / last_max
thresholds = [2, 5, 10, 20]
factors = [1, 1.25, 1.5, 2.0]
factor = self.multi_step_interpolate(pct, thresholds, factors)
adjusted_stake_amount = base_stake_amount * factor #max(base_stake_amount, min(100, base_stake_amount * percent_4))
adjusted_stake_amount = base_stake_amount * factor # max(base_stake_amount, min(100, base_stake_amount * percent_4))
return adjusted_stake_amount
def expectedProfit(self, pair: str, last_candle: DataFrame):
expected_profit = 0.004 #min(0.01, first_max)
count_of_buys = self.pairs[pair]['count_of_buys']
pct_first = round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3)
expected_profit = max(0.004, abs(
pct_first / 3)) # 0.004 + 0.002 * self.pairs[pair]['count_of_buys'] #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}")
@@ -1250,12 +1317,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# 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 calculateRegression(self,
dataframe: DataFrame,
column= 'close',
window= 50,
degree=3,
future_offset: int = 10 # projection à n bougies après
) -> DataFrame:
dataframe: DataFrame,
column='close',
window=50,
degree=3,
future_offset: int = 10 # projection à n bougies après
) -> DataFrame:
df = dataframe.copy()
regression_fit = []
@@ -1298,10 +1365,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
df[f"{column}_regression"] = regression_fit
# 2. Dérivée première = différence entre deux bougies successives
df[f"{column}_regression_deriv1"] = round(100 * df[f"{column}_regression"].diff() / df[f"{column}_regression"], 4)
df[f"{column}_regression_deriv1"] = round(100 * df[f"{column}_regression"].diff() / df[f"{column}_regression"],
4)
# 3. Dérivée seconde = différence de la dérivée première
df[f"{column}_regression_deriv2"] = round(10 * df[f"{column}_regression_deriv1"].rolling(int(window / 4)).mean().diff(), 4)
df[f"{column}_regression_deriv2"] = round(
10 * df[f"{column}_regression_deriv1"].rolling(int(window / 4)).mean().diff(), 4)
df[f"{column}_future_{future_offset}"] = regression_future_fit
@@ -1395,7 +1464,6 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# Approximation directe (aucune interpolation complexe ici, juste une lecture)
return numeric_matrice[row_idx, col_idx]
@property
def protections(self):
return [
@@ -1460,7 +1528,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
deriv1 = np.diff(smooth, prepend=smooth[0])
deriv2 = np.diff(deriv1, prepend=deriv1[0])
return pd.Series(smooth, index=series.index), pd.Series(deriv1, index=series.index), pd.Series(deriv2, index=series.index)
return pd.Series(smooth, index=series.index), pd.Series(deriv1, index=series.index), pd.Series(deriv2,
index=series.index)
def causal_savgol(self, series, window=25, polyorder=3):
result = []
@@ -1478,7 +1547,6 @@ class Zeus_8_3_2_B_4_2(IStrategy):
result.append(poly(window - 1))
return pd.Series(result, index=series.index)
def get_stake_from_drawdown(self, pct: float, base_stake: float = 100.0, step: float = 0.04, growth: float = 1.15,
max_stake: float = 1000.0) -> float:
"""
@@ -1498,7 +1566,8 @@ class Zeus_8_3_2_B_4_2(IStrategy):
stake = base_stake * (growth ** level)
return min(stake, max_stake)
def compute_adaptive_paliers(self, max_drawdown: float = 0.65, first_steps: list[float] = [0.01, 0.01, 0.015, 0.02], growth: float = 1.2) -> list[float]:
def compute_adaptive_paliers(self, max_drawdown: float = 0.65, first_steps: list[float] = [0.01, 0.01, 0.015, 0.02],
growth: float = 1.2) -> list[float]:
"""
Génère une liste de drawdowns négatifs avec des paliers plus rapprochés au début.
@@ -1577,19 +1646,19 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# def get_active_stake(self, pct: float) -> float:
# """
# Renvoie la mise correspondant au drawdown `pct`.
#
#
# :param pct: drawdown courant (négatif, ex: -0.043)
# :param paliers: liste de tuples (drawdown, stake)
# :return: stake correspondant
# """
# abs_pct = abs(pct)
# stake = self.paliers[0][1] # stake par défaut
#
#
# for palier, s in self.paliers:
# if abs_pct >= abs(palier):
# stake = s
# else:
# break
# break
#
# return stake
@@ -1632,7 +1701,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
#
# return result
def polynomial_forecast(self, series: pd.Series, window: int = 20, degree: int = 2, steps = [12, 24, 36]):
def polynomial_forecast(self, series: pd.Series, window: int = 20, degree: int = 2, steps=[12, 24, 36]):
"""
Calcule une régression polynomiale sur les `window` dernières valeurs de la série,
puis prédit les `n_future` prochaines valeurs.
@@ -1661,14 +1730,14 @@ class Zeus_8_3_2_B_4_2(IStrategy):
current = series.iloc[-1]
count = 0
for future_step in steps: #range(1, n_future + 1)
for future_step in steps: # range(1, n_future + 1)
future_x = window - 1 + future_step
prediction = poly(future_x)
# series.loc[series.index[future_x], f'poly_pred_t+{future_step}'] = prediction
# Afficher les prédictions
# print(f"{current} → t+{future_step}: x={future_x}, y={prediction:.2f}")
if prediction > 0: #current:
if prediction > 0: # current:
count += 1
return poly, x_future, y_future, count
@@ -1736,7 +1805,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# Compter les positions actives sur les paires non-BTC
max_nb_trades = 0
total_non_btc = 0
max_pair = ''
max_pair = ''
for p in non_btc_pairs:
max_nb_trades = max(max_nb_trades, self.pairs[p]['count_of_buys'])
if (max_nb_trades == self.pairs[p]['count_of_buys'] and max_nb_trades > limit):
@@ -1750,7 +1819,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
# return False
if max_pair != '':
#if this_pair_count >= limit:
# if this_pair_count >= limit:
# Si une autre paire non-BTC a aussi >3 trades, blocage
# if max_pair == pair:
# print(f"{pair} Cette paire {max_pair} est la seule avec >=3 / {max_nb_trades}")