Przejdź do treści
MQL5 · MetaTrader 5 · po polsku
kod odczarowany

MQL5 / Błędy

retcode 10016

10016 — TRADE_RETCODE_INVALID_STOPS

Serwer odrzucił zlecenie, bo stop loss albo take profit leży za blisko ceny, po złej stronie rynku albo z nadmiarem miejsc dziesiętnych.

2 fragmenty kodu z tej strony przeszły przez kompilator MetaEditor build 6090, 2026-08-05.

CTrade::OrderSend: market buy 0.10 EURUSD sl: 1.09280 tp: 1.09500 [invalid stops]

Co ten kod znaczy

Serwer przyjął zapytanie, sprawdził poziomy zabezpieczające i je odrzucił. Samo zlecenie było poprawne — problem leży wyłącznie w wartościach sl i tp.

Cztery przyczyny, w kolejności częstości

1. Stop bliżej niż minimalny dystans brokera. Każdy instrument ma poziom SYMBOL_TRADE_STOPS_LEVEL wyrażony w punktach. Stop loss i take profit muszą leżeć co najmniej tyle punktów od ceny rynkowej.

Sprawdzenie minimalnego dystansu
long minimalny = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
double odstep = minimalny * _Point;

MqlTick tick;
SymbolInfoTick(_Symbol, tick);

//--- dla pozycji długiej stop musi leżeć poniżej bid o co najmniej odstep
double sl = MathMin(zaplanowanySL, tick.bid - odstep);

Wielu brokerów podaje tu zero. Zero nie znaczy „dowolnie blisko" — znaczy, że dystans jest zmienny i zależy od bieżącego spreadu. Bezpieczna praktyka to przyjąć MathMax(minimalny, spread * 2).

2. Stop po złej stronie ceny. Dla pozycji długiej stop loss musi być poniżej ceny, take profit powyżej. Dla krótkiej odwrotnie. Pomyłka w znaku daje dokładnie ten kod zwrotny.

3. Nadmiar miejsc dziesiętnych. Cena 1.0928000000000001 powstała z arytmetyki na double bywa odrzucana. Każdą cenę wysyłaną w zapytaniu przepuść przez NormalizeDouble(cena, _Digits).

4. Poziom zamrożenia. SYMBOL_TRADE_FREEZE_LEVEL określa strefę wokół ceny, w której nie można modyfikować ani zamykać zlecenia. Dotyczy to modyfikacji istniejącej pozycji, nie otwierania nowej.

Gotowa kontrola przed wysłaniem

Dociągnięcie stopów do dozwolonego zakresu
bool PoprawStopy(const string symbol, const ENUM_ORDER_TYPE typ,
                 double &sl, double &tp)
  {
   MqlTick tick;
   if(!SymbolInfoTick(symbol, tick))
      return false;

   int cyfry = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
   double punkt = SymbolInfoDouble(symbol, SYMBOL_POINT);
   long stopy = SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL);
   long spread = SymbolInfoInteger(symbol, SYMBOL_SPREAD);

   double odstep = MathMax((double)stopy, spread * 2.0) * punkt;

   if(typ == ORDER_TYPE_BUY)
     {
      if(sl > 0) sl = MathMin(sl, tick.bid - odstep);
      if(tp > 0) tp = MathMax(tp, tick.ask + odstep);
     }
   else if(typ == ORDER_TYPE_SELL)
     {
      if(sl > 0) sl = MathMax(sl, tick.ask + odstep);
      if(tp > 0) tp = MathMin(tp, tick.bid - odstep);
     }

   sl = NormalizeDouble(sl, cyfry);
   tp = NormalizeDouble(tp, cyfry);
   return true;
  }

Powiązane