Obiekty graficzne, które zamrażają wykres
Każda zmiana właściwości obiektu wymusza przerysowanie. Jak rysować setki elementów bez zatrzymywania terminala.
1 fragment kodu z tej strony przeszedł przez kompilator MetaEditor build 6090, 2026-08-05.
Stworzenie interaktywnego panelu (Dashboard) na wykresie w MQL5 wydaje się proste. Używasz ObjectCreate dla przycisków i etykiet, a w OnChartEvent łapiesz kliknięcia. Jednak objawem, z którym mierzy się 90% programistów po wdrożeniu rozbudowanego GUI, jest drastyczne tąpnięcie wydajności. Wykres zaczyna klatkować, ticki są opóźnione, a terminal zużywa 30% CPU na bezczynności. Winowajcą niemal zawsze jest nieświadome wywoływanie funkcji ObjectSet... w pętli lub przy każdym ticku.
Wewnętrzny mechanizm przerysowywania (Redraw)
Kiedy zmieniasz właściwość obiektu, np. tekst na etykiecie za pomocą ObjectSetString(0, "Label1", OBJPROP_TEXT, "Nowy tekst"), terminal nie odświeża natychmiast pikseli na ekranie. Oznacza obiekt jako "brudny" (dirty) i czeka na moment bezpiecznego przerysowania. Jednak każda taka operacja wywołuje wewnętrzne zapytanie do silnika renderującego GTD (Graphics Device Interface lub DirectX). Jeśli masz 50 etykiet i przy każdym ticku aktualizujesz je wszystkie (nawet jeśli wartość się nie zmieniła), terminal musi weryfikować 50 zmian.
Wzorzec z zmiennymi Shadow (Cache)
Aby zlikwidować opóźnienia, musisz wdrożyć wzorzec "Dirty Checking". Zapamiętujesz w pamięci EA poprzedni stan obiektu i odpytujesz funkcje ObjectSet... tylko wtedy, gdy wartość faktycznie uległa zmianie. Ma to szczególne znaczenie przy liczbach zmiennoprzecinkowych, gdzie często nie zależy nam na aktualizacji 10 miejsc po przecinku.
// Zmienne przechowujące poprzedni stan ("Shadow variables")
string prevProfitText = "";
color prevProfitColor = clrNONE;
void UpdateDashboard() {
double currentProfit = AccountInfoDouble(ACCOUNT_PROFIT);
// Formatujemy tekst (np. do 2 miejsc po przecinku)
string profitStr = DoubleToString(currentProfit, 2) + " USD";
// 1. Sprawdzamy czy tekst się zmienił
if(profitStr != prevProfitText) {
ObjectSetString(0, "Label_Profit", OBJPROP_TEXT, profitStr);
prevProfitText = profitStr; // Aktualizujemy cache
}
// 2. Sprawdzamy czy zmienił się kolor (zysk/strata)
color targetColor = (currentProfit >= 0) ? clrGreen : clrRed;
if(targetColor != prevProfitColor) {
ObjectSetInteger(0, "Label_Profit", OBJPROP_COLOR, targetColor);
prevProfitColor = targetColor;
}
// UWAGA: ChartRedraw() powinno być wywoływane oszczędnie!
// Jeśli nic się nie zmieniło, w ogóle nie wywołuj ChartRedraw().
// Terminal sam odświeży wykres przy nowym ticku.
}