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

MQL5 / Kurs / Lekcja 5 z 7

Wskaźniki i CopyBuffer

Uchwyt tworzysz raz w OnInit, dane kopiujesz w OnTick. Co się dzieje, gdy zrobisz odwrotnie, i skąd bierze się błąd 4806.

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

W MQL4 wartość średniej pobierało się jednym wywołaniem iMA w miejscu, gdzie była potrzebna. W MQL5 to samo zajmuje dwa kroki i to jest największa zmiana mentalna przy przesiadce.

Dwa kroki zamiast jednego

  1. UchwytiMA zwraca liczbę identyfikującą policzony wskaźnik. Tworzysz go raz, w OnInit.
  2. Kopia danychCopyBuffer przepisuje wartości z bufora wskaźnika do twojej tablicy. Robisz to wtedy, gdy potrzebujesz liczb.
Kompletny szkielet eksperta ze średnią
input int OkresSredniej = 20;

int uchwytSredniej = INVALID_HANDLE;

int OnInit()
  {
   uchwytSredniej = iMA(_Symbol, _Period, OkresSredniej, 0, MODE_SMA, PRICE_CLOSE);

   if(uchwytSredniej == INVALID_HANDLE)
     {
      PrintFormat("Nie udało się utworzyć wskaźnika. Kod błędu: %d", GetLastError());
      return INIT_FAILED;
     }
   return INIT_SUCCEEDED;
  }

void OnDeinit(const int powod)
  {
   if(uchwytSredniej != INVALID_HANDLE)
      IndicatorRelease(uchwytSredniej);
  }

void OnTick()
  {
   double srednia[];
   ArraySetAsSeries(srednia, true);

   //--- 3 wartości, licząc od świecy bieżącej wstecz
   if(CopyBuffer(uchwytSredniej, 0, 0, 3, srednia) < 3)
     {
      PrintFormat("CopyBuffer nie zwrócił danych. Kod błędu: %d", GetLastError());
      return;
     }

   PrintFormat("SMA(%d): świeca 1 = %.*f", OkresSredniej, _Digits, srednia[1]);
  }

Co znaczą argumenty CopyBuffer

CopyBuffer(uchwyt, numer_bufora, pozycja_startowa, ile, tablica)
  • numer_bufora — który bufor wskaźnika. Średnia ma jeden, czyli 0. MACD ma dwa: linię główną (0) i sygnalną (1). Bollinger ma trzy.
  • pozycja_startowa — od której świecy zaczynamy kopiowanie, licząc wstecz od bieżącej. Zero to świeca bieżąca.
  • ile — ile wartości skopiować.

Funkcja zwraca liczbę faktycznie skopiowanych elementów albo -1 przy błędzie. Sprawdzanie tej wartości nie jest ozdobnikiem — to jedyny sposób, żeby się dowiedzieć, że dane jeszcze nie dojechały.

ArraySetAsSeries decyduje o kierunku

To jest miejsce, w którym najłatwiej o cichy błąd. ArraySetAsSeries(tablica, true) sprawia, że indeks 0 oznacza świecę najnowszą, tak jak na wykresie. Bez tego wywołania indeks 0 to element najstarszy ze skopiowanych.

Ustawienietablica[0]tablica[2]
ArraySetAsSeries(t, true)świeca bieżącatrzecia od końca
domyślnie (false)najstarsza z pobranycho dwie młodsza

Kod bez ArraySetAsSeries skompiluje się i wykona. Po prostu będzie czytał sygnał ze świecy sprzed dwudziestu okresów i nikt ci o tym nie powie. Jeśli chcesz zobaczyć te indeksy w ruchu, mamy do tego wizualizator.

Skąd błąd 4806 zaraz po starcie

Utworzenie uchwytu nie znaczy, że wskaźnik jest już policzony. Terminal robi to w tle. Jeśli wywołasz CopyBuffer w tej samej linijce co iMA, dostaniesz -1 i kod błędu 4806 — dane nie zostały znalezione.

Wskaźnik na wskaźniku i wskaźnik własny

iCustom działa tak samo, tylko nazwę wskaźnika podajesz tekstem, a jego parametry doklejasz na końcu:

Uchwyt do wskaźnika własnego
int uchwyt = iCustom(_Symbol, _Period, "MojFolder\\MojWskaznik", 14, 3);

Podwójny ukośnik jest konieczny, bo pojedynczy w łańcuchu znakowym rozpoczyna sekwencję sterującą. Ścieżka liczy się od katalogu MQL5\Indicators.

Zadanie

Przerób powyższego eksperta tak, żeby korzystał z dwóch średnich o różnych okresach i wypisywał w dzienniku słowo przeciecie, kiedy szybsza przetnie wolniejszą — porównując wartości ze świec 1 i 2, nigdy ze świecy 0. Zwolnij oba uchwyty w OnDeinit.