Frictrade

This commit is contained in:
Jérôme Delacotte
2025-12-05 23:27:40 +01:00
parent 3efc95e415
commit ae98d11559
26 changed files with 15887 additions and 38 deletions

View File

@@ -456,7 +456,7 @@ class FrictradeLearning(IStrategy):
# Add all ta features
pair = metadata['pair']
short_pair = self.getShortName(pair)
self.path = f"user_data/plots/{short_pair}/" + ("valide/" if not self.dp.runmode.value in ('backtest') else '')
self.path = f"user_data/strategies/plots/{short_pair}/" + ("valide/" if not self.dp.runmode.value in ('backtest') else '')
heikinashi = qtpylib.heikinashi(dataframe)
dataframe['haopen'] = heikinashi['open']
@@ -490,6 +490,16 @@ class FrictradeLearning(IStrategy):
& (dataframe["sma5_sqrt"] > 5)
)
dataframe["sma12_sqrt"] = (
np.sqrt(np.abs(dataframe["sma12"] - dataframe["sma12"].shift(1)))
+ np.sqrt(np.abs(dataframe["sma12"].shift(3) - dataframe["sma12"].shift(1)))
)
dataframe["sma12_inv"] = (
(dataframe["sma12"].shift(2) >= dataframe["sma12"].shift(1))
& (dataframe["sma12"].shift(1) <= dataframe["sma12"])
& (dataframe["sma12_sqrt"] > 5)
)
dataframe["percent"] = dataframe['mid'].pct_change()
dataframe["percent3"] = dataframe['mid'].pct_change(3).rolling(3).mean()
dataframe["percent12"] = dataframe['mid'].pct_change(12).rolling(12).mean()
@@ -723,9 +733,9 @@ class FrictradeLearning(IStrategy):
self.trainModel(dataframe, metadata)
short_pair = self.getShortName(pair)
path=f"user_data/plots/{short_pair}/"
# path=f"user_data/strategies/plots/{short_pair}/"
self.model = joblib.load(f"{path}/{short_pair}_rf_model.pkl")
self.model = joblib.load(f"{self.path}/{short_pair}_rf_model.pkl")
# Préparer les features pour la prédiction
features = dataframe[self.model_indicators].fillna(0)
@@ -824,7 +834,12 @@ class FrictradeLearning(IStrategy):
# Buy = prediction > threshold
dataframe["buy"] = 0
dataframe.loc[dataframe["ml_prob"] > 0.5, ['enter_long', 'enter_tag']] = (1, f"future")
dataframe.loc[
(dataframe["ml_prob"].shift(3) < 0.2)
& (dataframe['low'].shift(3) < dataframe['min180'].shift(3))
& (dataframe['min180'].shift(3) == dataframe['min180']),
['enter_long', 'enter_tag']
] = (1, f"future")
dataframe['test'] = np.where(dataframe['enter_long'] == 1, dataframe['close'] * 1.003, np.nan)
return dataframe
@@ -1060,9 +1075,10 @@ class FrictradeLearning(IStrategy):
# FIN ########################## ALGO ATH
condition = last_candle['hapercent'] > 0 and last_candle['sma24_deriv1'] > 0 \
and last_candle['close'] < self.pairs[pair]['first_buy'] \
and last_candle['ml_prob'] > 0.65
condition = last_candle['percent'] > 0 and last_candle['sma24_deriv1'] > 0 \
and last_candle['close'] < self.pairs[pair]['first_buy']
# and last_candle['ml_prob'] > 0.65
limit_buy = 40
# or (last_candle['close'] <= last_candle['min180'] and hours > 3)
if (decline >= dca_threshold) and condition:
@@ -1206,12 +1222,12 @@ class FrictradeLearning(IStrategy):
position = (mid - min_) / (max_ - min_)
zone = int(position * 3) # 0 à 2
if zone == 0:
current_trailing_stop_positive = self.trailing_stop_positive
current_trailing_stop_positive_offset = self.trailing_stop_positive_offset * 2
if minutes > 1440:
current_trailing_only_offset_is_reached = False
current_trailing_stop_positive_offset = self.trailing_stop_positive_offset
# if zone == 0:
# current_trailing_stop_positive = self.trailing_stop_positive
# current_trailing_stop_positive_offset = self.trailing_stop_positive_offset * 2
# if minutes > 1440:
# current_trailing_only_offset_is_reached = False
# current_trailing_stop_positive_offset = self.trailing_stop_positive_offset
# if zone == 1:
# ----- 5) Calcul du trailing stop dynamique -----
@@ -1236,7 +1252,7 @@ class FrictradeLearning(IStrategy):
stake=0
)
if last_candle['ml_prob'] > 0.65:
if last_candle['sma12'] > last_candle['sma24']:
return None
# if last_candle['sma24_deriv1'] > 0 : #and minutes < 180 and baisse < 30: # and last_candle['sma5_deriv1'] > -0.15:
# if (minutes < 180):
@@ -1371,7 +1387,7 @@ class FrictradeLearning(IStrategy):
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}/"
path=self.path #f"user_data/plots/{pair}/"
os.makedirs(path, exist_ok=True)
# # Étape 1 : sélectionner numériques
@@ -1452,7 +1468,7 @@ class FrictradeLearning(IStrategy):
plt.yticks(rotation=0)
# --- Sauvegarde ---
output_path = f"{path}/Matrice_de_correlation_temperature.png"
output_path = f"{self.path}/Matrice_de_correlation_temperature.png"
plt.savefig(output_path, bbox_inches="tight", dpi=150)
plt.close(fig)
@@ -1594,7 +1610,7 @@ class FrictradeLearning(IStrategy):
)
# Sauvegarde du graphique sur disque
output_path = f"{path}/shap_waterfall.png"
output_path = f"{self.path}/shap_waterfall.png"
plt.savefig(output_path, dpi=200, bbox_inches='tight')
plt.close() # ferme la figure proprement
@@ -1625,13 +1641,13 @@ class FrictradeLearning(IStrategy):
# Graphs
fig = plot_optimization_history(study)
fig.write_html(f"{path}/optimization_history.html")
fig.write_html(f"{self.path}/optimization_history.html")
fig = plot_param_importances(study)
fig.write_html(f"{path}/param_importances.html")
fig.write_html(f"{self.path}/param_importances.html")
fig = plot_slice(study)
fig.write_html(f"{path}/slice.html")
fig.write_html(f"{self.path}/slice.html")
fig = plot_parallel_coordinate(study)
fig.write_html(f"{path}/parallel_coordinates.html")
fig.write_html(f"{self.path}/parallel_coordinates.html")
# 2⃣ Sélection des features AVANT calibration
@@ -1677,14 +1693,14 @@ class FrictradeLearning(IStrategy):
feat_imp.plot(kind='bar', figsize=(12, 6))
plt.title("Feature importances")
# plt.show()
plt.savefig(f"{path}/Feature importances.png", bbox_inches='tight')
plt.savefig(f"{self.path}/Feature importances.png", bbox_inches='tight')
result = permutation_importance(self.train_model, X_valid, y_valid, scoring='f1', n_repeats=10, random_state=42)
perm_imp = pd.Series(result.importances_mean, index=X_valid.columns).sort_values(ascending=False)
perm_imp.plot(kind='bar', figsize=(12, 6))
plt.title("Permutation feature importance")
# plt.show()
plt.savefig(f"{path}/Permutation feature importance.png", bbox_inches='tight')
plt.savefig(f"{self.path}/Permutation feature importance.png", bbox_inches='tight')
# Shap
explainer = shap.TreeExplainer(self.train_model)
@@ -1695,7 +1711,7 @@ class FrictradeLearning(IStrategy):
# Force plot pour une observation
force_plot = shap.force_plot(explainer.expected_value, shap_values[0, :], X_valid.iloc[0, :])
shap.save_html(f"{path}/shap_force_plot.html", force_plot)
shap.save_html(f"{self.path}/shap_force_plot.html", force_plot)
fig, ax = plt.subplots(figsize=(24, 48))
PartialDependenceDisplay.from_estimator(
@@ -1705,7 +1721,7 @@ class FrictradeLearning(IStrategy):
kind="average",
ax=ax
)
fig.savefig(f"{path}/PartialDependenceDisplay.png", bbox_inches="tight")
fig.savefig(f"{self.path}/PartialDependenceDisplay.png", bbox_inches="tight")
plt.close(fig)
best_f1 = 0
@@ -1726,7 +1742,7 @@ class FrictradeLearning(IStrategy):
print(f"Accuracy: {acc:.3f}")
# 7⃣ Sauvegarde du modèle
joblib.dump(self.train_model, f"{path}/{pair}_rf_model.pkl")
joblib.dump(self.train_model, f"{self.path}/{pair}_rf_model.pkl")
print(f"✅ Modèle sauvegardé sous {pair}_rf_model.pkl")