Edgoro
Trade server return code 10025 · MQL5

MT5 error 10025 No changes: why and how to fix

Why MetaTrader 5 returns 10025 (no changes) when a trailing stop sends the same stop again, and how to modify a position only when something changes.

Trade server return code · MqlTradeResult.retcode
10025 TRADE_RETCODE_NO_CHANGES
“No changes in request”
Experts tab · line printed by CTrade (example values)
CTrade::OrderSend: modify position #123456789 EURUSD (sl: 1.08200, tp: 1.08900) [no changes]

What it means

The modification request contains exactly the values the position or order already has. The server refuses it as an error. The position is untouched, so it's harmless in itself, but it shows that the EA sends requests that do nothing, often on every tick.

Usual causes

  • A trailing stop that sends on every tick without comparing the new stop with the current one.
  • Rounding. The new stop is computed slightly differently, then rounded to the same price as the current one.
  • Comparing raw doubles. A comparison that sees 1.08200000001 and 1.082 as different, when the server sees the same price.
  • Unchanged take-profit and stop. A routine that "updates" both levels with the values it just read.

MetaQuotes' checklist for Market products treats a modification without changes as an error to avoid; the MQL4 equivalent was error 1 (ERR_NO_RESULT).

How to detect it

  • trade.ResultRetcode() (or result.retcode) is 10025 after PositionModify() or OrderModify(); the Experts tab shows the request followed by [no changes].
  • A journal full of identical modify lines is the usual sign.

Broken code

This EA compiles. Whenever the Bid hasn't moved, it resends the current stop and gets 10025; when the Bid falls, it even moves the stop back.

MQL5
#include <Trade/Trade.mqh>

input int InpTrailPoints = 200; // Trailing distance, points

CTrade trade;

void OnTick()
  {
   if(!PositionSelect(_Symbol) || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY)
      return;
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   // Sent on every tick: the same stop again and again, and sometimes a lower one
   double sl  = NormalizeDouble(bid - InpTrailPoints * _Point, _Digits);
   trade.PositionModify(_Symbol, sl, PositionGetDouble(POSITION_TP));
  }

Fixed code

The same program with the check that prevents the error. It compiles in MetaEditor with 0 errors and 0 warnings.

MQL5
#include <Trade/Trade.mqh>

input int   InpTrailPoints = 200;   // Trailing distance, points
input ulong InpMagic       = 26111; // Magic number of this EA's positions

CTrade trade;

int OnInit()
  {
   trade.SetExpertMagicNumber(InpMagic);
   return INIT_SUCCEEDED;
  }

void OnTick()
  {
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   if(tickSize <= 0.0)
      tickSize = _Point;
   double bid     = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double minDist = (double)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0 || PositionGetString(POSITION_SYMBOL) != _Symbol || PositionGetInteger(POSITION_MAGIC) != (long)InpMagic)
         continue;
      if(PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY)
         continue;
      double oldSl = PositionGetDouble(POSITION_SL);
      double newSl = NormalizeDouble(MathFloor((bid - InpTrailPoints * _Point) / tickSize) * tickSize, _Digits);
      // Send only when the stop moves UP by at least one tick, and stays beyond the stops level
      if(oldSl != 0.0 && newSl < oldSl + tickSize / 2)
         continue;
      if(bid - newSl < minDist)
         continue;
      if(!trade.PositionModify(ticket, newSl, PositionGetDouble(POSITION_TP)))
         PrintFormat("Modify #%I64u failed: retcode %u (%s)", ticket, trade.ResultRetcode(), trade.ResultRetcodeDescription());
     }
  }

Why the fix works

The new stop is rounded to the tick size first, then compared with the current one: the EA only sends a request when the stop moves up by at least one tick. Comparing with half a tick of tolerance avoids false differences between two doubles that are the same price. As a bonus, the stop can no longer move backwards, and only this EA's own positions are touched. Sell positions mirror the logic, with the Ask and a stop that only moves down.

Questions

Is error 10025 dangerous?

Not for the position: nothing changes. But an EA that sends useless requests on every tick floods the journal and the trade server, and MetaQuotes' checklist for Market products treats it as an error. Compare before you send.

Why does my trailing stop give 10025?

Because it sends a modification even when the new stop rounds to the current one. Round the new stop to the tick size and send only when it improves on the current stop by at least one tick.

What was 10025 called in MT4?

MQL4 returned error 1 (ERR_NO_RESULT) when OrderModify() was called with unchanged values.

The programs on this page are minimal examples written to show the error and its fix, not trading systems. Some of them send orders when they run: try them on a demo account. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.

Working code that avoids it

All MQL5 examples

Rather not write the error handling yourself?

Edgoro's MT5 EA generator writes complete MQL5 Expert Advisors from plain English and compiles each one in MetaEditor before you get it. A clean build proves the code compiles, not that a strategy works: test it on a demo account.