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

MQL5 / Przepisy

Filtr wiadomości bez internetu

MetaTrader ma wbudowany kalendarz dostępny z poziomu kodu. Nie wymaga zapytań sieciowych ani listy dozwolonych adresów, a prawie nikt o nim nie wie.

5 fragmentów kodu z tej strony przeszło przez kompilator MetaEditor build 6090, 2026-08-05.

Typowe rozwiązanie problemu „nie handluj w czasie publikacji danych" wygląda tak: pobrać kalendarz z jakiejś strony przez WebRequest, przeparsować, zapisać do pliku. Wymaga to dodania adresu do listy w ustawieniach, działa tylko przy połączeniu i psuje się, gdy strona zmieni format.

Nie trzeba tego robić. Terminal ma kalendarz wbudowany i dostępny z poziomu MQL5, razem z prognozami, wartościami rzeczywistymi i oceną ważności.

Trzy funkcje, które wystarczą

FunkcjaDo czego
CalendarValueHistorywszystkie wydarzenia z zadanego przedziału czasu
CalendarEventByIdopis wydarzenia: nazwa, ważność, kraj
CalendarValueLastwyłącznie to, co zmieniło się od poprzedniego sprawdzenia

Pierwsza wystarcza do filtra czasowego, druga do rozpoznania, czy publikacja jest istotna, trzecia do reagowania na napływające wyniki.

Filtr

Czy w pobliżu jest publikacja ważnych danych
input int MinutPrzed = 30;
input int MinutPo    = 15;

bool BlisokPublikacji(const string waluta)
  {
   MqlCalendarValue wartosci[];

   datetime od = TimeCurrent() - MinutPo * 60;
   datetime doo = TimeCurrent() + MinutPrzed * 60;

   //--- pusty kod kraju, filtrujemy po walucie instrumentu
   int ile = CalendarValueHistory(wartosci, od, doo, NULL, waluta);
   if(ile <= 0)
      return false;

   for(int i = 0; i < ile; i++)
     {
      MqlCalendarEvent wydarzenie;
      if(!CalendarEventById(wartosci[i].event_id, wydarzenie))
         continue;

      if(wydarzenie.importance != CALENDAR_IMPORTANCE_HIGH)
         continue;

      PrintFormat("Publikacja %s o %s - wstrzymuje wejscia",
                  wydarzenie.name,
                  TimeToString(wartosci[i].time, TIME_MINUTES));
      return true;
     }

   return false;
  }

Waluta instrumentu bierze się z jego właściwości, więc filtr sam dopasowuje się do tego, na czym stoi ekspert:

Waluty, które dotyczą tego instrumentu
string bazowa = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
string zysku  = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);

if(BlisokPublikacji(bazowa) || BlisokPublikacji(zysku))
   return;

Dla EURUSD sprawdzi to wydarzenia dla euro i dolara, dla złota — dla dolara. Bez wpisywania czegokolwiek na sztywno.

Wartości są przemnożone przez milion

To jest fakt, który zaskakuje każdego przy pierwszym użyciu i nie wynika z niczego oczywistego. Pola actual_value, forecast_value i prev_value są typu całkowitego i przechowują liczbę pomnożoną przez 1 000 000.

Do tego brak wartości nie jest zerem, tylko najmniejszą możliwą liczbą typu long. Wydarzenie, którego wynik jeszcze nie został opublikowany, ma tam LONG_MIN — i potraktowanie tego jak liczby daje wynik, który wygląda jak gigantyczny spadek.

Poprawny odczyt wartości liczbowej
double WartoscRzeczywista(const MqlCalendarValue &wartosc, bool &jest)
  {
   jest = (wartosc.actual_value != LONG_MIN);
   if(!jest)
      return 0.0;

   return wartosc.actual_value / 1000000.0;
  }

Ważność ma cztery poziomy

CALENDAR_IMPORTANCE_NONE, _LOW, _MODERATE i _HIGH. Filtrowanie wyłącznie po najwyższym poziomie przepuszcza sporo publikacji, które realnie ruszają rynkiem — indeksy nastrojów, wystąpienia przedstawicieli banków centralnych. Z drugiej strony wpuszczenie poziomu niskiego zablokuje handel na pół dnia, bo drobnych odczytów jest kilkadziesiąt dziennie.

Rozsądny punkt wyjścia to poziom wysoki i umiarkowany, z parametrem pozwalającym użytkownikowi to zmienić.

Reagowanie na napływające wyniki

CalendarValueLast działa inaczej niż pozostałe: przyjmuje identyfikator zmiany i zwraca wyłącznie to, co pojawiło się po nim. Dzięki temu nie trzeba przy każdym wywołaniu przeglądać całego dnia.

Tylko to, co nowe od poprzedniego sprawdzenia
ulong ostatniaZmiana = 0;

void OnTimer()
  {
   MqlCalendarValue nowe[];

   int ile = CalendarValueLast(ostatniaZmiana, nowe, NULL, "USD");
   if(ile <= 0)
      return;

   for(int i = 0; i < ile; i++)
      if(nowe[i].actual_value != LONG_MIN)
         PrintFormat("Nowy odczyt: wydarzenie %I64u, wartosc %.2f",
                     nowe[i].event_id, nowe[i].actual_value / 1000000.0);
  }

Zmienna ostatniaZmiana jest aktualizowana przez samą funkcję. Przy pierwszym wywołaniu z zerem dostaniesz komplet bieżących danych, przy kolejnych — tylko różnicę.

Czego kalendarz nie zrobi

Nie powie, jak rynek zareaguje. Nie zastąpi też filtra zmienności — publikacja o niskiej ważności potrafi ruszyć instrumentem mocniej niż wysoka, jeśli odczyt bardzo odbiegnie od prognozy. Do tego drugiego przydaje się porównanie actual_value z forecast_value, ale to już jest decyzja strategiczna, a nie techniczna.

Powiązane