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.
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
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;
}