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
| Operacja | Cena, która obowiązuje |
|---|---|
| otwarcie pozycji długiej | ask |
| zamknięcie pozycji długiej | bid |
| otwarcie pozycji krótkiej | bid |
| zamknięcie pozycji krótkiej | ask |
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.
| Poziom | Sprawdzany względem | Musi leżeć |
|---|---|---|
| stop loss pozycji długiej | bid | poniżej |
| take profit pozycji długiej | bid | powyżej |
| stop loss pozycji krótkiej | ask | powyżej |
| take profit pozycji krótkiej | ask | poniż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".
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;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.