//+------------------------------------------------------------------+ //| EA_Gold_Rebond.mq5 | //| Trading Bot EMA8 / SMA14 | //+------------------------------------------------------------------+ #property copyright "Copyright 2026" #property link "https://forge.mql5.io" #property version "2.00" #include CTrade trade; //--- PARAMÈTRES D'ENTRÉE (Inputs modifiables) input group "--- PARAMÈTRES DE RISQUE & CAPITAL ---" input double InpRiskPercent = 20.0; // Risque par position (% de l'équité) input double InpStopLossPercent = 0.33; // Stop Loss en % input double InpTakeProfitPercent = 1.00; // Take Profit en % input int InpMaxPositions = 2; // Maximum de positions ouvertes (Add-in max = 2) input ulong InpMagicNumber = 888148; // Identifiant unique de ce robot input group "--- TRAILING STOP & BREAK-EVEN ---" input double InpBERatio = 1.2; // Activation du Break-Even (en R:R, ex: 1.2R) input double InpTrailingStepPct = 0.16; // Pas d'avancement du Trailing Stop (%) input group "--- INDICATEURS ---" input int InpLenEMA = 8; // Période EMA input int InpLenSMA = 14; // Période SMA //--- VARIABLES GLOBALES int handleEMA = INVALID_HANDLE; int handleSMA = INVALID_HANDLE; datetime lastBarTime = 0; int barsInTrend = 0; bool entryExecutedThisBar = false; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { trade.SetExpertMagicNumber(InpMagicNumber); trade.SetMarginMode(); // Initialisation des indicateurs handleEMA = iMA(_Symbol, _Period, InpLenEMA, 0, MODE_EMA, PRICE_CLOSE); handleSMA = iMA(_Symbol, _Period, InpLenSMA, 0, MODE_SMA, PRICE_CLOSE); if(handleEMA == INVALID_HANDLE || handleSMA == INVALID_HANDLE) { Print("[ERREUR] Impossible d'initialiser les indicateurs."); return(INIT_FAILED); } lastBarTime = 0; barsInTrend = 0; entryExecutedThisBar = false; Print("[SUCCÈS] EA_Gold_Rebond initialisé avec succès sur ", _Symbol); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(handleEMA != INVALID_HANDLE) IndicatorRelease(handleEMA); if(handleSMA != INVALID_HANDLE) IndicatorRelease(handleSMA); Print("[INFO] EA arrêté."); } //+------------------------------------------------------------------+ //| Expert tick function (Chaque variation du prix) | //+------------------------------------------------------------------+ void OnTick() { // 1. GESTION CONTINUE DES POSITIONS EXISTANTES (BE & Trailing Stop) ManagePositions(); // 2. MISE À JOUR DE LA TENDANCE SUR CLÔTURE DE BOUGIE datetime currentBarTime = iTime(_Symbol, _Period, 0); if(currentBarTime != lastBarTime) { lastBarTime = currentBarTime; entryExecutedThisBar = false; // Réinitialisation du verrou d'entrée pour la nouvelle bougie UpdateTrendCount(); } // 3. VÉRIFICATION DES RESTRICTIONS D'OUVERTURE if(GetOpenPositionsCount() >= InpMaxPositions) return; if(entryExecutedThisBar) return; // 4. RÉCUPÉRATION EN TEMPS RÉEL DE L'EMA ET LA SMA SUR LA BOUGIE EN COURS (Index 0) double emaVal[1], smaVal[1]; if(CopyBuffer(handleEMA, 0, 0, 1, emaVal) <= 0) return; if(CopyBuffer(handleSMA, 0, 0, 1, smaVal) <= 0) return; double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); // 5. CONDITIONS D'ENTRÉE AU TOUCHÉ (Dès la 3e bougie de tendance) bool buySignal = (barsInTrend >= 3) && (ask <= emaVal[0] || ask <= smaVal[0]); bool sellSignal = (barsInTrend <= -3) && (bid >= emaVal[0] || bid >= smaVal[0]); // 6. EXECUTION DES ORDRES if(buySignal) { double sl = NormalizeDouble(ask * (1.0 - (InpStopLossPercent / 100.0)), _Digits); double tp = NormalizeDouble(ask * (1.0 + (InpTakeProfitPercent / 100.0)), _Digits); double lot = CalculateLotSize(ask, sl); if(lot > 0 && trade.Buy(lot, _Symbol, ask, sl, tp, "EA Rebond Buy")) { PrintFormat("[BUY] Ordre exécuté ! Lot: %.2f | Prix: %.2f | SL: %.2f | TP: %.2f", lot, ask, sl, tp); entryExecutedThisBar = true; } } else if(sellSignal) { double sl = NormalizeDouble(bid * (1.0 + (InpStopLossPercent / 100.0)), _Digits); double tp = NormalizeDouble(bid * (1.0 - (InpTakeProfitPercent / 100.0)), _Digits); double lot = CalculateLotSize(bid, sl); if(lot > 0 && trade.Sell(lot, _Symbol, bid, sl, tp, "EA Rebond Sell")) { PrintFormat("[SELL] Ordre exécuté ! Lot: %.2f | Prix: %.2f | SL: %.2f | TP: %.2f", lot, bid, sl, tp); entryExecutedThisBar = true; } } } //+------------------------------------------------------------------+ //| Met à jour le compteur de bougies en tendance (Bougie fermée) | //+------------------------------------------------------------------+ void UpdateTrendCount() { double emaVal[1], smaVal[1]; if(CopyBuffer(handleEMA, 0, 1, 1, emaVal) <= 0) return; if(CopyBuffer(handleSMA, 0, 1, 1, smaVal) <= 0) return; double close1 = iClose(_Symbol, _Period, 1); bool aboveBoth = (close1 > emaVal[0] && close1 > smaVal[0]); bool belowBoth = (close1 < emaVal[0] && close1 < smaVal[0]); if(aboveBoth) { barsInTrend = (barsInTrend > 0) ? barsInTrend + 1 : 1; } else if(belowBoth) { barsInTrend = (barsInTrend < 0) ? barsInTrend - 1 : -1; } else { barsInTrend = 0; } } //+------------------------------------------------------------------+ //| Compte le nombre de positions ouvertes du robot | //+------------------------------------------------------------------+ int GetOpenPositionsCount() { int count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber) { count++; } } return count; } //+------------------------------------------------------------------+ //| Gestion du Break-Even à 1,2 R et Trailing Stop tous les 0,16 % | //+------------------------------------------------------------------+ void ManagePositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue; long posType = PositionGetInteger(POSITION_TYPE); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentSL = PositionGetDouble(POSITION_SL); double currentTP = PositionGetDouble(POSITION_TP); double targetBE = openPrice * (InpStopLossPercent / 100.0) * InpBERatio; double stepDist = openPrice * (InpTrailingStepPct / 100.0); if(posType == POSITION_TYPE_BUY) { double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Break-Even à 1,2 R if(bid >= (openPrice + targetBE) && currentSL < openPrice) { trade.PositionModify(ticket, NormalizeDouble(openPrice, _Digits), currentTP); PrintFormat("[BE] Position Buy #%d sécurisée au Break-Even", ticket); } // Trailing Stop par paliers de 0.16% else if(currentSL >= openPrice) { double candidateSL = NormalizeDouble(bid * (1.0 - (InpStopLossPercent / 100.0)), _Digits); if(candidateSL >= currentSL + stepDist) { trade.PositionModify(ticket, candidateSL, currentTP); PrintFormat("[TRAILING] SL Buy #%d mis à jour : %.2f", ticket, candidateSL); } } } else if(posType == POSITION_TYPE_SELL) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Break-Even à 1,2 R if(ask <= (openPrice - targetBE) && (currentSL > openPrice || currentSL == 0)) { trade.PositionModify(ticket, NormalizeDouble(openPrice, _Digits), currentTP); PrintFormat("[BE] Position Sell #%d sécurisée au Break-Even", ticket); } // Trailing Stop par paliers de 0.16% else if(currentSL > 0 && currentSL <= openPrice) { double candidateSL = NormalizeDouble(ask * (1.0 + (InpStopLossPercent / 100.0)), _Digits); if(candidateSL <= currentSL - stepDist) { trade.PositionModify(ticket, candidateSL, currentTP); PrintFormat("[TRAILING] SL Sell #%d mis à jour : %.2f", ticket, candidateSL); } } } } } //+------------------------------------------------------------------+ //| Calcul dynamique des lots selon 20% d'équité risquée | //+------------------------------------------------------------------+ double CalculateLotSize(double entryPrice, double slPrice) { double equity = AccountInfoDouble(ACCOUNT_EQUITY); double riskAmount = equity * (InpRiskPercent / 100.0); double priceRisk = MathAbs(entryPrice - slPrice); if(priceRisk <= 0) return 0.0; double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); if(tickSize <= 0 || tickValue <= 0) return 0.0; double lossPerLot = (priceRisk / tickSize) * tickValue; if(lossPerLot <= 0) return 0.0; double lot = riskAmount / lossPerLot; double stepVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); double minVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); lot = MathFloor(lot / stepVol) * stepVol; if(lot < minVol) lot = minVol; if(lot > maxVol) lot = maxVol; return lot; }