Pętla we wskaźniku zatrzymuje wszystkie wskaźniki
Wszystkie wskaźniki jednego instrumentu dzielą jeden wątek. Pętla w jednym z nich zatrzymuje pozostałe, także na innych wykresach.
2 fragmenty kodu z tej strony przeszły przez kompilator MetaEditor build 6090, 2026-08-05.
To jest fakt z dokumentacji, który prawie nikt nie kojarzy, a wyjaśnia całą klasę „zawieszeń MetaTradera":
Wszystkie wskaźniki policzone dla jednego instrumentu pracują w jednym wątku — niezależnie od tego, na ilu wykresach są podpięte.
Ekspert ma własny wątek. Skrypt ma własny wątek. Wskaźniki na EURUSD mają jeden wspólny. Jeśli któryś z nich wejdzie w długą pętlę, pozostałe czekają.
Co z tego wynika
Wskaźnik z pętlą oczekującą na dane blokuje nie tylko siebie. Blokuje każdy inny wskaźnik na tym samym instrumencie, na wszystkich otwartych wykresach. Objawia się to jako zamrożony terminal, choć terminal działa poprawnie — po prostu czeka na twój kod.
while(!IsStopped())
{
int skopiowane = CopyTicks(_Symbol, ticks, COPY_TICKS_ALL, ostatniCzas, 1000000);
if(skopiowane > 0)
break;
}Ta pętla wygląda niewinnie i w ekspercie byłaby tylko marnotrawstwem. We wskaźniku wiesza wszystkie wskaźniki na tym symbolu.
Trzy ograniczenia wskaźników, o których warto wiedzieć
Nie ma Sleep. Funkcja nie działa we wskaźnikach w ogóle. To nie jest przeoczenie MetaQuotes, tylko konsekwencja wspólnego wątku: uśpienie jednego wskaźnika uśpiłoby wszystkie.
Jest limit czasu na zakończenie. Po zażądaniu zatrzymania program ma około dwóch i pół sekundy na dokończenie pracy. Po tym czasie zostaje przerwany przymusowo. Stąd IsStopped() w pętli — sprawdzanie tej funkcji pozwala wyjść, zanim terminal zrobi to za ciebie.
Wskaźnik nie powinien czekać na cokolwiek. Ani na dane, ani na sieć, ani na plik. Jeśli danych nie ma, właściwą reakcją jest zwrócenie wartości i policzenie ich przy kolejnym wywołaniu.
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
//--- dane niekompletne? oddajemy sterowanie, wrócimy przy kolejnym ticku
if(rates_total < 100)
return 0;
//--- zwrócenie zera oznacza: policz mnie od nowa następnym razem
return rates_total;
}Jak sprawdzić, który wskaźnik zamula
Terminal nie powie tego wprost, ale da się to zmierzyć. GetMicrosecondCount zwraca licznik mikrosekund niezależny od zegara systemowego.
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
{
ulong start = GetMicrosecondCount();
//--- tu właściwe obliczenia
ulong trwalo = GetMicrosecondCount() - start;
if(trwalo > 50000) // ponad 50 milisekund
PrintFormat("wskaznik | przeliczenie trwalo %.1f ms | swiec: %d",
trwalo / 1000.0, rates_total - prev_calculated);
return rates_total;
}Wpis pojawiający się przy każdym ticku znaczy, że wskaźnik liczy całą historię zamiast przyrostu — patrz IndicatorCounted i prev_calculated.
Wyjątek: dane spoza terminala
Jeśli wskaźnik naprawdę musi sięgnąć po coś wolnego — plik, zapytanie sieciowe — nie rób tego we wskaźniku. Właściwym miejscem jest usługa: program MQL5 działający w tle, z własnym wątkiem, który zapisuje wynik tam, gdzie wskaźnik go tylko odczyta. Wskaźnik pozostaje wtedy tym, czym ma być: funkcją liczącą, która zawsze kończy się szybko.