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

MQL5 / Pułapki

Ekspert, który przestał handlować i nic nie powiedział

Uśmiechnięta buźka na wykresie, terminal połączony, dziennik pusty, a transakcji nie ma od trzech dni. Sześć przyczyn i gotowy czujnik życia.

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

To jest jeden z najczęściej zgłaszanych i najgorzej opisanych problemów w MQL5. Objaw zawsze wygląda tak samo: ekspert stoi na wykresie, buźka się uśmiecha, terminal jest połączony, w dzienniku ani jednego błędu — a od kilku dni nie ma transakcji. Właściciel dowiaduje się o tym przypadkiem, przy ręcznym sprawdzeniu rachunku.

Problem nie polega na tym, że ekspert przestał działać. Polega na tym, że nikt się o tym nie dowiedział.

Sześć przyczyn, w kolejności częstości

1. Pętla w OnTick, z której nie ma wyjścia. Najgorszy przypadek, bo wygląda dokładnie tak jak w zgłoszeniach: buźka jest, błędów nie ma. Terminal nie przerywa działającej funkcji ani nie zgłasza, że trwa ona od godziny. Kolejne ticki są po prostu pomijane. Typowe źródło to pętla oczekująca na dane, które nigdy nie przyjdą.

2. Uchwyt wskaźnika, który przestał być ważny. Po zmianie symbolu, po utracie połączenia albo po przeliczeniu historii CopyBuffer zaczyna zwracać -1. Kod z poprawnym if(CopyBuffer(...) < 0) return; wychodzi wtedy z OnTick przy każdym ticku — na zawsze, cicho i bez komunikatu.

3. Wyłączony przycisk handlu. Ktoś kliknął, terminal się zaktualizował, komputer wstał z uśpienia. Ekspert liczy dalej, tylko zlecenia nie wychodzą.

4. Warunek, który już nigdy nie będzie prawdziwy. Zmienna zapamiętana w złym momencie: licznik pozycji, flaga „mam otwartą pozycję" ustawiona przed rozłączeniem, lastTradeTime z przyszłości po zmianie czasu na serwerze.

5. Instrument w trybie tylko do zamykania. Kontrakt terminowy przed wygaśnięciem, akcja przed zawieszeniem obrotu. Opisaliśmy to przy SYMBOL_TRADE_MODE.

6. Ekspert, którego już tam nie ma. Zmiana profilu, przypadkowe usunięcie z wykresu, awaria terminala i restart bez przywrócenia szablonu. Buźka, którą widzisz, bywa na innym wykresie niż ten, na który patrzysz.

Czujnik życia

Rozwiązanie nie polega na naprawianiu przyczyn — jest ich za dużo. Polega na tym, żeby ekspert regularnie meldował, że żyje, a ty żebyś to widział bez otwierania terminala.

Najprostszy mechanizm wykorzystuje zmienne globalne terminala: przeżywają restart, mają własny znacznik czasu i widać je w oknie Narzędzia → Zmienne globalne bez grzebania w kodzie.

Melduję, że żyję
input ulong Magic = 12345;

string NazwaCzujnika(void)
  {
   return StringFormat("zycie_%s_%I64u", _Symbol, Magic);
  }

//--- wywoływane z OnTick i z OnTimer
void ZameldujZycie(const string etap)
  {
   GlobalVariableSet(NazwaCzujnika(), (double)TimeCurrent());

   static datetime ostatniWpis = 0;
   if(TimeCurrent() - ostatniWpis >= 3600)
     {
      ostatniWpis = TimeCurrent();
      PrintFormat("czujnik | %s | pozycji: %d | handel: %s",
                  etap, PositionsTotal(),
                  TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) ? "tak" : "NIE");
     }
  }

Wywołanie stawia się na końcu OnTick, nie na początku. Wtedy brak świeżego wpisu znaczy, że funkcja nie dobiegła końca — czyli dokładnie przypadek pierwszy z listy.

Dodatkowo warto wywoływać je z OnTimer, bo OnTick nie przyjdzie w weekend ani przy zerwanym połączeniu, a to też jest informacja.

Timer wykrywa ciszę, której OnTick nie wykryje
int OnInit()
  {
   EventSetTimer(300);
   return INIT_SUCCEEDED;
  }

void OnTimer()
  {
   datetime ostatniTick = (datetime)SymbolInfoInteger(_Symbol, SYMBOL_TIME);
   int cisza = (int)(TimeCurrent() - ostatniTick);

   if(cisza > 900 && TerminalInfoInteger(TERMINAL_CONNECTED))
      PrintFormat("czujnik | brak kwotowań od %d sekund", cisza);

   ZameldujZycie("timer");
  }

Diagnoza po fakcie

Gdy ekspert już zamilkł, kolejność sprawdzania jest taka:

  1. Czy zmienna globalna czujnika ma świeży czas? Jeśli nie — OnTick się nie kończy albo eksperta nie ma na wykresie.
  2. Czy w zakładce Dziennik są wpisy o rozłączeniach? Po każdym rozłączeniu uchwyty wskaźników bywają unieważniane.
  3. Czy TERMINAL_TRADE_ALLOWED i MQL_TRADE_ALLOWED są prawdziwe?
  4. Czy instrument nadal jest w oknie Rynek i ma świeże kwotowania?

Trzy z tych czterech pytań ekspert może sobie zadać sam, przy każdym wywołaniu timera — i to jest cała różnica między systemem, który mówi, co mu jest, a takim, który po prostu milczy.

Powiązane