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
- Uchwyt —
iMAzwraca liczbę identyfikującą policzony wskaźnik. Tworzysz go raz, wOnInit. - Kopia danych —
CopyBufferprzepisuje wartości z bufora wskaźnika do twojej tablicy. Robisz to wtedy, gdy potrzebujesz liczb.
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.
| Ustawienie | tablica[0] | tablica[2] |
|---|---|---|
ArraySetAsSeries(t, true) | świeca bieżąca | trzecia od końca |
domyślnie (false) | najstarsza z pobranych | o 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:
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.