diff --git a/Zeus_8_3_2_B_4_2.py b/Zeus_8_3_2_B_4_2.py index c44f67c..6df0452 100644 --- a/Zeus_8_3_2_B_4_2.py +++ b/Zeus_8_3_2_B_4_2.py @@ -48,10 +48,13 @@ from sklearn.metrics import ( accuracy_score, roc_auc_score, roc_curve, + precision_score, recall_score, precision_recall_curve, + f1_score ) from sklearn.tree import export_text import inspect - +from sklearn.feature_selection import mutual_info_classif +from sklearn.inspection import permutation_importance from tabulate import tabulate @@ -77,7 +80,19 @@ def normalize(df): class Zeus_8_3_2_B_4_2(IStrategy): # Machine Learning model = joblib.load('rf_model.pkl') - model_indicators = ['rsi_deriv1', "max_rsi_12", "mid_smooth_5_deriv1", "volume_deriv1"] + model_indicators = [ + 'rsi', 'rsi_deriv1', "max_rsi_12", + "bb_percent", + 'vol_24', + 'percent3', + 'sma5_dist', 'sma5_deriv1', + 'sma24_dist', 'sma24_deriv1', + 'sma60_dist', 'sma60_deriv1', + 'down_count', 'up_count', + 'down_pct', 'slope_norm', + 'min_max_60', + 'rsi_slope', 'adx_change', 'volatility_ratio' + ] levels = [1, 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] # startup_candle_count = 12 * 24 * 5 @@ -286,12 +301,12 @@ class Zeus_8_3_2_B_4_2(IStrategy): pct_inc = DecimalParameter(0.0001, 0.003, default=0.0022, decimals=4, space='buy', optimize=True, load=True) 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_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_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_deriv_5m_slop_inf_buy = CategoricalParameter(indicators, default="sma12", space='buy', optimize=True, load=True) + # deriv_5m_slope_inf_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) @@ -392,7 +407,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): condition = True #(last_candle[f"{indic_5m}_deriv1"] >= indic_deriv1_5m) and (last_candle[f"{indic_5m}_deriv2"] >= indic_deriv2_5m) # allow_to_buy = True #(not self.stop_all) #& (not self.all_down) - # and val > self.buy_val.value #not last_candle['tendency'] in ('B-', 'B--') # (rate <= float(limit)) | (entry_tag == 'force_entry') + # and val > self.buy_val.value #not last_candle['tendency'] in (-1, -2) # (rate <= float(limit)) | (entry_tag == 'force_entry') allow_to_buy = (condition and not self.pairs[pair]['stop']) | (entry_tag == 'force_entry') # if allow_to_buy: @@ -562,7 +577,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # if (last_candle['mid_smooth_deriv1'] >= 0): # return None - # if (last_candle['tendency'] in ('H++', 'H+')) and (last_candle['rsi'] < 80): + # if (last_candle['tendency'] in (2, 1)) and (last_candle['rsi'] < 80): # return None # # if (last_candle['sma24_deriv1'] < 0 and before_last_candle['sma24_deriv1'] >= 0) and (current_profit > expected_profit): @@ -573,7 +588,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): # trend = last_candle['trend_class_1d'] # 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'] == 'H+' 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'] == 1 and profit > max(5, expected_profit) and (last_candle['hapercent'] < 0): # self.pairs[pair]['stop'] = True # self.log_trade( # last_candle=last_candle, @@ -854,11 +869,11 @@ class Zeus_8_3_2_B_4_2(IStrategy): # On considère les petites valeurs comme zéro if abs(d1) < eps: - return 'P' # Palier / neutre + return 0 # Palier / neutre if d1 > d1_lim_sup: - return 'H++' if d2 > eps else 'H+' # Acceleration Hausse / Ralentissement Hausse + return 2 if d2 > eps else 1 # Acceleration Hausse / Ralentissement Hausse if d1 < d1_lim_inf: - return 'B--' if d2 < -eps else 'B-' # Acceleration Baisse / Ralentissement Baisse + return -2 if d2 < -eps else -1 # Acceleration Baisse / Ralentissement Baisse if abs(d1) < eps: return 'DH' if d2 > eps else 'DB' # Depart Hausse / Depart Baisse return 'Mid' @@ -874,13 +889,13 @@ class Zeus_8_3_2_B_4_2(IStrategy): # 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 + # return 0 # Palier # if d1 == 0.0: # 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 2 if d2 > 0 else 1 # Acceleration Hausse / Ralentissement Hausse # if d1 < d1_lim_inf: - # return 'B--' if d2 < 0 else 'B-' # Accéleration Baisse / Ralentissement Baisse + # return -2 if d2 < 0 else -1 # Accéleration Baisse / Ralentissement Baisse # return 'Mid' # # dataframe[f"tendency{suffixe}"] = dataframe.apply(tag_by_derivatives, axis=1) @@ -898,6 +913,19 @@ class Zeus_8_3_2_B_4_2(IStrategy): ################### INFORMATIVE 1h informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") informative = self.populateDataframe(informative, timeframe='1h') + # informative['target_value'] = informative['sma5'].shift(-6).rolling(5).max() - informative['sma5'] * 1.005 + # if self.dp.runmode.value in ('backtest'): + # self.trainModel(informative, metadata) + # + # # Préparer les features pour la prédiction + # features = informative[self.model_indicators].fillna(0) + # + # # Prédiction : probabilité que le prix monte + # probs = self.model.predict_proba(features)[:, 1] + # + # # Sauvegarder la probabilité pour l’analyse + # informative['ml_prob'] = probs + dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) ################### INFORMATIVE 1d @@ -953,9 +981,6 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['mid_smooth_5h'] dataframe["mid_smooth_5h_deriv2"] = 100 * dataframe["mid_smooth_5h_deriv1"].diff().rolling(window=60).mean() - # Compter les baisses / hausses consécutives - # self.calculateDownAndUp(dataframe, limit=0.0001) - # =============================== # Lissage des valeurs Journalières horizon_d = 12 * 5 * 24 @@ -1030,29 +1055,36 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['stop_buying'] = latched - self.trainModel(dataframe, metadata) + if self.dp.runmode.value in ('backtest'): + self.trainModel(dataframe, metadata) # Préparer les features pour la prédiction features = dataframe[self.model_indicators].fillna(0) # Prédiction : probabilité que le prix monte - # probs = self.model.predict_proba(features)[:, 1] + probs = self.model.predict_proba(features)[:, 1] # Sauvegarder la probabilité pour l’analyse - # dataframe['ml_prob'] = probs + dataframe['ml_prob'] = probs - # self.inspect_model(self.model) + self.inspect_model(self.model) return dataframe def trainModel(self, dataframe: DataFrame, metadata: dict): df = dataframe.copy() # 3️⃣ Créer la cible : 1 si le prix monte dans les prochaines bougies - df['target'] = (1000 * (df['sma24'].shift(-24) - df['sma24'])) #.astype(int) + # df['target'] = (df['sma24'].shift(-24) > df['sma24']).astype(int) + df['target'] = (df['sma5'].shift(-12).rolling(12).max() > df['sma5'] * 1.00025).astype(int) + df['target'] = df['target'].fillna(0).astype(int) # Nettoyage df = df.dropna() + X = df[self.model_indicators] + y = df['target'] # ta colonne cible binaire ou numérique + print(self.feature_auc_scores(X, y)) + # 4️⃣ Split train/test X = df[self.model_indicators] y = df['target'] @@ -1060,39 +1092,50 @@ class Zeus_8_3_2_B_4_2(IStrategy): # 5️⃣ Entraînement du modèle # train_model = RandomForestClassifier(n_estimators=200, random_state=42) - # train_model = RandomForestClassifier( - # n_estimators=300, - # max_depth=12, - # min_samples_split=4, - # min_samples_leaf=2, - # max_features='sqrt', - # random_state=42, - # n_jobs=-1 - # ) - train_model = RandomForestRegressor( + train_model = RandomForestClassifier( n_estimators=300, - max_depth=None, - random_state=42, - n_jobs=-1 + max_depth=12, + # min_samples_split=4, + # min_samples_leaf=2, + # max_features='sqrt', + # random_state=42, + # n_jobs=-1, + class_weight='balanced' ) train_model.fit(X_train, y_train) # 6️⃣ Évaluer la précision (facultatif) preds = train_model.predict(X_test) - # acc = accuracy_score(y_test, preds) - # print(f"Accuracy: {acc:.3f}") + acc = accuracy_score(y_test, preds) + print(f"Accuracy: {acc:.3f}") # 7️⃣ Sauvegarde du modèle joblib.dump(train_model, 'rf_model.pkl') print("✅ Modèle sauvegardé sous rf_model.pkl") - y_pred = train_model.predict(X_test) + # X = dataframe des features (après shift/rolling/indicators) + # y = target binaire ou décimale + # model = ton modèle entraîné (RandomForestClassifier ou Regressor) - print("R² :", r2_score(y_test, y_pred)) - print("RMSE :", mean_squared_error(y_test, y_pred)) #, squared=False)) - print("MAE :", mean_absolute_error(y_test, y_pred)) + # # --- 1️⃣ Mutual Information (MI) --- + # mi_scores = mutual_info_classif(X.fillna(0), y) + # mi_series = pd.Series(mi_scores, index=X.columns, name='MI') + # + # # --- 2️⃣ Permutation Importance (PI) --- + # pi_result = permutation_importance(train_model, X, y, n_repeats=10, random_state=42, n_jobs=-1) + # pi_series = pd.Series(pi_result.importances_mean, index=X.columns, name='PI') + # + # # --- 3️⃣ Combinaison dans un seul dataframe --- + # importance_df = pd.concat([mi_series, pi_series], axis=1) + # importance_df = importance_df.sort_values(by='PI', ascending=False) # tri par importance modèle + # print(importance_df) + # + # importance_df.plot(kind='bar', figsize=(10, 5)) + # plt.title("Mutual Info vs Permutation Importance") + # plt.ylabel("Score") + # plt.show() - # self.analyze_model(train_model, X_train, X_test, y_train, y_test) + self.analyze_model(train_model, X_train, X_test, y_train, y_test) def inspect_model(self, model): """ @@ -1252,39 +1295,138 @@ class Zeus_8_3_2_B_4_2(IStrategy): plt.savefig(os.path.join(output_dir, "Courbe ROC.png"), bbox_inches="tight") plt.close() - # ---- Interprétation SHAP (optionnelle) ---- - try: - import shap + # # ---- Interprétation SHAP (optionnelle) ---- + # try: + # import shap + # + # print("\n===== 💡 ANALYSE SHAP =====") + # explainer = shap.TreeExplainer(model) + # shap_values = explainer.shap_values(X_test) + # # shap.summary_plot(shap_values[1], X_test) + # # Vérifie le type de sortie de shap_values + # if isinstance(shap_values, list): + # # Cas des modèles de classification (plusieurs classes) + # shap_values_to_plot = shap_values[0] if len(shap_values) == 1 else shap_values[1] + # else: + # shap_values_to_plot = shap_values + # + # # Ajustement des dimensions au besoin + # if shap_values_to_plot.shape[1] != X_test.shape[1]: + # print(f"⚠️ Mismatch dimensions SHAP ({shap_values_to_plot.shape[1]}) vs X_test ({X_test.shape[1]})") + # min_dim = min(shap_values_to_plot.shape[1], X_test.shape[1]) + # shap_values_to_plot = shap_values_to_plot[:, :min_dim] + # X_to_plot = X_test.iloc[:, :min_dim] + # else: + # X_to_plot = X_test + # + # plt.figure(figsize=(12, 4)) + # shap.summary_plot(shap_values_to_plot, X_to_plot, show=False) + # plt.savefig(os.path.join(output_dir, "shap_summary.png"), bbox_inches="tight") + # plt.close() + # except ImportError: + # print("\n(SHAP non installé — `pip install shap` pour activer l’analyse SHAP.)") - print("\n===== 💡 ANALYSE SHAP =====") - explainer = shap.TreeExplainer(model) - shap_values = explainer.shap_values(X_test) - # shap.summary_plot(shap_values[1], X_test) - # Vérifie le type de sortie de shap_values - if isinstance(shap_values, list): - # Cas des modèles de classification (plusieurs classes) - shap_values_to_plot = shap_values[0] if len(shap_values) == 1 else shap_values[1] - else: - shap_values_to_plot = shap_values + y_proba = model.predict_proba(X_test)[:, 1] - # Ajustement des dimensions au besoin - if shap_values_to_plot.shape[1] != X_test.shape[1]: - print(f"⚠️ Mismatch dimensions SHAP ({shap_values_to_plot.shape[1]}) vs X_test ({X_test.shape[1]})") - min_dim = min(shap_values_to_plot.shape[1], X_test.shape[1]) - shap_values_to_plot = shap_values_to_plot[:, :min_dim] - X_to_plot = X_test.iloc[:, :min_dim] - else: - X_to_plot = X_test + # Trace ou enregistre le graphique + self.plot_threshold_analysis(y_test, y_proba, step=0.05, + save_path="/home/souti/freqtrade/user_data/plots/threshold_analysis.png") - plt.figure(figsize=(12, 10)) - shap.summary_plot(shap_values_to_plot, X_to_plot, show=False) - plt.savefig(os.path.join(output_dir, "shap_summary.png"), bbox_inches="tight") - plt.close() - except ImportError: - print("\n(SHAP non installé — `pip install shap` pour activer l’analyse SHAP.)") + # y_test : vraies classes (0 / 1) + # y_proba : probabilités de la classe 1 prédites par ton modèle + # Exemple : y_proba = model.predict_proba(X_test)[:, 1] + + seuils = np.arange(0.0, 1.01, 0.05) + precisions, recalls, f1s = [], [], [] + + for seuil in seuils: + y_pred = (y_proba >= seuil).astype(int) + precisions.append(precision_score(y_test, y_pred)) + recalls.append(recall_score(y_test, y_pred)) + f1s.append(f1_score(y_test, y_pred)) + + plt.figure(figsize=(10, 6)) + plt.plot(seuils, precisions, label='Précision', marker='o') + plt.plot(seuils, recalls, label='Rappel', marker='o') + plt.plot(seuils, f1s, label='F1-score', marker='o') + + # Ajoute un point pour le meilleur F1 + best_idx = np.argmax(f1s) + plt.scatter(seuils[best_idx], f1s[best_idx], color='red', s=80, label=f'Max F1 ({seuils[best_idx]:.2f})') + + plt.title("Performance du modèle selon le seuil de probabilité") + plt.xlabel("Seuil de probabilité (classe 1)") + plt.ylabel("Score") + plt.grid(True, alpha=0.3) + plt.legend() + plt.savefig("/home/souti/freqtrade/user_data/plots/seuil_de_probabilite.png", bbox_inches='tight') + # plt.show() + + print(f"✅ Meilleur F1 : {f1s[best_idx]:.3f} au seuil {seuils[best_idx]:.2f}") print("\n===== ✅ FIN DE L’ANALYSE =====") + def plot_threshold_analysis(self, y_true, y_proba, step=0.05, save_path=None): + """ + Affiche la précision, le rappel et le F1-score selon le seuil de décision. + y_true : labels réels (0 ou 1) + y_proba : probabilités prédites (P(hausse)) + step : pas entre les seuils testés + save_path : si renseigné, enregistre l'image au lieu d'afficher + """ + + # Le graphique généré affichera trois courbes : + # + # 🔵 Precision — la fiabilité de tes signaux haussiers. + # + # 🟢 Recall — la proportion de hausses que ton modèle détecte. + # + # 🟣 F1-score — le compromis optimal entre les deux. + + thresholds = np.arange(0, 1.01, step) + precisions, recalls, f1s = [], [], [] + + for thr in thresholds: + preds = (y_proba >= thr).astype(int) + precisions.append(precision_score(y_true, preds)) + recalls.append(recall_score(y_true, preds)) + f1s.append(f1_score(y_true, preds)) + + plt.figure(figsize=(10, 6)) + plt.plot(thresholds, precisions, label="Precision", linewidth=2) + plt.plot(thresholds, recalls, label="Recall", linewidth=2) + plt.plot(thresholds, f1s, label="F1-score", linewidth=2, linestyle="--") + plt.axvline(0.5, color='gray', linestyle=':', label="Seuil 0.5") + plt.title("📊 Performance selon le seuil de probabilité", fontsize=14) + plt.xlabel("Seuil de décision (threshold)") + plt.ylabel("Score") + plt.legend() + plt.grid(True, alpha=0.3) + + if save_path: + plt.savefig(save_path, bbox_inches='tight') + print(f"✅ Graphique enregistré : {save_path}") + else: + plt.show() + + # # ============================= + # # Exemple d’utilisation : + # # ============================= + # if __name__ == "__main__": + # # Exemple : chargement d’un modèle et test + # import joblib + # + # model = joblib.load("/media/Home/home/souti/freqtrade/user_data/strategies/tools/sklearn/model.pkl") + # data = np.load("/media/Home/home/souti/freqtrade/user_data/strategies/tools/sklearn/test_data.npz") + # X_test, y_test = data["X"], data["y"] + # + # y_proba = model.predict_proba(X_test)[:, 1] + # + # # Trace ou enregistre le graphique + # plot_threshold_analysis(y_test, y_proba, step=0.05, + # save_path="/media/Home/home/souti/freqtrade/user_data/strategies/tools/sklearn/threshold_analysis.png") + + def populateDataframe(self, dataframe, timeframe='5m'): heikinashi = qtpylib.heikinashi(dataframe) dataframe['haopen'] = heikinashi['open'] @@ -1292,10 +1434,10 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose'] dataframe['mid'] = dataframe['haopen'] + (dataframe['haclose'] - dataframe['haopen']) / 2 - dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] - dataframe["percent3"] = (dataframe["close"] - dataframe["open"].shift(3)) / dataframe["open"].shift(3) - dataframe["percent12"] = (dataframe["close"] - dataframe["open"].shift(12)) / dataframe["open"].shift(12) - dataframe["percent24"] = (dataframe["close"] - dataframe["open"].shift(24)) / dataframe["open"].shift(24) + dataframe["percent"] = dataframe['close'].pct_change() + dataframe["percent3"] = dataframe['close'].pct_change(3) + dataframe["percent12"] = dataframe['close'].pct_change(12) + dataframe["percent24"] = dataframe['close'].pct_change(24) if self.dp.runmode.value in ('backtest'): dataframe['futur_percent'] = 100 * (dataframe['close'].shift(-1) - dataframe['close']) / dataframe['close'] @@ -1323,6 +1465,7 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['max12'] = talib.MAX(dataframe['close'], timeperiod=12) dataframe['max60'] = talib.MAX(dataframe['close'], timeperiod=60) dataframe['min60'] = talib.MIN(dataframe['close'], timeperiod=60) + dataframe['min_max_60'] = ((dataframe['max60'] - dataframe['close']) / dataframe['min60']) # dataframe['min36'] = talib.MIN(dataframe['close'], timeperiod=36) # dataframe['max36'] = talib.MAX(dataframe['close'], timeperiod=36) # dataframe['pct36'] = 100 * (dataframe['max36'] - dataframe['min36']) / dataframe['min36'] @@ -1332,6 +1475,13 @@ class Zeus_8_3_2_B_4_2(IStrategy): dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] + dataframe["bb_percent"] = ( + (dataframe["close"] - dataframe["bb_lowerband"]) / + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) + ) + dataframe["bb_width"] = ( + (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] + ) # Calcul MACD macd, macdsignal, macdhist = talib.MACD( @@ -1403,6 +1553,46 @@ class Zeus_8_3_2_B_4_2(IStrategy): # tr = DataFrame({'hl': high_low, 'hc': high_close, 'lc': low_close}).max(axis=1) # dataframe['atr'] = tr.rolling(window=self.DEFAULT_PARAMS['atr_period']).mean() + ########################### + # df = ton DataFrame OHLCV avec colonnes: open, high, low, close, volume + # Assure-toi qu'il est trié par date croissante + + # --- Volatilité normalisée --- + dataframe['atr'] = ta.volatility.AverageTrueRange( + high=dataframe['high'], low=dataframe['low'], close=dataframe['close'], window=14 + ).average_true_range() + dataframe['atr_norm'] = dataframe['atr'] / dataframe['close'] + + # --- Force de tendance --- + dataframe['adx'] = ta.trend.ADXIndicator( + high=dataframe['high'], low=dataframe['low'], close=dataframe['close'], window=14 + ).adx() + + # --- Volume directionnel (On Balance Volume) --- + dataframe['obv'] = ta.volume.OnBalanceVolumeIndicator( + close=dataframe['close'], volume=dataframe['volume'] + ).on_balance_volume() + + # --- Volatilité récente (écart-type des rendements) --- + dataframe['ret'] = dataframe['close'].pct_change() + dataframe['vol_24'] = dataframe['ret'].rolling(24).std() + + # Compter les baisses / hausses consécutives + self.calculateDownAndUp(dataframe, limit=0.0001) + + # df : ton dataframe OHLCV + indicateurs existants + # Assurez-vous que les colonnes suivantes existent : + # 'max_rsi_12', 'roc_24', 'bb_percent_1h' + + # --- Filtrage des NaN initiaux --- + # dataframe = dataframe.dropna() + + dataframe['rsi_slope'] = dataframe['rsi'].diff(3) / 3 # vitesse moyenne du RSI + dataframe['adx_change'] = dataframe['adx'] - dataframe['adx'].shift(12) # évolution de la tendance + dataframe['volatility_ratio'] = dataframe['atr_norm'] / dataframe['bb_width'] + + ########################### + dataframe['volume_sma_deriv'] = dataframe['volume'] * dataframe['sma5_deriv1'] / (dataframe['volume'].rolling(5).mean()) self.calculeDerivees(dataframe, 'volume', timeframe=timeframe, ema_period=12) @@ -1410,6 +1600,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): return dataframe + def feature_auc_scores(self, X, y): + aucs = {} + for col in X.columns: + try: + aucs[col] = roc_auc_score(y, X[col].fillna(method='ffill').fillna(0)) + except Exception: + aucs[col] = np.nan + return pd.Series(aucs).sort_values(ascending=False) + def macd_tendance_int(self, dataframe: pd.DataFrame, macd_col='macd', signal_col='macdsignal', @@ -1462,8 +1661,8 @@ class Zeus_8_3_2_B_4_2(IStrategy): return tendance 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['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) * ( @@ -1502,6 +1701,12 @@ class Zeus_8_3_2_B_4_2(IStrategy): factor1 = 100 * (ema_period / 5) factor2 = 10 * (ema_period / 5) + dataframe[f"{name}{suffixe}_inv"] = (dataframe[f"{name}{suffixe}"].shift(2) >= dataframe[f"{name}{suffixe}"].shift(1)) \ + & (dataframe[f"{name}{suffixe}"].shift(1) <= dataframe[f"{name}{suffixe}"]) + # --- Distance à la moyenne mobile --- + dataframe[f"{name}{suffixe}_dist"] = (dataframe['close'] - dataframe[f"{name}{suffixe}"]) / dataframe[f"{name}{suffixe}"] + + # dérivée relative simple dataframe[d1_col] = (dataframe[name] - dataframe[name].shift(1)) / dataframe[name].shift(1) # lissage EMA @@ -2730,7 +2935,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'] == 'B-': + if self.pairs[pair]['stop'] and last_candle['max_rsi_12_1h'] <= 60 and last_candle['trend_class_1h'] == -1: dispo = round(self.wallets.get_available_stake_amount()) self.pairs[pair]['stop'] = False self.log_trade( @@ -2948,15 +3153,15 @@ class Zeus_8_3_2_B_4_2(IStrategy): q1, q2, q3, q4 = q v = series.iloc[i] if v <= q1: - trend_class.append('B--') + trend_class.append(-2) elif v <= q2: - trend_class.append('B-') + trend_class.append(-1) elif v <= q3: - trend_class.append('P') + trend_class.append(0) elif v <= q4: - trend_class.append('H+') + trend_class.append(1) else: - trend_class.append('H++') + trend_class.append(2) return trend_class dataframe['slope_norm'] = df['slope_norm'] diff --git a/tools/sklearn/Confusion_Matrix.py b/tools/sklearn/Confusion_Matrix.py index 56d0177..aa0c1a7 100644 --- a/tools/sklearn/Confusion_Matrix.py +++ b/tools/sklearn/Confusion_Matrix.py @@ -44,4 +44,4 @@ for title, normalize in titles_options: print(title) print(disp.confusion_matrix) -plt.show() \ No newline at end of file +plt.show() diff --git a/tools/sklearn/RandomForestRegressor.py b/tools/sklearn/RandomForestRegressor.py index 0e42bf6..1c0a33d 100644 --- a/tools/sklearn/RandomForestRegressor.py +++ b/tools/sklearn/RandomForestRegressor.py @@ -1,3 +1,4 @@ + from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import r2_score, mean_absolute_error import pandas as pd