LGBMClassifier ajout des corrélations mid_smooth_24
This commit is contained in:
@@ -84,7 +84,6 @@ def normalize(df):
|
||||
|
||||
class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
# Machine Learning
|
||||
model = joblib.load('rf_model.pkl')
|
||||
# model_indicators = [
|
||||
# 'rsi', 'rsi_deriv1', 'rsi_deriv2', "max_rsi_12",
|
||||
# "bb_percent",
|
||||
@@ -100,24 +99,29 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
# 'rsi_1h', 'rsi_deriv1_1h', 'rsi_deriv2_1h', "max_rsi_12_1h",
|
||||
# ]
|
||||
|
||||
model_indicators = ['open', 'high', 'low', 'close', 'volume', 'haopen', 'haclose', 'hapercent', 'mid',
|
||||
'percent', 'percent3', 'percent12', 'percent24', 'sma5', 'sma5_dist', 'sma5_deriv1',
|
||||
'sma5_deriv2', 'sma5_state', 'sma12', 'sma12_dist', 'sma12_deriv1', 'sma12_deriv2',
|
||||
'sma12_state', 'sma24', 'sma24_dist', 'sma24_deriv1', 'sma24_deriv2', 'sma24_state', 'sma48',
|
||||
'sma48_dist', 'sma48_deriv1', 'sma48_deriv2', 'sma48_state', 'sma60', 'sma60_dist',
|
||||
'sma60_deriv1', 'sma60_deriv2', 'sma60_state', 'mid_smooth_3', 'mid_smooth_3_dist',
|
||||
'mid_smooth_3_deriv1', 'mid_smooth_3_deriv2', 'mid_smooth_3_state', 'mid_smooth_5',
|
||||
'mid_smooth_5_dist', 'mid_smooth_5_deriv1', 'mid_smooth_5_deriv2', 'mid_smooth_5_state',
|
||||
'mid_smooth_12', 'mid_smooth_12_dist', 'mid_smooth_12_deriv1', 'mid_smooth_12_deriv2',
|
||||
'mid_smooth_12_state', 'mid_smooth_24', 'mid_smooth_24_dist', 'mid_smooth_24_deriv1',
|
||||
'mid_smooth_24_deriv2', 'mid_smooth_24_state', 'rsi', 'max_rsi_12', 'max_rsi_24', 'rsi_dist',
|
||||
'rsi_deriv1', 'rsi_deriv2', 'rsi_state', 'max12', 'max60', 'min60', 'min_max_60',
|
||||
'bb_lowerband', 'bb_middleband', 'bb_upperband', 'bb_percent', 'bb_width', 'macd',
|
||||
'macdsignal', 'macdhist', 'sma_20', 'sma_100', 'slope', 'slope_smooth', 'atr', 'atr_norm',
|
||||
'adx', 'obv', 'ret', 'vol_24', 'down_count', 'up_count', 'down_pct', 'up_pct',
|
||||
'rsi_slope', 'adx_change', 'volatility_ratio', 'rsi_diff', 'slope_ratio', 'volume_sma_deriv',
|
||||
'volume_dist', 'volume_deriv1', 'volume_deriv2', 'volume_state', 'slope_norm', 'trend_class',
|
||||
'mid_smooth']
|
||||
model_indicators = [
|
||||
# 'hapercent',
|
||||
# 'percent', 'percent3', 'percent12', 'percent24',
|
||||
# 'sma5_dist', 'sma5_deriv1', 'sma5_deriv2',
|
||||
# 'sma12_dist', 'sma12_deriv1', 'sma12_deriv2',
|
||||
# 'sma24_dist', 'sma24_deriv1', 'sma24_deriv2',
|
||||
# 'sma48_dist', 'sma48_deriv1', 'sma48_deriv2',
|
||||
# 'sma60_dist', 'sma60_deriv1', 'sma60_deriv2',
|
||||
# 'mid_smooth_3_deriv1', 'mid_smooth_3_deriv2',
|
||||
# 'mid_smooth_5_dist', 'mid_smooth_5_deriv1', 'mid_smooth_5_deriv2',
|
||||
# 'mid_smooth_12_dist', 'mid_smooth_12_deriv1', 'mid_smooth_12_deriv2',
|
||||
# 'mid_smooth_24_dist', 'mid_smooth_24_deriv1', 'mid_smooth_24_deriv2',
|
||||
# 'rsi', 'max_rsi_12', 'max_rsi_24', 'rsi_dist',
|
||||
# 'rsi_deriv1', 'rsi_deriv2', 'min_max_60',
|
||||
# 'bb_percent', 'bb_width', 'macd',
|
||||
# 'macdsignal', 'macdhist', 'slope', 'slope_smooth', 'atr', 'atr_norm',
|
||||
# 'adx',
|
||||
# 'obv', 'obv_deriv1', 'obv_deriv2',
|
||||
# 'obv5', 'obv5_deriv1', 'obv5_deriv2',
|
||||
# 'vol_24', 'down_count', 'up_count', 'down_pct', 'up_pct',
|
||||
# 'rsi_slope', 'adx_change', 'volatility_ratio', 'rsi_diff', 'slope_ratio', 'volume_sma_deriv',
|
||||
# 'volume_dist', 'volume_deriv1', 'volume_deriv2', 'slope_norm',
|
||||
]
|
||||
|
||||
levels = [1, 2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
|
||||
# startup_candle_count = 12 * 24 * 5
|
||||
@@ -1083,40 +1087,48 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
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)
|
||||
short_pair = self.getShortName(pair)
|
||||
if short_pair == 'BTC':
|
||||
self.model = joblib.load(f"{short_pair}_rf_model.pkl")
|
||||
|
||||
# Prédiction : probabilité que le prix monte
|
||||
probs = self.model.predict_proba(features)[:, 1]
|
||||
# Préparer les features pour la prédiction
|
||||
features = dataframe[self.model_indicators].fillna(0)
|
||||
|
||||
# Sauvegarder la probabilité pour l’analyse
|
||||
dataframe['ml_prob'] = probs
|
||||
# Prédiction : probabilité que le prix monte
|
||||
probs = self.model.predict_proba(features)[:, 1]
|
||||
|
||||
self.inspect_model(self.model)
|
||||
# Sauvegarder la probabilité pour l’analyse
|
||||
dataframe['ml_prob'] = probs
|
||||
|
||||
self.inspect_model(self.model)
|
||||
|
||||
return dataframe
|
||||
|
||||
def trainModel(self, dataframe: DataFrame, metadata: dict):
|
||||
pair = self.getShortName(metadata['pair'])
|
||||
pd.set_option('display.max_rows', None)
|
||||
pd.set_option('display.max_columns', None)
|
||||
pd.set_option("display.width", 200)
|
||||
path=f"user_data/plots/{pair}/"
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
||||
# Étape 1 : sélectionner numériques
|
||||
numeric_cols = dataframe.select_dtypes(include=['int64', 'float64']).columns
|
||||
|
||||
# Étape 2 : enlever constantes
|
||||
usable_cols = [c for c in numeric_cols if dataframe[c].nunique() > 1
|
||||
and (not c.endswith("_state") and not c.endswith("_1h") and not c.endswith("_1d")
|
||||
and not c.endswith("_class") and not c.endswith("_price")
|
||||
and not c.startswith('stop_buying'))]
|
||||
|
||||
# Étape 3 : remplacer inf et NaN par 0
|
||||
dataframe[usable_cols] = dataframe[usable_cols].replace([np.inf, -np.inf], 0).fillna(0)
|
||||
|
||||
print("Colonnes utilisables pour le modèle :")
|
||||
print(usable_cols)
|
||||
|
||||
self.model_indicators = usable_cols
|
||||
# # Étape 1 : sélectionner numériques
|
||||
# numeric_cols = dataframe.select_dtypes(include=['int64', 'float64']).columns
|
||||
#
|
||||
# # Étape 2 : enlever constantes
|
||||
# usable_cols = [c for c in numeric_cols if dataframe[c].nunique() > 1
|
||||
# and (not c.endswith("_state") and not c.endswith("_1h") and not c.endswith("_1d")
|
||||
# and not c.endswith("_class") and not c.endswith("_price")
|
||||
# and not c.startswith('stop_buying'))]
|
||||
#
|
||||
# # Étape 3 : remplacer inf et NaN par 0
|
||||
# dataframe[usable_cols] = dataframe[usable_cols].replace([np.inf, -np.inf], 0).fillna(0)
|
||||
#
|
||||
# print("Colonnes utilisables pour le modèle :")
|
||||
# print(usable_cols)
|
||||
#
|
||||
# self.model_indicators = usable_cols
|
||||
#
|
||||
df = dataframe[self.model_indicators].copy()
|
||||
|
||||
# Corrélations des colonnes
|
||||
@@ -1126,7 +1138,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
|
||||
# 3️⃣ Créer la cible : 1 si le prix monte dans les prochaines bougies
|
||||
# df['target'] = (df['sma24'].shift(-24) > df['sma24']).astype(int)
|
||||
df['target'] = (df['sma24'].shift(-25).rolling(24).max() > df['sma24'] * 1.003).astype(int)
|
||||
df['target'] = (df['percent12'].shift(-13) > 0.0015).astype(int)
|
||||
df['target'] = df['target'].fillna(0).astype(int)
|
||||
|
||||
# Corrélations triées par importance avec une colonne cible
|
||||
@@ -1178,7 +1190,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
plt.yticks(rotation=0)
|
||||
|
||||
# --- Sauvegarde ---
|
||||
output_path = "/home/souti/freqtrade/user_data/plots/Matrice_de_correlation_temperature.png"
|
||||
output_path = f"{path}/Matrice_de_correlation_temperature.png"
|
||||
plt.savefig(output_path, bbox_inches="tight", dpi=150)
|
||||
plt.close(fig)
|
||||
|
||||
@@ -1194,6 +1206,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
|
||||
X = df[self.model_indicators]
|
||||
y = df['target'] # ta colonne cible binaire ou numérique
|
||||
print("===== 🎯 FEATURES SCORES =====")
|
||||
print(self.feature_auc_scores(X, y))
|
||||
|
||||
# 4️⃣ Split train/test
|
||||
@@ -1211,29 +1224,30 @@ 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,
|
||||
# class_weight='balanced'
|
||||
# )
|
||||
# 1️⃣ Entraîne ton modèle LGBM normal
|
||||
train_model = LGBMClassifier(
|
||||
n_estimators=800,
|
||||
learning_rate=0.02,
|
||||
max_depth=10,
|
||||
num_leaves=31,
|
||||
subsample=0.8,
|
||||
colsample_bytree=0.8,
|
||||
reg_alpha=0.2,
|
||||
reg_lambda=0.4,
|
||||
class_weight='balanced',
|
||||
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,
|
||||
class_weight='balanced'
|
||||
)
|
||||
# 1️⃣ Entraîne ton modèle LGBM normal
|
||||
# train_model = LGBMClassifier(
|
||||
# n_estimators=800,
|
||||
# learning_rate=0.02,
|
||||
# max_depth=10,
|
||||
# num_leaves=31,
|
||||
# subsample=0.8,
|
||||
# colsample_bytree=0.8,
|
||||
# reg_alpha=0.2,
|
||||
# reg_lambda=0.4,
|
||||
# class_weight='balanced',
|
||||
# random_state=42,
|
||||
# )
|
||||
|
||||
train_model.fit(X_train, y_train)
|
||||
|
||||
# 2️⃣ Sélection des features AVANT calibration
|
||||
@@ -1246,7 +1260,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
calibrated.fit(X_train[selected_features], y_train)
|
||||
print(calibrated)
|
||||
|
||||
# # calibration
|
||||
# # # calibration
|
||||
# train_model = CalibratedClassifierCV(train_model, method='sigmoid', cv=5)
|
||||
# # Sélection
|
||||
# sfm = SelectFromModel(train_model, threshold="median")
|
||||
@@ -1262,14 +1276,13 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
print("\nRapport de classification :\n", classification_report(y_test, y_pred))
|
||||
print("\nMatrice de confusion :\n", confusion_matrix(y_test, y_pred))
|
||||
|
||||
# Importances
|
||||
importances = pd.DataFrame({
|
||||
"feature": train_model.feature_name_,
|
||||
"importance": train_model.feature_importances_
|
||||
}).sort_values("importance", ascending=False)
|
||||
print("\n===== 🔍 IMPORTANCE DES FEATURES =====")
|
||||
|
||||
print(importances)
|
||||
# # Importances
|
||||
# importances = pd.DataFrame({
|
||||
# "feature": train_model.feature_name_,
|
||||
# "importance": train_model.feature_importances_
|
||||
# }).sort_values("importance", ascending=False)
|
||||
# print("\n===== 🔍 IMPORTANCE DES FEATURES =====")
|
||||
# print(importances)
|
||||
|
||||
best_f1 = 0
|
||||
best_t = 0.5
|
||||
@@ -1289,7 +1302,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
print(f"Accuracy: {acc:.3f}")
|
||||
|
||||
# 7️⃣ Sauvegarde du modèle
|
||||
joblib.dump(train_model, 'rf_model.pkl')
|
||||
joblib.dump(train_model, f"{pair}_rf_model.pkl")
|
||||
print("✅ Modèle sauvegardé sous rf_model.pkl")
|
||||
|
||||
# X = dataframe des features (après shift/rolling/indicators)
|
||||
@@ -1314,7 +1327,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
# plt.ylabel("Score")
|
||||
# plt.show()
|
||||
|
||||
self.analyze_model(train_model, X_train, X_test, y_train, y_test)
|
||||
self.analyze_model(pair, train_model, X_train, X_test, y_train, y_test)
|
||||
|
||||
def inspect_model(self, model):
|
||||
"""
|
||||
@@ -1388,12 +1401,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
|
||||
print("\n===== ✅ FIN DE L’INSPECTION =====")
|
||||
|
||||
def analyze_model(self, model, X_train, X_test, y_train, y_test):
|
||||
def analyze_model(self, pair, model, X_train, X_test, y_train, y_test):
|
||||
"""
|
||||
Analyse complète d'un modèle ML supervisé (classification binaire).
|
||||
Affiche performances, importance des features, matrices, seuils, etc.
|
||||
"""
|
||||
output_dir = "user_data/plots"
|
||||
output_dir = f"user_data/plots/{pair}/"
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# ---- Prédictions ----
|
||||
@@ -1518,7 +1531,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
|
||||
# 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")
|
||||
save_path=f"{output_dir}/threshold_analysis.png")
|
||||
|
||||
# y_test : vraies classes (0 / 1)
|
||||
# y_proba : probabilités de la classe 1 prédites par ton modèle
|
||||
@@ -1547,7 +1560,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
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.savefig(f"{output_dir}/seuil_de_probabilite.png", bbox_inches='tight')
|
||||
# plt.show()
|
||||
|
||||
print(f"✅ Meilleur F1 : {f1s[best_idx]:.3f} au seuil {seuils[best_idx]:.2f}")
|
||||
@@ -1616,6 +1629,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
|
||||
|
||||
def populateDataframe(self, dataframe, timeframe='5m'):
|
||||
dataframe = dataframe.copy()
|
||||
heikinashi = qtpylib.heikinashi(dataframe)
|
||||
dataframe['haopen'] = heikinashi['open']
|
||||
dataframe['haclose'] = heikinashi['close']
|
||||
@@ -1667,7 +1681,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
(dataframe["close"] - dataframe["bb_lowerband"]) /
|
||||
(dataframe["bb_upperband"] - dataframe["bb_lowerband"])
|
||||
)
|
||||
dataframe["bb_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["sma5"]
|
||||
dataframe["bb_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["sma24"]
|
||||
|
||||
# dataframe["bb_width"] = (
|
||||
# (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||
@@ -1762,6 +1776,12 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
dataframe['obv'] = ta.volume.OnBalanceVolumeIndicator(
|
||||
close=dataframe['close'], volume=dataframe['volume']
|
||||
).on_balance_volume()
|
||||
self.calculeDerivees(dataframe, 'obv', timeframe=timeframe, ema_period=1)
|
||||
|
||||
dataframe['obv5'] = ta.volume.OnBalanceVolumeIndicator(
|
||||
close=dataframe['sma5'], volume=dataframe['volume'].rolling(5).sum()
|
||||
).on_balance_volume()
|
||||
self.calculeDerivees(dataframe, 'obv5', timeframe=timeframe, ema_period=5)
|
||||
|
||||
# --- Volatilité récente (écart-type des rendements) ---
|
||||
dataframe['vol_24'] = dataframe['percent'].rolling(24).std()
|
||||
@@ -1797,7 +1817,7 @@ class Zeus_8_3_2_B_4_2(IStrategy):
|
||||
aucs = {}
|
||||
for col in X.columns:
|
||||
try:
|
||||
aucs[col] = roc_auc_score(y, X[col].fillna(method='ffill').fillna(0))
|
||||
aucs[col] = roc_auc_score(y, X[col].ffill().fillna(0))
|
||||
except Exception:
|
||||
aucs[col] = np.nan
|
||||
return pd.Series(aucs).sort_values(ascending=False)
|
||||
|
||||
Reference in New Issue
Block a user