I programmed this Python code as best as I could, with the help of the web and forums. It's far from perfect. It does what I want, and I managed to make it work, but there are coding mistakes that I want to fix. The code needs to be entirely restructured to comply with Python standards. The lot size calculation needs to be corrected because it doesn't currently respect the defined risk percentage. The code must only take one order at a time per currency pair, which it doesn't currently do. The code must be able to trade multiple currency pairs, optimizing each one individually, which I haven't been able to implement so far. Finally, a function should be implemented to allow the code to use multiple threads. J'ai programmé ce code Python comme j'ai pu, avec l'aide du web et des forums. Il est loin d'être génial. Il fait ce que je veux, j'arrive à le faire fonctionner, mais il y a des erreurs d'écriture que je souhaite corriger. Ilva falloir restructurer entièrement le code pour qu'il correspondent au standard python. Il faut corriger la taille des lots, car actuellement il ne respecte pas correctement le pourcentage de risque défini. Il faut que le code ne prennent que 1 seul ordre à la fois par paire de devises, ce qu'il ne fait pas actuellement. Il faut que le code puisse trader sur plusieurs paires de devises, en optimisant chaque paire de devises 1 par 1 ce que je n'arrive pas à implémenter actuellement. pour finir il faudrait implémenter une fonction pour que le code puisse utiliser plusieurs threads. --------------------------------------------------------------------------------------------------------------------------- import MetaTrader5 as mt5 import warnings import datetime import optuna import time import joblib import json import ta import os import pandas as pd import numpy as np from stable_baselines3 import PPO from sklearn.preprocessing import StandardScaler from sklearn.model_selection import TimeSeriesSplit from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from ta import add_all_ta_features from ta.trend import ADXIndicator, CCIIndicator from ta.volatility import BollingerBands from ta.momentum import StochasticOscillator, WilliamsRIndicator from ta.volume import ForceIndexIndicator, OnBalanceVolumeIndicator from ta.utils import dropna from xgboost import XGBClassifier # Désactiver les messages d'information TensorFlow os.environ["TF_ENABLE_ONEDNN_OPTS"] = "0" warnings.filterwarnings("ignore", category=FutureWarning) # Connexion à MT5 et validation if not mt5.initialize(): print("Erreur d'initialisation de MT5") exit() symbol = "EURUSD" timeframe_H1 = mt5.TIMEFRAME_H1 n_bars = 2300 # Vérification de la disponibilité du symbole if mt5.symbol_info(symbol) is None: print(f"Le symbole {symbol} n'est pas disponible dans MT5.") mt5.shutdown() exit() # Tentative de sélection if not mt5.symbol_select(symbol, True): print(f"Erreur : impossible de sélectionner le symbole {symbol}.") mt5.shutdown() exit() else: print(f"Symbole {symbol} sélectionné avec succès.") # Vérification des limites de taille de lot pour EURUSD symbol_info = mt5.symbol_info(symbol) if symbol_info is not None: print(f"Taille minimale de lot : {symbol_info.volume_min}") print(f"Taille maximale de lot : {symbol_info.volume_max}") print(f"Incrément de lot : {symbol_info.volume_step}") else: print("Erreur : Impossible de récupérer les informations du symbole EURUSD") mt5.shutdown() exit() # Récupération des données pour H1 rates_H1 = mt5.copy_rates_from_pos(symbol, timeframe_H1, 0, n_bars) # Conversion en DataFrame pour H1 data_H1 = pd.DataFrame(rates_H1) data_H1['time'] = pd.to_datetime(data_H1['time'], unit='s') data_H1.set_index('time', inplace=True) data_H1 = data_H1[['open', 'high', 'low', 'close', 'tick_volume']] data_H1.dropna(inplace=True) # Récupération des données pour H4 et D1 rates_H4 = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_H4, 0, n_bars) rates_D1 = mt5.copy_rates_from_pos(symbol, mt5.TIMEFRAME_D1, 0, n_bars) # Conversion en DataFrames pour H4 et D1 data_H4 = pd.DataFrame(rates_H4) data_D1 = pd.DataFrame(rates_D1) # Transformation du temps pour chaque timeframe data_H4['time'] = pd.to_datetime(data_H4['time'], unit='s') data_D1['time'] = pd.to_datetime(data_D1['time'], unit='s') # Définir l'index comme étant le temps pour faciliter les fusions data_H4.set_index('time', inplace=True) data_D1.set_index('time', inplace=True) # Nettoyage initial des données pour enlever les valeurs manquantes sur H1 data_H1 = dropna(data_H1) # Ajout des indicateurs techniques avec `ta` pour H1 data_H1 = add_all_ta_features( data_H1, open="open", high="high", low="low", close="close", volume="tick_volume" ) # Ajout de SuperTrend def calculate_supertrend(df, atr_period=10, multiplier=3): df = df.copy() # Faire une copie explicite pour éviter les avertissements de copie high, low, close = df['high'], df['low'], df['close'] # Calcul du True Range (TR) df['tr1'] = high - low df['tr2'] = abs(high - close.shift(1)) df['tr3'] = abs(low - close.shift(1)) df['tr'] = df[['tr1', 'tr2', 'tr3']].max(axis=1) # Calcul de l'Average True Range (ATR) df['atr'] = df['tr'].rolling(atr_period).mean() # Calcul des bandes SuperTrend hl2 = (high + low) / 2 df['upperband'] = hl2 + (multiplier * df['atr']) df['lowerband'] = hl2 - (multiplier * df['atr']) df['in_uptrend'] = True # Boucle pour déterminer la tendance for i in range(1, len(df)): if close.iloc[i] > df['upperband'].iloc[i - 1]: df.loc[df.index[i], 'in_uptrend'] = True elif close.iloc[i] < df['lowerband'].iloc[i - 1]: df.loc[df.index[i], 'in_uptrend'] = False else: df.loc[df.index[i], 'in_uptrend'] = df['in_uptrend'].iloc[i - 1] if df['in_uptrend'].iloc[i] and df['lowerband'].iloc[i] < df['lowerband'].iloc[i - 1]: df.loc[df.index[i], 'lowerband'] = df['lowerband'].iloc[i - 1] if not df['in_uptrend'].iloc[i] and df['upperband'].iloc[i] > df['upperband'].iloc[i - 1]: df.loc[df.index[i], 'upperband'] = df['upperband'].iloc[i - 1] # Supprime les colonnes intermédiaires pour nettoyer df.drop(columns=['tr1', 'tr2', 'tr3', 'tr'], inplace=True) return df # Appliquer la fonction SuperTrend data_H1 = calculate_supertrend(data_H1) # Ajout de RSI (Relative Strength Index) sur plusieurs périodes data_H1['rsi_7'] = ta.momentum.RSIIndicator(close=data_H1['close'], window=7).rsi() data_H1['rsi_14'] = ta.momentum.RSIIndicator(close=data_H1['close'], window=14).rsi() # Ajout de MACD (Moving Average Convergence Divergence) macd = ta.trend.MACD(data_H1['close']) data_H1['macd'] = macd.macd() data_H1['macd_signal'] = macd.macd_signal() data_H1['macd_diff'] = macd.macd_diff() # Calcul de l'ADX adx_indicator = ADXIndicator(high=data_H1['high'], low=data_H1['low'], close=data_H1['close'], window=14) data_H1['adx'] = adx_indicator.adx() # Force de la tendance data_H1['adx_neg'] = adx_indicator.adx_neg() # Directionnel négatif data_H1['adx_pos'] = adx_indicator.adx_pos() # Directionnel positif # Calcul des Bandes de Bollinger bollinger = BollingerBands(close=data_H1['close'], window=20, window_dev=2) data_H1['bollinger_mavg'] = bollinger.bollinger_mavg() # Moyenne mobile data_H1['bollinger_hband'] = bollinger.bollinger_hband() # Bande haute data_H1['bollinger_lband'] = bollinger.bollinger_lband() # Bande basse data_H1['bollinger_wband'] = bollinger.bollinger_wband() # Largeur de la bande data_H1['bollinger_pband'] = bollinger.bollinger_pband() # Position du prix dans la bande # Calcul du CCI cci = CCIIndicator(high=data_H1['high'], low=data_H1['low'], close=data_H1['close'], window=20) data_H1['cci'] = cci.cci() # Calcul du Force Index force_index = ForceIndexIndicator(close=data_H1['close'], volume=data_H1['tick_volume'], window=2) data_H1['force_index'] = force_index.force_index() # Calcul du Stochastic stochastic = StochasticOscillator(high=data_H1['high'], low=data_H1['low'], close=data_H1['close'], window=14, smooth_window=3) data_H1['stoch_k'] = stochastic.stoch() # %K data_H1['stoch_d'] = stochastic.stoch_signal() # %D (signal line) # Calcul du Williams_r williams_r = WilliamsRIndicator(high=data_H1['high'], low=data_H1['low'], close=data_H1['close'], lbp=14) data_H1['williams_r'] = williams_r.williams_r() # Calcul de OBV obv = OnBalanceVolumeIndicator(close=data_H1['close'], volume=data_H1['tick_volume']) data_H1['obv'] = obv.on_balance_volume() # Remplir les valeurs manquantes après calcul data_H1.bfill(inplace=True) data_H1 = data_H1.infer_objects(copy=False) # Downcast final pour la future version # Calcul des indicateurs techniques pour H4 data_H4 = calculate_supertrend(data_H4) data_H4 = add_all_ta_features( data_H4, open="open", high="high", low="low", close="close", volume="tick_volume" ) # Ajout de RSI (Relative Strength Index) pour H4 data_H4['rsi_7'] = ta.momentum.RSIIndicator(close=data_H4['close'], window=7).rsi() data_H4['rsi_14'] = ta.momentum.RSIIndicator(close=data_H4['close'], window=14).rsi() # Ajout de MACD pour H4 macd_H4 = ta.trend.MACD(data_H4['close']) data_H4['macd'] = macd_H4.macd() data_H4['macd_signal'] = macd_H4.macd_signal() data_H4['macd_diff'] = macd_H4.macd_diff() # Remplir les valeurs manquantes après calcul des indicateurs data_H4.bfill(inplace=True) data_H4 = data_H4.infer_objects(copy=False) # Downcast final pour la future version # Calcul des indicateurs techniques pour D1 data_D1 = calculate_supertrend(data_D1) data_D1 = add_all_ta_features( data_D1, open="open", high="high", low="low", close="close", volume="tick_volume" ) # Ajout de RSI (Relative Strength Index) pour D1 data_D1['rsi_7'] = ta.momentum.RSIIndicator(close=data_D1['close'], window=7).rsi() data_D1['rsi_14'] = ta.momentum.RSIIndicator(close=data_D1['close'], window=14).rsi() # Ajout de MACD pour D1 macd_D1 = ta.trend.MACD(data_D1['close']) data_D1['macd'] = macd_D1.macd() data_D1['macd_signal'] = macd_D1.macd_signal() data_D1['macd_diff'] = macd_D1.macd_diff() # Remplir les valeurs manquantes après calcul des indicateurs data_D1.bfill(inplace=True) data_D1 = data_D1.infer_objects(copy=False) # Downcast final pour la future version # Renommer les colonnes de H4 et D1 pour éviter les conflits lors de la fusion data_H4 = data_H4.add_suffix('_H4') data_D1 = data_D1.add_suffix('_D1') # Joindre les données H4 et D1 avec les données H1 en alignant les timestamps data_H1 = data_H1.join(data_H4, how='left').join(data_D1, how='left') # Correction de bfill et ffill avec infer_objects data_H1.ffill(inplace=True) # Utilise forward fill pour éviter les NaN dans le futur data_H1 = data_H1.infer_objects(copy=False) # Downcast les objets selon la future version data_H1.bfill(inplace=True) # Backfill également avec infer_objects data_H1 = data_H1.infer_objects(copy=False) # Downcast final pour la future version # Vérification de l'absence de NaN après fusion if data_H1.isna().sum().sum() == 0: print("Les données `data_H1` sont complètes et ne contiennent pas de NaN.") else: print("Attention : `data_H1` contient encore des NaN après le remplissage.") # Affichage d'un échantillon de données pour vérifier le contenu de data_H1 print(data_H1.head()) # Remplir les valeurs manquantes en utilisant le forward fill data_H1.ffill(inplace=True) data_H1 = data_H1.infer_objects(copy=False) # Downcast final pour la future version # Convertir les colonnes 'in_uptrend_H4' et 'in_uptrend_D1' en type bool data_H1['in_uptrend_H4'] = data_H1['in_uptrend_H4'].astype(bool) data_H1['in_uptrend_D1'] = data_H1['in_uptrend_D1'].astype(bool) # Préparation de la variable cible pour XGBoost : direction du prix de clôture data_H1['target'] = np.where(data_H1['close'].shift(-10) > data_H1['close'], 1, 0) # 1 pour hausse, 0 pour baisse # Séparation des données pour XGBoost X = data_H1.drop(columns=['target']) # Supprime la cible de X y = data_H1['target'] # Encodage des colonnes booléennes 'in_uptrend_H4' et 'in_uptrend_D1' en variables numériques X = pd.get_dummies(X, columns=['in_uptrend_H4', 'in_uptrend_D1'], drop_first=True) # Division des données en ensembles d'entraînement et de test X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) # Ajoutez la vérification de la distribution ici print("Distribution de y_train :") print(y_train.value_counts()) # Chemins pour sauvegarder le meilleur modèle et le score BEST_MODEL_PATH = "best_model.pkl" BEST_SCORE_PATH = "best_score.json" def save_and_compare_model(new_model, new_score): """ Sauvegarde le nouveau modèle s'il est meilleur que l'ancien. """ try: # Charger le meilleur score actuel if os.path.exists(BEST_SCORE_PATH): with open(BEST_SCORE_PATH, 'r') as score_file: best_score = json.load(score_file).get('accuracy', 0) else: best_score = 0 # Aucun modèle sauvegardé encore # Comparer avec le nouveau score if new_score > best_score: print(f"[INFO] Nouveau modèle trouvé avec un score supérieur ({new_score:.4f} > {best_score:.4f}). Sauvegarde en cours.") # Sauvegarder le nouveau modèle joblib.dump(new_model, BEST_MODEL_PATH) # Sauvegarder le nouveau score with open(BEST_SCORE_PATH, 'w') as score_file: json.dump({'accuracy': new_score}, score_file) else: print(f"[INFO] Le modèle actuel reste le meilleur ({best_score:.4f} >= {new_score:.4f}).") except Exception as e: print(f"[ERROR] Erreur lors de la sauvegarde du modèle : {str(e)}") def load_best_model(): """ Charge le meilleur modèle sauvegardé s'il existe. """ if os.path.exists(BEST_MODEL_PATH): print("[INFO] Chargement du meilleur modèle existant.") return joblib.load(BEST_MODEL_PATH) else: print("[INFO] Aucun modèle existant trouvé, un nouveau sera entraîné.") return None # Charger le meilleur modèle existant, s'il existe xgb_model = load_best_model() if xgb_model is None: print("[INFO] Aucun modèle existant, Optuna entraînera un nouveau modèle.") else: print("[INFO] Modèle existant chargé, il sera utilisé pour les prédictions.") # Optimisation des hyperparamètres de XGBoost avec Optuna def objective_xgboost(trial): params = { 'learning_rate': trial.suggest_float('learning_rate', 0.001, 0.1), 'max_depth': trial.suggest_int('max_depth', 3, 20), 'n_estimators': trial.suggest_int('n_estimators', 100, 3000), 'subsample': trial.suggest_float('subsample', 0.5, 1.0), 'colsample_bytree': trial.suggest_float('colsample_bytree', 0.4, 1.0), 'gamma': trial.suggest_float('gamma', 0, 20), # Contrôle du surajustement 'min_child_weight': trial.suggest_int('min_child_weight', 1, 20), 'scale_pos_weight': trial.suggest_float('scale_pos_weight', 0.5, 10.0) # Ajuste le poids des baisses } xgb_model = XGBClassifier(**params) xgb_model.fit(X_train, y_train) y_pred = xgb_model.predict(X_test) return accuracy_score(y_test, y_pred) def train_evaluate_xgboost(n_trials=100): """ Entraîne et évalue un modèle XGBoost en utilisant Optuna. """ # Entraîner un modèle avec Optuna study = optuna.create_study(direction="maximize") study.optimize(objective_xgboost, n_trials=n_trials) # Meilleurs paramètres trouvés best_params_xgb = study.best_params print("Meilleurs paramètres XGBoost:", best_params_xgb) # Entraînement du modèle avec les meilleurs paramètres xgb_model = XGBClassifier(**best_params_xgb, eval_metric='logloss') xgb_model.fit(X_train, y_train) # Évaluation du modèle y_pred = xgb_model.predict(X_test) accuracy = accuracy_score(y_test, y_pred) print(f"Précision du modèle XGBoost : {accuracy:.2f}") # Comparer et sauvegarder le modèle save_and_compare_model(xgb_model, accuracy) return xgb_model # Fonction pour obtenir un volume valide pour un symbole donné def get_valid_volume(symbol, desired_volume): """ Ajuste le volume pour respecter les limites du broker. """ symbol_info = mt5.symbol_info(symbol) if symbol_info is None: print(f"Erreur : Le symbole {symbol} n'est pas trouvé.") raise ValueError(f"Le symbole {symbol} n'est pas trouvé.") min_volume = max(symbol_info.volume_min, 0.01) # Taille minimale des lots max_volume = min(symbol_info.volume_max, 50.0) # Taille maximale arbitraire volume_step = symbol_info.volume_step # Ajustement du volume if desired_volume < min_volume: print(f"Le volume désiré {desired_volume:.2f} est inférieur au minimum {min_volume:.2f}. Ajusté à {min_volume:.2f}.") return min_volume elif desired_volume > max_volume: print(f"Le volume désiré {desired_volume:.2f} est supérieur au maximum {max_volume:.2f}. Ajusté à {max_volume:.2f}.") return max_volume else: adjusted_volume = round(desired_volume / volume_step) * volume_step return round(adjusted_volume, 2) def calculate_lot_size_no_stop_loss(symbol, risk_percentage=0.001): account_info = mt5.account_info() if account_info is None: print("Erreur lors de la récupération des informations du compte.") return 0.01 # Valeur minimale par défaut balance = account_info.balance equity = account_info.equity margin_free = account_info.margin_free risk_amount = min(balance, margin_free) * risk_percentage symbol_info = mt5.symbol_info(symbol) if not symbol_info: print(f"Erreur : Impossible d'obtenir les informations pour le symbole {symbol}.") return 0.01 point = symbol_info.point contract_size = symbol_info.trade_contract_size pip_value_per_lot = (contract_size * point) / 10 leverage = account_info.leverage margin_required_per_lot = (contract_size * symbol_info.bid) / leverage lot_size = min(risk_amount / pip_value_per_lot, margin_free / margin_required_per_lot) valid_volume = get_valid_volume(symbol, lot_size) # Validation finale du volume if valid_volume < symbol_info.volume_min or valid_volume > symbol_info.volume_max: print(f"[ERROR] Volume calculé {valid_volume} hors limites acceptables.") return symbol_info.volume_min return valid_volume # Fonction pour exécuter un ordre sur MT5 def place_order(symbol, order_type, volume): positions = mt5.positions_get(symbol=symbol) if positions: print(f"[WARNING] Des positions sont déjà ouvertes pour {symbol}. Vérifiez la gestion des positions.") return None # Évite d'ouvrir une position supplémentaire tick = mt5.symbol_info_tick(symbol) if tick is None or tick.ask == 0 or tick.bid == 0: print(f"[ERROR] Données de tick invalides pour {symbol}.") return None price = tick.ask if order_type == "BUY" else tick.bid if price <= 0: print("[ERROR] Prix invalide pour l'exécution de l'ordre.") return None request = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": volume, "type": mt5.ORDER_TYPE_BUY if order_type == "BUY" else mt5.ORDER_TYPE_SELL, "price": price, "deviation": 10, "magic": 123456, "comment": "MegaForexEA", } result = mt5.order_send(request) if result.retcode != mt5.TRADE_RETCODE_DONE: print(f"[ERROR] Échec de l'exécution de l'ordre {order_type} : {result.comment}") print(f"[DEBUG] Détails de la requête : {request}") return None print(f"[INFO] Ordre exécuté : {order_type} {volume} {symbol} au prix {price}") return result def close_all_positions(symbol): positions = mt5.positions_get(symbol=symbol) if not positions: print(f"[INFO] Aucune position à fermer pour {symbol}.") return True success = True for position in positions: volume = position.volume order_type = "SELL" if position.type == mt5.ORDER_TYPE_BUY else "BUY" print(f"[INFO] Tentative de fermeture de la position {order_type} de {volume} lots pour {symbol}.") tick = mt5.symbol_info_tick(symbol) if not tick or tick.bid == 0 or tick.ask == 0: print("[ERROR] Données de tick invalides pour fermer la position.") success = False continue request = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": volume, "type": mt5.ORDER_TYPE_SELL if order_type == "SELL" else mt5.ORDER_TYPE_BUY, "price": tick.bid if order_type == "SELL" else tick.ask, "deviation": 10, "magic": 123456, "comment": "MegaForexEA", } result = mt5.order_send(request) if result.retcode != mt5.TRADE_RETCODE_DONE: print(f"[ERROR] Échec de la fermeture de la position {order_type} pour {symbol}. {result.comment}") success = False else: print(f"[INFO] Position {order_type} fermée avec succès.") if success: print(f"[INFO] Toutes les positions pour {symbol} ont été fermées avec succès.") else: print(f"[ERROR] Certaines positions pour {symbol} n'ont pas pu être fermées.") return success def manage_positions(symbol, prediction): positions = mt5.positions_get(symbol=symbol) if not positions: print("[INFO] Aucune position ouverte pour ce symbole.") return True # Autorise l'ouverture d'une nouvelle position print(f"[INFO] Gestion des positions existantes pour {symbol}.") # Tentative de clôture des positions success = close_all_positions(symbol) if not success: print("[ERROR] Impossible de fermer toutes les positions existantes. Nouvelle position non ouverte.") return False # Bloque l'ouverture de nouvelles positions si la fermeture échoue. return True # Toutes les positions ont été fermées avec succès, une nouvelle position peut être ouverte. # Gérer une seule position ouverte position = positions[0] current_direction = "BUY" if position.type == mt5.ORDER_TYPE_BUY else "SELL" print(f"[INFO] Position existante : {current_direction} avec volume {position.volume}") # Vérifie si la position actuelle correspond à la prédiction if (current_direction == "BUY" and prediction == 1) or (current_direction == "SELL" and prediction == 0): print("[INFO] La position existante correspond à la prédiction. Aucun changement nécessaire.") return False # Pas besoin d'ouvrir une nouvelle position # Ferme la position si elle ne correspond pas à la prédiction print(f"[INFO] Fermeture de la position actuelle : {current_direction}") success = close_all_positions(symbol) if not success: print("[ERROR] Impossible de fermer la position existante. Nouvelle position non ouverte.") return False return True # Autorise l'ouverture d'une nouvelle position après fermeture des existantes def make_prediction_and_act(model, symbol, risk_percentage=0.001, timeframe=mt5.TIMEFRAME_H1, n_bars=2300): print(f"[DEBUG] Début de l'analyse pour {symbol}") # Récupération des données rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, n_bars) if rates is None or len(rates) == 0: print("[ERROR] Erreur lors de la récupération des données.") return None # Préparation des données pour la prédiction data = pd.DataFrame(rates) data['time'] = pd.to_datetime(data['time'], unit='s') data.set_index('time', inplace=True) data = add_all_ta_features(data, open="open", high="high", low="low", close="close", volume="tick_volume") data = calculate_supertrend(data) # Prédiction features = data.iloc[-1].fillna(0).values.reshape(1, -1) features_df = pd.DataFrame(features, columns=data.columns, index=[0]) features_df = features_df.reindex(columns=X_train.columns, fill_value=0) features_df = features_df.apply(pd.to_numeric, errors='coerce').fillna(0) prediction = model.predict(features_df)[0] order_type = "BUY" if prediction == 1 else "SELL" print(f"[INFO] Prédiction pour {symbol} : {order_type}") # Gestion des positions if not manage_positions(symbol, prediction): print("[INFO] Gestion des positions existantes terminée. Aucune nouvelle position n'a été ouverte.") return None # Sortir si la gestion des positions a échoué. # Vérifier qu'aucune position n'est ouverte avant de continuer if mt5.positions_total() > 0: print("[ERROR] Des positions sont encore ouvertes malgré la tentative de fermeture.") return None # Calculer la taille du lot lot_size = calculate_lot_size_no_stop_loss(symbol, risk_percentage) # Ouvrir une nouvelle position open_result = place_order(symbol, order_type, lot_size) if open_result: print(f"[INFO] Position {order_type} ouverte avec succès pour {symbol}.") else: print(f"[ERROR] Échec de l'ouverture de la position {order_type}.") return order_type def train_and_execute(symbol="EURUSD", risk_percentage=0.001): for entrainement in range(2): # Répéter 2 fois print(f"\n[INFO] Début de l'entrainement {entrainement + 1}") xgb_model = train_evaluate_xgboost(n_trials=100) print(f"[INFO] Fin de l'entrainement {entrainement + 1}.") # Prédiction et action après l'entraînement print(f"\n[INFO] Prédiction et action après l'entrainement {entrainement + 1} :") make_prediction_and_act(xgb_model, symbol, risk_percentage) # Point d'entrée principal if __name__ == "__main__": # Effectuer une seule itération de trading train_and_execute(symbol="EURUSD", risk_percentage=0.001) # 0,1% de risque par transaction