How to Move Stop Loss to Breakeven in MQL5 (EA Code + Real Backtest)

Published 2026-11-06 · Ranar Algo

To move a stop loss to breakeven in MQL5, loop over your open positions on every tick, and once price is a set number of points in profit, call CTrade::PositionModify(ticket, open_price + lock, current_tp) for a buy (or open_price - lock for a sell), skipping positions whose stop is already at or past that level. Add a small "lock" of a few points so spread and commission are covered, and respect the broker's SYMBOL_TRADE_STOPS_LEVEL so the request is not rejected.

Why breakeven code goes wrong

A breakeven stop sounds like two lines of code, but most broken versions share the same bugs:

The breakeven function

This works on hedging and netting accounts because it walks positions by ticket and filters by symbol and magic number. PositionGetTicket(i) also selects the position, so the PositionGet* calls that follow read that position.

input int InpBETriggerPts = 200;  // profit (points) that arms breakeven
input int InpBELockPts    = 20;   // points locked beyond entry (covers spread/commission)

void ManageBreakeven()
  {
   double pt    = _Point;
   double minD  = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * pt;
   double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong tk = PositionGetTicket(i);          // also selects the position
      if(tk == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol ||
         PositionGetInteger(POSITION_MAGIC) != InpMagic)
         continue;
      double open = PositionGetDouble(POSITION_PRICE_OPEN);
      double sl   = PositionGetDouble(POSITION_SL);
      double tp   = PositionGetDouble(POSITION_TP);
      if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        {
         double newSL = NormalizeDouble(open + InpBELockPts * pt, _Digits);
         if(bid - open < InpBETriggerPts * pt) continue;   // not armed yet
         if(sl != 0.0 && sl >= newSL) continue;            // already at/above breakeven
         if(bid - newSL <= minD) continue;                 // broker stops level
         c_Trade.PositionModify(tk, newSL, tp);
        }
      else
        {
         double newSL = NormalizeDouble(open - InpBELockPts * pt, _Digits);
         if(open - ask < InpBETriggerPts * pt) continue;
         if(sl != 0.0 && sl <= newSL) continue;
         if(newSL - ask <= minD) continue;
         c_Trade.PositionModify(tk, newSL, tp);
        }
     }
  }

Call ManageBreakeven() at the top of OnTick(), before any new-bar check, so the stop moves on the first tick that qualifies instead of waiting up to an hour for the next H1 bar. Entry logic can still run once per bar.

A few details worth knowing:

Full example EA

The test EA is a plain EMA(20/50) crossover on closed bars: buy when the fast EMA crosses above the slow one, sell on the opposite cross, one position at a time, 300-point stop, 600-point target, 0.10 lots. Breakeven arms at +200 points and locks +20 points. The entry side uses iMA handles, CopyBuffer on bars 1 and 2, and SetTypeFillingBySymbol so orders are accepted by brokers with different filling modes. OnTick() looks like this:

void OnTick()
  {
   ManageBreakeven();                 // every tick
   if(!IsNewBar())
      return;
   if(CopyBuffer(h_Fast, 0, 1, 2, g_fast) < 2 || CopyBuffer(h_Slow, 0, 1, 2, g_slow) < 2)
      return;
   bool crossUp   = g_fast[1] <= g_slow[1] && g_fast[0] > g_slow[0];
   bool crossDown = g_fast[1] >= g_slow[1] && g_fast[0] < g_slow[0];
   if(MyPositionType() != -1 || (!crossUp && !crossDown))
      return;
   // ... c_Trade.Buy / c_Trade.Sell with SL and TP in points
  }

Real backtest: breakeven on vs off

We ran the same EA twice in the MetaTrader 5 Strategy Tester on EURUSD H1, 2024.01.01 to 2025.01.01, $10,000 deposit, 1-minute OHLC modelling. The only difference: in the second run the trigger was set out of reach, so breakeven never fired.

This is a useful result precisely because it is not flattering. Breakeven almost doubled the win rate and lowered drawdown, but it made the system lose more overall. Trades that would have run to the 600-point target were stopped out at +20 after a pullback, so many small wins replaced fewer big ones, and the freed-up slot let the EA take ten more trades. Neither version is profitable; the crossover itself has no edge on this data. The lesson: breakeven is a risk-shaping tool, not a profit generator. A trigger that is too close to entry (here 200 of a 600-point target) cuts your winners. Test a few trigger values, or tie it to ATR, before trusting it. Past performance does not guarantee future results.

Building this without writing the plumbing

The breakeven loop, the side-of-book pricing, stops-level checks and the on/off comparison above are the parts that take time to get right. Ranar Algo lets you describe the rule in plain English ("EMA 20/50 cross on EURUSD H1, 300-point stop, 600-point target, move the stop to entry +20 points once price is 200 points in profit"), then generates the MQL5, compiles it, and runs a real MT5 backtest so you see actual numbers like the comparison above. You get the source code and keep your IP. It is still improving, so if a generated EA misses something in your spec, feedback is genuinely welcome.

Summary

Build & backtest your own EA free →

Ranar Algo turns a plain-English strategy into a compiled MQL5 Expert Advisor with a real MetaTrader 5 backtest. You keep your IP. Past performance does not guarantee future results.