ChartGetInteger(chart_id,CHART_FIRST_VISIBLE_BAR) - BUG

 

Hi, 

the function in general works, but since the usage of the function results in unacceptable lagging of the whole EA when frequently used, it has to be called a bug. And its not new, its there since years. MQ doesn´t fix it. 

My procedure:

Whenever the chart changes, I collect all the chart data and store them into an MMF, which then can be read by indicators. Why? I have to, cuz - if the indicators read the values also - sooner or later MT will crash. So it is already a necessary workaround, to avoid a freezes and crashes. Btw: CHARTEVENT_CHART_CHANGE still lacks as well since years, not every chart change is recognized/reflected, also reported, also never fixed. This means on top: You have to check the data within OnTimer() additionally to even see all the changes, and that makes it even more worse. 

But, the collection process needs su much time, that I digged deeper and measured the time of all single ChartGetInteger, ChartGetDouble etc. functions. The main problem is clearly ChartGetInteger(chart_id,CHART_FIRST_VISIBLE_BAR), it eats up the most of the time, and that, no matter if the value has changed or not. So obviously the value isn´t even cached. Only this function takes up to 100ms and more, the average is above 50ms, whereby peaks are above 300ms!!!!

That explains, why its even impossible to use the function in an EA and indicators the same time.  The whole result, collecting all values (10) looks like this then.

Result including  CHART_FIRST_VISIBLE_BAR

 

Result without  CHART_FIRST_VISIBLE_BAR


Its obvious, the results are way better, but still ridiculously slow. But for the second result, I had to provoke several hundred of chart-changes, while the first result just needed some, its the standard, cuz CHART_FIRST_VISIBLE_BAR always lags like hell. 

The code, where I read the value, is nothing special:

//+------------------------------------------------------------------+   
   public: bool _Refresh(bool subwinrelated_only, int subwin)
      {
      bool changed=false;
      long l_value=0;
      double d_value=0;
      if (subwin<0) subwin=0;
      int scale_last=scale;
      
      if (!subwinrelated_only)
         {
         //--- Width
         if (!::ChartGetInteger(_chart_id,CHART_WIDTH_IN_PIXELS,subwin,l_value)) return false;
         changed|=(int)l_value!=width;
         width=(int)l_value;
   
         //--- Shift
         if (!::ChartGetInteger(_chart_id,CHART_SHIFT,subwin,l_value)) return false;
         changed|=(bool)l_value!=shift_status;
         shift_status=(bool)l_value;
         
         //--- Shift size
         if (!::ChartGetDouble(_chart_id,CHART_SHIFT_SIZE,subwin,d_value)) return false;
         changed|=(bool)(d_value!=shift_size);
         shift_size=(double)d_value;
   
         //--- First bar
         if (!::ChartGetInteger(_chart_id,CHART_FIRST_VISIBLE_BAR,subwin,l_value)) return false;
         changed|=(int)l_value!=firstbar_shift;
         firstbar_shift=(int)l_value;
   
         //--- Number of bars
         if (!::ChartGetInteger(_chart_id,CHART_VISIBLE_BARS,subwin,l_value)) return false;
         changed|=(int)l_value!=cntbars;
         cntbars=(int)l_value;
         
         //--- Scale
         if (!::ChartGetInteger(_chart_id,CHART_SCALE,subwin,l_value)) return false;
         changed|=(int)l_value!=scale;
         scale=(int)l_value;
         }

      //--- Y dist
      if (_chart_subwin==0) 
         offset_y=0;
      else 
         {
         if (!::ChartGetInteger(_chart_id,CHART_WINDOW_YDISTANCE,subwin,l_value)) return false;
         changed|=(int)l_value!=offset_y;
         offset_y=(int)l_value;
         }
   
      //--- Price min
      if (!::ChartGetDouble(_chart_id,CHART_PRICE_MIN,subwin,d_value)) return false;
      changed|=(bool)(d_value!=price_min);
      price_min=(double)d_value;
      
      //--- Price max
      if (!::ChartGetDouble(_chart_id,CHART_PRICE_MAX,subwin,d_value)) return false;
      changed|=(bool)(d_value!=price_max);
      price_max=(double)d_value;
   
      //--- Height
      if (!::ChartGetInteger(_chart_id,CHART_HEIGHT_IN_PIXELS,subwin,l_value)) return false;
      changed|=(int)l_value!=height;
      height=(int)l_value;
   
      //--- Calculate lastbar X
      int sub=(int)((double)width *shift_size/100.0);
      lastbar_x=width-sub;
      
      if (scale!=scale_last)
         _UpdatePixBetweenBars();

      // Create string to export in ToArrayString to avoid repeatedly creation
      if (changed && subwin==0)
         Invalidate();
      return changed;      
      }      




If anyone knows a better workaround, I'd be happy to hear about. Otherwise pls support this issue to be reported as a serious bug. 

Needless to say: Reading all the chart-data should never take more than 1ms, this could be done in a few microseconds, and it does not matter at all here, that the data is asynchronous and taken from another thread. Swiping the context, locking/reading/unlocking etc. is a matter of a few hundred nanoseconds, not eternity like it is here. No clue how MQ coded this, but its beyond of whats actually possible.  

 
PS: Latest build MT5
 

Forum on trading, automated trading systems and testing trading strategies

CopyRates - BUG

Alain Verleyen, 2025.10.26 14:05

Bug report without code and details needed to reproduce it are just ignored.

Picture of code is not code.

Incomplete code that doesn't compile is also useless.
 
Alain Verleyen #:
Incomplete code that doesn't compile is also useless.

What usesless is, is this forum. 

How many bugs did I report with code, with videos and so on. And what has ever been solved?

Nothing. 

 
Doerk Hilger #:

What usesless is, is this forum. 

How many bugs did I report with code, with videos and so on. And what has ever been solved?

Nothing. 

You are always doing the same, complaining and never willing to answer constructively.

You are not really interested to collaborate and have anything fixed. Business as usual. 

By they way I have complex code too and have no issue with CopyRates or ChartGetXXX functions.

 
//+------------------------------------------------------------------+
//|                                                  Chart_Issue.mq5 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, Dirk Hilger"
#property link      "https://www.stereotrader.net"
#property version   "1.00"

#define MICROSECONDSTOSTRING(value) ((value)>999999 ? (string)(MathFloor((value)/100000)/10)+" s" : (value>999 ? (string)(MathFloor((value)/100)/10)+" ms" : (string)MathFloor((value)) +" µs"))
void __OutDebug(string funcname, string a1, uint threshold=0)
   {
   static ulong t=::GetMicrosecondCount();
   
   ulong t2=::GetMicrosecondCount();
   uint span=(uint)(t2-t);
   if (span>threshold && a1!=NULL)
      ::Print("(",funcname,") ",a1," ("+MICROSECONDSTOSTRING(span)+")");   
   t=t2;
   }

class AlainHasNoIssues 
   {
   long        _chart_id;
   int         _chart_subwin;
   
   //--- Obtained data by function
   int         width;            // Width in pixels
   int         height;           // Height in pixels
   int         offset_y;         // Offset (subwindow)
   bool        shift_status;     // Shift on/off
   double      shift_size;       // Shift size percent
   double      price_min;        // Minimal price Y
   double      price_max;        // Maximal price Y
   int         firstbar_shift;   // Shift of first bar
   int         cntbars;          // Number of bars
   int         scale;            // Scale value
   
   int         pix_between_bars; 
   bool        pix_between_bars_valid;

   //--- Calculated by function
   int         lastbar_x;        // X of last bar in pixels
   
   //---
   
   //--- Data to be calculated (CChartExt)
   datetime    time_min;         // Minimal time X
   datetime    time_max;         // Max time X
   
   //--- User data to be calculated (CChartExt)
   int         max_x;
   int         max_y;
   int         min_x;
   int         min_y;
   int         shift_width;      // Shift with in pixels *
   int         shift_x;          // X where shift b   
   public: AlainHasNoIssues()
      {
      _chart_id=ChartID();
      }
   //+------------------------------------------------------------------+   
   public: bool Refresh(bool subwinrelated_only, int subwin)
      {
      bool changed=false;
      long l_value=0;
      double d_value=0;
      if (subwin<0) subwin=0;
      int scale_last=scale;
      
      
      if (!subwinrelated_only)
         {
         //--- Width
         if (!::ChartGetInteger(_chart_id,CHART_WIDTH_IN_PIXELS,subwin,l_value)) return false;
         changed|=(int)l_value!=width;
         width=(int)l_value;
   
         //--- Shift
         if (!::ChartGetInteger(_chart_id,CHART_SHIFT,subwin,l_value)) return false;
         changed|=(bool)l_value!=shift_status;
         shift_status=(bool)l_value;
         
         //--- Shift size
         if (!::ChartGetDouble(_chart_id,CHART_SHIFT_SIZE,subwin,d_value)) return false;
         changed|=(bool)(d_value!=shift_size);
         shift_size=(double)d_value;
   
         //--- First bar
         if (!::ChartGetInteger(_chart_id,CHART_FIRST_VISIBLE_BAR,subwin,l_value)) return false;
         changed|=(int)l_value!=firstbar_shift;
         firstbar_shift=(int)l_value;
   
         //--- Number of bars
         if (!::ChartGetInteger(_chart_id,CHART_VISIBLE_BARS,subwin,l_value)) return false;
         changed|=(int)l_value!=cntbars;
         cntbars=(int)l_value;
         
         //--- Scale
         if (!::ChartGetInteger(_chart_id,CHART_SCALE,subwin,l_value)) return false;
         changed|=(int)l_value!=scale;
         scale=(int)l_value;
         }

      //--- Y dist
      if (_chart_subwin==0) 
         offset_y=0;
      else 
         {
         if (!::ChartGetInteger(_chart_id,CHART_WINDOW_YDISTANCE,subwin,l_value)) return false;
         changed|=(int)l_value!=offset_y;
         offset_y=(int)l_value;
         }
   
      //--- Price min
      if (!::ChartGetDouble(_chart_id,CHART_PRICE_MIN,subwin,d_value)) return false;
      changed|=(bool)(d_value!=price_min);
      price_min=(double)d_value;
      
      //--- Price max
      if (!::ChartGetDouble(_chart_id,CHART_PRICE_MAX,subwin,d_value)) return false;
      changed|=(bool)(d_value!=price_max);
      price_max=(double)d_value;
   
      //--- Height
      if (!::ChartGetInteger(_chart_id,CHART_HEIGHT_IN_PIXELS,subwin,l_value)) return false;
      changed|=(int)l_value!=height;
      height=(int)l_value;
   
      //--- Calculate lastbar X
      int sub=(int)((double)width *shift_size/100.0);
      lastbar_x=width-sub;
      
      return changed;      
      }         
   };
   
   
AlainHasNoIssues _allperfect;   
   
int OnInit()
  {
  EventSetMillisecondTimer(25);
   return(INIT_SUCCEEDED);
  }
  
void OnTimer()
   {
   __OutDebug(NULL,NULL);
   _allperfect.Refresh(false,0);
   __OutDebug(NULL,"Alain would never see this, cuz he has no issues with Chartxxxx-functions, but it took: ",1000);
  
   }  
 

5 years ago, same thing - with compilable source code. 
Funfact: You were involved and confirmed the bug. 

https://www.mql5.com/en/forum/342152

ChartGetInteger() - delayed execution of up to 100ms - Bug? - How to use a timer to check chart settings and freeze in any version of MT5 or MT4
ChartGetInteger() - delayed execution of up to 100ms - Bug? - How to use a timer to check chart settings and freeze in any version of MT5 or MT4
  • 2020.05.28
  • www.mql5.com
Hi, some of us use the timer to check chart settings for synchronizing etc. Problem is as usual: once you use such a timer and you have 10 charts opened, it delays metatrader heavily and can also result in a freeze, especially when used within an indicator
 

6 years ago, related, and that was the repetition of another 5 years ago. And of course no real source code, cuz how shall I prove sth is not there with code?

https://www.mql5.com/en/forum/326220

CHARTEVENT_CHART_CHANGE - Missing events (Bug?) - How to fix missing events in MM5?
CHARTEVENT_CHART_CHANGE - Missing events (Bug?) - How to fix missing events in MM5?
  • 2019.11.11
  • www.mql5.com
The missing events force me to check these parameters every n milliseconds to detect such changes and fire the event in ontimer , which is just a workaround, but surely not the perfect reason. Some of the other missing chart events are fixed too. Just figured out, meanwhile 5 years after reported, that there are still missing events
 
Doerk Hilger #:

5 years ago, same thing - with compilable source code. 
Funfact: You were involved and confirmed the bug. 

https://www.mql5.com/en/forum/342152

You are unfair as from this old topic, the issue was reproduced AND fixed.

Forum on trading, automated trading systems and testing trading strategies

ChartGetInteger() - delayed execution of up to 100ms - Bug?

Alain Verleyen, 2025.10.26 23:58

Build 5370.

The issue was fixed a long time ago.

2025.10.26 19:56:41.942 ChartDelay (GBPUSD,H1)  Execution delay: 2 µs
2025.10.26 19:56:42.192 ChartDelay (GBPUSD,H1)  Execution delay: 1 µs
2025.10.26 19:56:42.426 ChartDelay (GBPUSD,H1)  Execution delay: 5 µs
2025.10.26 19:56:42.692 ChartDelay (GBPUSD,H1)  Execution delay: 3 µs
2025.10.26 19:56:42.927 ChartDelay (GBPUSD,H1)  Execution delay: 2 µs
2025.10.26 19:56:43.177 ChartDelay (GBPUSD,H1)  Execution delay: 2 µs
2025.10.26 19:56:43.438 ChartDelay (GBPUSD,H1)  Execution delay: 2 µs
2025.10.26 19:56:43.687 ChartDelay (GBPUSD,H1)  Execution delay: 1 µs
2025.10.26 19:56:43.924 ChartDelay (GBPUSD,H1)  Execution delay: 1 µs
2025.10.26 19:56:44.187 ChartDelay (GBPUSD,H1)  Execution delay: 2 µs

 

Doerk Hilger #:

"Alain would never see this, cuz he has no issues with Chartxxxx-functions, but it took: "

Your sarcasm is not appreciated.

By saying I have no problem with ChartGetXXX, I meant it all depends of the context. And no, in my context I don't have issue.