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

MQL5 / Pułapki

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.

Obiekty graficzne, które zamrażają wykresKażda zmiana właściwości obiektu wymusza przerysowanie. Jak rysować setki elementów bez zatrzymywania terminala. Wzorzec Dirty Checking (Sprawdzanie Stanu) Antywzorzec (OnTick) ObjectSetString (Aktualizuj P&L) ObjectSetString (Aktualizuj Spread) ChartRedraw() (Siłowe odświeżenie) Klatkowanie, 100% użycia API graficznego. Wzorzec z pamięcią podręczną if (newProfit != oldProfit) -> ObjectSetString (Tylko zmiana) Brak zbędnego obciążenia silnika.

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.
}