Canvas Lagging when chart is scrolled.

 

Good morning, i''m new in the mql5 community.

I created an indicator to show day separators.

First I coded it using the default OBJ_VLINE, but then I moved to canvas since I want to have the line transparent.

At the moment I'm just updating the Canvas if OnChartEvent is called (for easier testing), but I've noticed that when I scroll the chart, the lines "lags", and they take some time to update to the new position.

Is there something is doing wrong? Maybe some slow function? Or am I missing something?

Thanks in advance.

#property indicator_chart_window
#property indicator_plots 0

#include <System/Canvas/Canvas.mqh>

//+------------------------------------------------------------------+
//| DaySeparator struct                                              |
//+------------------------------------------------------------------+
struct DaySeparator {
    
    string      objName;
    datetime    time;

    DaySeparator() {
        objName = "";
        time = 0;
    }

};

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
CCanvas         Canvas;
string          CurrentDay = "";
DaySeparator    CurrDaySep;
DaySeparator    DaySeparators[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
    Canvas.CreateBitmapLabel(0, 0, "Canvas Test 1", 0, 0, 200, 150, COLOR_FORMAT_ARGB_NORMALIZE);
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)  {
    Canvas.Destroy();
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[]) {
    
    int toCalculate = prev_calculated == 0 ? rates_total : rates_total - prev_calculated + 1;
    int start = rates_total - toCalculate;
    
    for(int i = start; i < rates_total; i++) {
        
        string strDay = TimeToString(time[i], TIME_DATE);

        if(CurrentDay != strDay) {
            CurrentDay = strDay;    
            
            //Save day separator
            int totDaySeps = ArraySize(DaySeparators);
            ArrayResize(DaySeparators, totDaySeps + 1);
            DaySeparators[totDaySeps] = CurrDaySep;

            //Set day separator
            CurrDaySep.objName = "SessionRanges - Daily separator " + strDay;
            CurrDaySep.time = time[i];
        }
    }

    return rates_total;
}

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
    if(id != CHARTEVENT_CHART_CHANGE) { return; }

    RedrawCanvas();
}

//+------------------------------------------------------------------+
//| Redraw Canvas                                                    |
//+------------------------------------------------------------------+
void RedrawCanvas() {
    uint default_color = 0;
    
    //Canvas erase
    Canvas.Erase(default_color);
    
    int chartFirstBar = int(ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR));
    int chartVisibleBars = int(ChartGetInteger(0, CHART_VISIBLE_BARS));
    int chartScale = int(ChartGetInteger(0, CHART_SCALE));
    int chartHeight = int(ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS));
    int chartWidth = int(ChartGetInteger(0, CHART_WIDTH_IN_PIXELS));

    Canvas.Resize(chartWidth, chartHeight);

    datetime time1 = iTime(_Symbol, _Period, chartFirstBar);
    datetime time2 = iTime(_Symbol, _Period, chartFirstBar - chartVisibleBars);

    datetime lastTime = iTime(_Symbol, _Period, 0);
    if(time2 < time1) { time2 = lastTime; }

    //Draw day separators
    for(int i = 0; i < ArraySize(DaySeparators); i++) {
        if(DaySeparators[i].time < time1 || DaySeparators[i].time > time2)
            continue;
        
        int barShift = iBarShift(_Symbol, _Period, DaySeparators[i].time);
        int xPosition = ShiftToX(chartFirstBar, chartScale, barShift);
        Canvas.LineThickVertical(xPosition, 0, chartHeight, ColorToARGB(clrRed, 140), 2, STYLE_DASH, LINE_END_BUTT);
    }

    //Canvas update
    Canvas.Update();
}

//+------------------------------------------------------------------+
//| Converts the bar index (as series) to x in pixels                |
//+------------------------------------------------------------------+
int ShiftToX(int chartFirstBar, int chartScale, int index) {
    return (chartFirstBar - index) * BarWidth(chartScale) - 1;
}

//+------------------------------------------------------------------+
//| Converts the price to y in pixels                                |
//+------------------------------------------------------------------+
int PriceToY(int chartHeight, double chartMax, double chartMin, double price) {
   if(chartMax - chartMin == 0) { return 0; }
   return int(round(chartHeight * (chartMax - price) / (chartMax - chartMin) - 1));
}

//+------------------------------------------------------------------+
//| Converts the chart scale property to bar width/spacing           |
//+------------------------------------------------------------------+
int BarWidth(int scale) {
    return int(pow(2, scale));
}

//+------------------------------------------------------------------+


 

 
Paolo Besana:

Good morning, i''m new in the mql5 community.

I created an indicator to show day separators.

First I coded it using the default OBJ_VLINE, but then I moved to canvas since I want to have the line transparent.

At the moment I'm just updating the Canvas if OnChartEvent is called (for easier testing), but I've noticed that when I scroll the chart, the lines "lags", and they take some time to update to the new position.

Is there something is doing wrong? Maybe some slow function? Or am I missing something?

Thanks in advance.

In my opinion, at the moment there is only one way to solve the problem of delays. It is necessary to disable the native chart, and draw this chart also on the canvas. I understand that you will not like this solution. But until MQ changes the lagging event model with very slow ChartGet functions..., there is no other way to do it. Moreover, this approach has several great performance advantages, but this is a separate topic.
It is also necessary to remember that in the Expert this lag will be several times less than in the indicator.
How to create your own chart on canvas, you can see this example(The time for forming a canvas chart with bars is approximately 0.1-0.2 milliseconds.):

Files:
iCanvas_CB.mqh  71 kb
CanvasBar.mq5  4 kb
 
Nikolai Semko #:

In my opinion, at the moment there is only one way to solve the problem of delays. It is necessary to disable the native chart, and draw this chart also on the canvas. I understand that you will not like this solution. But until MQ changes the lagging event model with very slow ChartGet functions..., there is no other way to do it. Moreover, this approach has several great performance advantages, but this is a separate topic.
It is also necessary to remember that in the Expert this lag will be several times less than in the indicator.
How to create your own chart on canvas, you can see this example(The time for forming a canvas chart with bars is approximately 0.1-0.2 milliseconds.):

Hi Nikolai,

I will try to implement what you suggested, as it seems to be the only solution if I want to use transparent objects without scroll "lag".

My only question now is if it is worth it for just a "sessions and days separator" indicator, maybe I should use this for more complicated projects...

Lets hope MQ will solve this in the near future...

Thanks for your response.

 
Paolo Besana #:
Hi Nikolai,

I will try to implement what you suggested, as it seems to be the only solution if I want to use transparent objects without scroll "lag".

My only question now is if it is worth it for just a "sessions and days separator" indicator, maybe I should use this for more complicated projects...

Lets hope MQ will solve this in the near future...

Thanks for your response.

Just remember that other indicators will not be displayed on the canvas.
Reason: