From 014996f0ab8bd29274ef8fccd9df2830d6a2ca0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Delacotte?= Date: Mon, 5 May 2025 20:34:38 +0200 Subject: [PATCH] =?UTF-8?q?Calcul=20probabilit=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Zeus_8_3_2_B_4_2.py | 147 ++++++++++++++++++++++++++++++++------------ 1 file changed, 107 insertions(+), 40 deletions(-) diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index 0a0c8bd..f37b008 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -86,23 +86,33 @@ class Zeus_8_3_2_B_4_2(IStrategy): "color": "#da59a6"}, "bb_upperband": { "color": "#da59a6", + }, + "sma10": { + "color": "blue" + }, + "sma5_1h": { + "color": "red" } + }, "subplots": { "Pct": { "sma20_pct": { 'color': "green" + }, + "down_pct": { + "color": "blue" + }, + "down_pct_1h": { + "color": "red" } }, "Rsi": { - "rsi60": { - "color": "red" + "rsi": { + "color": "pink" }, - 'rsi60_diff': { + "rsi_1h": { "color": "blue" - }, - 'rsi60_diff2': { - 'color': "green" } }, "Rsi_diff": { @@ -111,8 +121,21 @@ class Zeus_8_3_2_B_4_2(IStrategy): }, "rsi_diff_2_1h": { "color": "blue" + }, + }, + "Down": { + "down_count_1h": { + "color": "green" + }, + "up_count_1h": { + "color": "blue" } }, + # "Diff": { + # "sma10_diff": { + # "color": "#74effc" + # } + # }, "smooth": { 'sma5_diff_sum_1h': { "color": "green" @@ -120,15 +143,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): 'sma5_diff2_sum_1h': { "color": "blue" }, - # 'mid_smooth_deriv1': { - # "color": "blue" - # }, + 'mid_smooth_deriv1_1d': { + "color": "blue" + }, 'mid_smooth_deriv1_1h': { "color": "red" }, - # 'mid_smooth_deriv2': { - # "color": "pink" - # }, + 'mid_smooth_deriv2_1d': { + "color": "pink" + }, 'mid_smooth_deriv2_1h': { "color": "#da59a6" } @@ -207,11 +230,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): self.pairs[pair]['count_of_buys'] = 1 self.pairs[pair]['current_profit'] = 0 - self.printLog( - f"|{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}" - f"+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}|" - - ) + self.printLineLog() stake_amount = self.adjust_stake_amount(pair, last_candle) @@ -366,11 +385,11 @@ 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':>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}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}|" + 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} |" + f"Tdc|Tdh|Tdd|Tdc|Tdh|Tdd|" ) + self.printLineLog() + self.columns_logged += 1 date = str(date)[:16] if date else "-" limit = None @@ -415,7 +434,13 @@ class Zeus_8_3_2_B_4_2(IStrategy): 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}|{round(last_candle['mid_smooth_deriv1_1d']):>5}|" + f"|{round(last_candle['mid_smooth_deriv1']) or '-':>3}|{round(last_candle['mid_smooth_deriv1_1h']) or '-':>5}|{round(last_candle['mid_smooth_deriv1_1d']) or '-' :>5}" + # f"|{round(last_candle['mid_smooth_deriv2']) or '-' :>3 }|{round(last_candle['mid_smooth_deriv2_1h']) or '-':>5}|{round(last_candle['mid_smooth_deriv2_1d']) or '-':>5}" + ) + + def printLineLog(self): + self.printLog( + f"+{'-' * 18}+{'-' * 12}+{'-' * 5}+{'-' * 20}+{'-' * 9}+{'-' * 8}+{'-' * 10}+{'-' * 8}+{'-' * 13}+{'-' * 14}+{'-' * 9}+{'-' * 4}+{'-' * 7}+" ) def printLog(self, str): @@ -452,8 +477,6 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['haclose'] = heikinashi['close'] dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] - dataframe['close_02'] = dataframe['haclose'] * 1.02 - dataframe['pct_change'] = dataframe['close'].pct_change(5) dataframe = self.calculateTendency(dataframe) @@ -474,6 +497,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) + dataframe['sma10_diff'] = 100 * dataframe['sma10'].diff() / dataframe['sma10'] 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() @@ -533,28 +557,24 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['highest_4_average'] = highest_4.mean() # Compter les baisses consécutives - dataframe['down'] = dataframe['hapercent'] <= 0.0001 - dataframe['up'] = dataframe['hapercent'] >= 0.0001 - 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) * ( - dataframe['up'].groupby((dataframe['up'] != dataframe['up'].shift()).cumsum()).cumcount() + 1) - dataframe['down_tag'] = (dataframe['down_count'] < -7) - dataframe['up_tag'] = (dataframe['up_count'] > 7) - # Créer une colonne vide - dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count') - dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count') + self.calculateDownAndUp(dataframe, limit=0.0001) + 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") + heikinashi = qtpylib.heikinashi(informative) + informative['haopen'] = heikinashi['open'] + informative['haclose'] = heikinashi['close'] + informative['hapercent'] = (informative['haclose'] - informative['haopen']) / informative['haclose'] + informative = self.calculateTendency(informative, 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'] = talib.RSI(informative['close']) #, timeperiod=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() @@ -565,6 +585,11 @@ class Zeus_8_3_2_B_4_2(IStrategy): informative['sma5_diff_sum'] = (informative['sma5_pct'].rolling(5).sum()) / 5 informative['sma5_diff2_sum'] = informative['sma5_diff_sum'].diff() + self.calculateDownAndUp(informative, limit=0.0012) + + if self.dp.runmode.value in ('backtest'): + self.test_signal_success(informative, percent=0.01, window_size=24) + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) ################### INFORMATIVE 1d @@ -572,7 +597,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): informative = self.calculateTendency(informative, 3) informative = self.apply_regression_derivatives(informative, column='mid', window=5, degree=3) - informative['rsi'] = talib.RSI(informative['close'], length=7) + informative['rsi'] = talib.RSI(informative['close']) #, timeperiod=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() @@ -713,16 +738,29 @@ class Zeus_8_3_2_B_4_2(IStrategy): # self.getBinanceOrderBook(pair, dataframe) + # if self.dp.runmode.value in ('backtest'): + # self.test_signal_success(dataframe, 0.005) + return dataframe + def calculateDownAndUp(self, dataframe, limit=0.0001): + dataframe['down'] = dataframe['hapercent'] <= limit + dataframe['up'] = 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) * ( + dataframe['up'].groupby((dataframe['up'] != dataframe['up'].shift()).cumsum()).cumcount() + 1) + dataframe['down_tag'] = (dataframe['down_count'] < -7) + dataframe['up_tag'] = (dataframe['up_count'] > 7) + # Créer une colonne vide + dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count') + dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count') + def calculateTendency(self, dataframe, window=12): dataframe['mid'] = dataframe['open'] + (dataframe['close'] - dataframe['open']) / 2 # 2. Calcul du lissage sur 200 bougies par moyenne mobile médiane dataframe['mid_smooth'] = dataframe['mid'].rolling(window=window, center=True, min_periods=1).median().rolling( 3).mean() - dataframe['mid_smooth_tag_max'] = (dataframe['mid_smooth'].shift(1)) == 0 & (dataframe['mid_smooth'] < 0) - dataframe['mid_smooth_tag_min'] = (dataframe['mid_smooth'].shift(1)) == 0 & (dataframe['mid_smooth'] > 0) - # 2. Dérivée première = différence entre deux bougies successives dataframe['mid_smooth_deriv1'] = round(100000 * dataframe['mid_smooth'].pct_change(), 2) # 3. Dérivée seconde = différence de la dérivée première @@ -1553,5 +1591,34 @@ class Zeus_8_3_2_B_4_2(IStrategy): return df + def test_signal_success(self, df, percent=0.03, window_size=36): + """ + df : DataFrame avec colonnes ['close', 'high', ...] + percent : hausse recherchée (ex: 0.03 pour +3%) + window_size : nombre de bougies (ex: 36 pour 3h en 5m) + """ + # Exemple condition : RSI < 30 et EMA20 > SMA50 + condition = (df['down_count'] == 0) & (df['down_count'].shift(1) < 0) & (df['down_pct'].shift(1) < -3) + + hits = 0 + total = 0 + + for idx in df[condition].index: + price_now = df.loc[idx, 'close'] + idx_pos = df.index.get_loc(idx) + + # Fenêtre de h heures + future_idx = df.index[idx_pos + 1: idx_pos + 1 + window_size] + if len(future_idx) < window_size: + continue + + future_highs = df.loc[future_idx, 'high'] + if (future_highs >= price_now * (1 + percent)).any(): + hits += 1 + total += 1 + + prob = hits / total if total > 0 else 0 + print(f"✅ {hits}/{total} hausses >= {percent*100:.1f}% dans {window_size} bougies → probabilité : {prob:.2%}") + return prob