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

MQL5 / Pułapki

Kod działa na kupnach, nie działa na sprzedażach

Klasyczny objaw pomylonej strony ceny. Wyjaśniamy, która cena obowiązuje przy otwarciu, zamknięciu i przy sprawdzaniu poziomów, i dlaczego błąd ujawnia się tylko w jedną stronę.

1 fragment kodu z tej strony przeszedł przez kompilator MetaEditor build 6090, 2026-08-05.

Objaw jest zawsze taki sam i zawsze zaskakuje: skrypt ustawiający stop lossa działa bez zarzutu na pozycjach długich, a na krótkich zwraca 10016. Kod jest ten sam, warunek symetryczny, a zachowanie nie.

Przyczyną jest spread i to, że w MQL5 obowiązują dwie różne ceny, zależnie od operacji.

Która cena kiedy

OperacjaCena, która obowiązuje
otwarcie pozycji długiejask
zamknięcie pozycji długiejbid
otwarcie pozycji krótkiejbid
zamknięcie pozycji krótkiejask

Z tego wynika reguła, którą warto zapamiętać w tej postaci: pozycja jest zamykana ceną przeciwną do tej, którą została otwarta.

A skoro stop loss i take profit to poziomy zamknięcia, to ich odległość liczy się od ceny zamknięcia, nie od ceny otwarcia.

PoziomSprawdzany względemMusi leżeć
stop loss pozycji długiejbidponiżej
take profit pozycji długiejbidpowyżej
stop loss pozycji krótkiejaskpowyżej
take profit pozycji krótkiejaskponiżej

Dlaczego błąd widać tylko w jedną stronę

Kod liczący oba stopy od bid daje dla pozycji długiej wynik poprawny — bo bid jest właściwą ceną odniesienia. Dla krótkiej ta sama arytmetyka przesuwa poziom o cały spread w stronę ceny. Jeśli twój dystans stopa był niewiele większy od minimalnego dystansu brokera, sprzedaże zaczną być odrzucane, a kupna przechodzić.

Na instrumencie o wąskim spreadzie problem nie ujawni się nigdy. Na złocie albo w chwili publikacji danych — natychmiast. Stąd wrażenie, że kod „czasem działa".

Jedna cena do wszystkiego
MqlTick tick;
SymbolInfoTick(_Symbol, tick);

//--- dla pozycji krótkiej ten stop leży o spread za blisko
double sl = (typ == POSITION_TYPE_BUY)
            ? tick.bid - Dystans * _Point
            : tick.bid + Dystans * _Point;
Każda strona liczona od swojej ceny
double PoziomStopa(const string symbol, const long typ, const int dystansPunktow)
  {
   MqlTick tick;
   if(!SymbolInfoTick(symbol, tick))
      return 0.0;

   double punkt = SymbolInfoDouble(symbol, SYMBOL_POINT);
   int cyfry = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   //--- pozycja dluga zamyka sie po bid, krotka po ask
   double odniesienie = (typ == POSITION_TYPE_BUY) ? tick.bid : tick.ask;
   double znak = (typ == POSITION_TYPE_BUY) ? -1.0 : 1.0;

   return NormalizeDouble(odniesienie + znak * dystansPunktow * punkt, cyfry);
  }

To samo dotyczy zleceń oczekujących

Przy zleceniach oczekujących odniesieniem jest cena otwarcia, czyli odwrotnie niż przy stopach. BUY LIMIT porównywany jest z ask, SELL LIMIT z bid. Pomylenie tego daje 10015 — również tylko po jednej stronie.

Jak to sprawdzić w trzy minuty

Powiązane