If I run the very same code that I sent above in other symbols where the market is closed, it works perfectly.
This is a sample log that works flawlessly for GOOG.NAS:
2020.05.19 12:33:58.532 OnCalculate_Fail (GOOG.NAS,M1) On Calculate ==> Rates total = 57612; Prev_calculated = 0 2020.05.19 12:33:58.532 OnCalculate_Fail (GOOG.NAS,M1) check_ibarshift(date = 2020.05.18 22:54:00) ==> iBarShift = -1 2020.05.19 12:33:58.532 OnCalculate_Fail (GOOG.NAS,M1) Setting Timer 2020.05.19 12:33:59.563 OnCalculate_Fail (GOOG.NAS,M1) Inside OnTimer, calling ChartSetSymbolPeriod to refresh the chart. 2020.05.19 12:33:59.585 OnCalculate_Fail (GOOG.NAS,M1) On Calculate ==> Rates total = 57612; Prev_calculated = 0 2020.05.19 12:33:59.585 OnCalculate_Fail (GOOG.NAS,M1) check_ibarshift(date = 2020.05.18 22:54:00) ==> iBarShift = 0 2020.05.19 12:33:59.585 OnCalculate_Fail (GOOG.NAS,M1) Killing Timer 2020.05.19 12:33:59.585 OnCalculate_Fail (GOOG.NAS,M1) start = 1 2020.05.19 12:33:59.597 OnCalculate_Fail (GOOG.NAS,M1) Loop end, returning rates_total = 57612
When the loop ends, rates_total returns 57612, and OnCalculate is not called anymore.
How is this even possible???
You changed the chart's symbol and period via ChartSetSymbolPeriod(0,NULL,0) so everything must be redone just as if you changed only TF.
Perhaps you should read the manual:Chart Operations / ChartSetSymbolPeriod - Reference on algorithmic/automated trading language for MetaTrader 5
Good luck if you want to convince Metaquotes developers it's a bug. It's how it works, you have no control on the number of times OnCalculate() will be called.
Using the 1 second timer, and refreshing the chart after that, works like switching to a different timeframe manually and returning back.
That's not exact, using ChartSetSymbolPeriod(0,NULL,0) is not the same as changing the timeframe. It's similar to manually click on the Refresh() command in the chart popup menu, and this can lead to SEVERAL calls of OnCalculate(). This command refresh the symbol's data and "reset" ALL the charts on the considered symbol.
Beside that, you don't need a timer at all, it's useless. Just use ChartSetSymbolPeriod().
You changed the chart's symbol and period via ChartSetSymbolPeriod(0,NULL,0) so everything must be redone just as if you changed only TF.
Perhaps you should read the manual:Ok, the title of my post is not the most appropriate since it's clear what you explain. And it makes sense that prev_calculated is 0 after the chart is refreshed.
However my code is ready to deal with that. Maybe you haven't noticed the problem in my log. I will try to be more clear. The problem is with iBarShift:
- The 1st time onCalculate is called, I check iBarShift in the other TF to see if it's ready. It's not ready, so it returns -1. This means the history in the other TF is not available, and that's why I set a timer, in order to let it load.
- A second after that, CharSetSymbolPeriod is called, so onCalculate is called again, and iBarshift in the other TF is checked again.
This time iBarShift returns 0, meaning that the history in the other TF has been FULLY loaded, because iBarShift it was called on the most current date available at the moment.
The timer is killed so no more calls to ChartSetSymbolPeriod are made. - The indicator is fully calculated.
- OnCalculate is suddenly called again, according to Alain (that knows much more than me, of course), because it can cause several calls to OnCalculate.
- iBarShift is called again to check if its ready and it returns an error!! How does that happen, if it previously returned no errors for the most current date?
Good luck if you want to convince Metaquotes developers it's a bug. It's how it works, you have no control on the number of times OnCalculate() will be called.
That's not exact, using ChartSetSymbolPeriod(0,NULL,0) is not the same as changing the timeframe. It's similar to manually click on the Refresh() command in the chart popup menu, and this can lead to SEVERAL calls of OnCalculate(). This command refresh the symbol's data and "reset" ALL the charts on the considered symbol.
Beside that, you don't need a timer at all, it's useless. Just use ChartSetSymbolPeriod().
Alain, it's not useless. I have tried the very same code without a timer, as you explained it to Favio, and it didn't work. Setting up a timer avoids calling ChartSetSymbolPeriod() a thousand times.
When the market closes again, I'll show you a log without the timer so you can believe me.
Anyway, as I replied to William, the main problem is: how is it possible that iBarShift fails after the history in the other TF was fully loaded? I mean, after I waited for one second and iBarShift returned no error for the most current date?Alain, this is my code as you suggested to Favio, without timer:
#property copyright "Copyright 2020, Carlos" #property indicator_chart_window #property indicator_buffers 1 // buffers used #property indicator_plots 1 // buffers displayed //--- Indicator Properties #property indicator_label1 "Close Value in Other TF" #property indicator_type1 DRAW_LINE #property indicator_color1 Blue #property indicator_style1 STYLE_SOLID #property indicator_width1 2 #define SECONDS_TO_WAIT 1 //--- input parameters input ENUM_TIMEFRAMES other_TimeFrame = PERIOD_D1; //--- Indicator buffer double otherTF_Buffer[]; int OnInit() { Print("Entering onInit"); //--- indicator buffers mapping SetIndexBuffer(0, otherTF_Buffer, INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,_Digits); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); return(INIT_SUCCEEDED); } 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 start; int shift; double c; // close value in the other timeframe double tf1, tf2; int offset; Print("On Calculate ==> Rates total = ", rates_total, "; Prev_calculated = ", prev_calculated); //--- Detect start position if(prev_calculated == 0) { start = 1; ArrayInitialize(otherTF_Buffer,EMPTY_VALUE); tf1 = PeriodSeconds(_Period); tf2 = PeriodSeconds(other_TimeFrame); offset = (int)ceil(tf2/tf1); } else { start = prev_calculated-offset; } //--- Main loop Print("start = ", start); for(int i = start; i < rates_total && !IsStopped(); i++) { shift = iBarShift(NULL, other_TimeFrame, time[i], false); if(shift < 0) { Print("iBarShift error #", GetLastError()); ChartSetSymbolPeriod(0,NULL,0); return 0; } c = iClose(NULL, other_TimeFrame, shift); if(c < 0) { Print("iClose error #", GetLastError()); ChartSetSymbolPeriod(0,NULL,0); return 0; } // Save the close value from the other timeframe otherTF_Buffer[i] = c; } //--- return value of prev_calculated for next call Print("Loop end, returning rates_total = ", rates_total); return(rates_total); }
I keep having the same problems for some symbols as with my original code with the timer. However removing the timer makes the indicator blink between being painted and not, as the problem is that iBarShift suddenly works for a moment, and the next call to OnCalculate it returns and error; next time it works again and next it doesn't, just as I explained in my previous answer.
This doesn't make any sense, since once the history in the other TF is loaded, iBarShift should not return an error anymore. Isn't that right, or am I missing something?
2020.05.19 18:36:33.753 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.753 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.753 OnCalculate_Fail (WTI_M0,D1) Loop end, returning rates_total = 134 2020.05.19 18:36:33.780 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.780 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.780 OnCalculate_Fail (WTI_M0,D1) iBarShift error #4401 2020.05.19 18:36:33.834 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.834 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.834 OnCalculate_Fail (WTI_M0,D1) Loop end, returning rates_total = 134 2020.05.19 18:36:33.860 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.860 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.860 OnCalculate_Fail (WTI_M0,D1) iBarShift error #4401 2020.05.19 18:36:33.918 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.918 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.918 OnCalculate_Fail (WTI_M0,D1) Loop end, returning rates_total = 134 2020.05.19 18:36:33.947 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:33.947 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:33.947 OnCalculate_Fail (WTI_M0,D1) iBarShift error #4401 2020.05.19 18:36:34.002 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:34.002 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:34.002 OnCalculate_Fail (WTI_M0,D1) Loop end, returning rates_total = 134 2020.05.19 18:36:34.031 OnCalculate_Fail (WTI_M0,D1) On Calculate ==> Rates total = 134; Prev_calculated = 0 2020.05.19 18:36:34.031 OnCalculate_Fail (WTI_M0,D1) start = 1 2020.05.19 18:36:34.031 OnCalculate_Fail (WTI_M0,D1) iBarShift error #4401
As you can see it goes forever like that.
Alain, this is my code as you suggested to Favio, without timer:
I keep having the same problems for some symbols as with my original code with the timer. However removing the timer makes the indicator blink between being painted and not, as the problem is that iBarShift suddenly works for a moment, and the next call to OnCalculate it returns and error; next time it works again and next it doesn't, just as I explained in my previous answer.
This doesn't make any sense, since once the history in the other TF is loaded, iBarShift should not return an error anymore. Isn't that
right, or am I missing something?
As you can see it goes forever like that.
As you can see the ChartSetSymbolPeriod() send 2 "reset" commands, why ? No idea.
As you can see all is going well on the first, and you get the iBarShift error on the second, why ? No idea.
A bug or a feature, we don't know but I am sure, by experience, it will be hard to convince the developers it's a weird behaviour.
Here is a solution, without a timer.
bool AllDone=false; int OnInit() { AllDone=false; Print("Entering onInit"); //--- indicator buffers mapping SetIndexBuffer(0, otherTF_Buffer, INDICATOR_DATA); IndicatorSetInteger(INDICATOR_DIGITS,_Digits); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); return(INIT_SUCCEEDED); } 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 start; int shift; double c; // close value in the other timeframe double tf1, tf2; int offset=0; Print("On Calculate ==> Rates total = ", rates_total, "; Prev_calculated = ", prev_calculated); //--- Detect start position if(prev_calculated == 0) { start = 1; ArrayInitialize(otherTF_Buffer,EMPTY_VALUE); tf1 = PeriodSeconds(_Period); tf2 = PeriodSeconds(other_TimeFrame); offset = (int)ceil(tf2/tf1); } else { start = prev_calculated-offset; } //--- Main loop Print("start = ", start); for(int i = start; i < rates_total && !IsStopped(); i++) { shift = iBarShift(NULL, other_TimeFrame, time[i], false); if(shift < 0) { Print("iBarShift error #", GetLastError(), " ",time[i]); if(!AllDone) ChartSetSymbolPeriod(0,NULL,0); return(0); } c = iClose(NULL, other_TimeFrame, shift); if(c < 0) { Print("iClose error #", GetLastError()); if(!AllDone) ChartSetSymbolPeriod(0,NULL,0); return(0); } // Save the close value from the other timeframe otherTF_Buffer[i] = c; } AllDone=true; //--- return value of prev_calculated for next call Print("Loop end, returning rates_total = ", rates_total); return(rates_total); }
Please note that most of the time I provide a clue towards the solution, it's not my responsibility to provide a solution that takes into account
all possibilities.
As you can see the ChartSetSymbolPeriod() send 2 "reset" commands, why ? No idea.
As you can see all is going well on the first, and you get the iBarShift error on the second, why ? No idea.
A bug or a feature, we don't know but I am sure, by experience, it will be hard to convince the developers it's a weird behaviour.
Here is a solution, without a timer.
Please note that most of the time I provide a clue towards the solution, it's not my responsibility to provide a solution that takes into account all possibilities.
Thank you for your time and help Alain.
Everything is a bit strange, since the problem I described yesterday has not happened to me anymore. I have been testing dozens of american stocks with markets closed and my original code didn't fail anymore. Anyway thanks again for your idea, it helped me too.
Thank you for your time and help Alain.
Everything is a bit strange, since the problem I described yesterday has not happened to me anymore. I have been testing dozens of american stocks with markets closed and my original code didn't fail anymore. Anyway thanks again for your idea, it helped me too.
With the last code you posted (no timer), it's easy to reproduce.
I asked to a Metaquotes developer his opinion, we will see if he answers me.
With the last code you posted (no timer), it's easy to reproduce.
I asked to a Metaquotes developer his opinion, we will see if he answers me.
Thank you again, Alain, very nice of you. I hope he answers you, since the problem it's quite random. Yesterday it didn't happen to me with any
symbol, but today it's happening again.
However, given your extensive experience, I am aware that the developers will most likely not take this
into account :)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hello everybody,
I was trying to solve this well-known problem explained by Fabio Cavalloni and others, when I have discovered some really strange behaviour in OnCalculate.
I have written a small sample program that reads the closing value in a different timeframe. Inside onCalculate, I check whether iBarShift is ready or not:
Using the 1 second timer, and refreshing the chart after that, works like switching to a different timeframe manually and returning back.
This is the code, which I have tried on american stocks outside market hours:
The problem with this code is that sometimes it works, sometimes it doesn't, and when it fails, I have tried to trace back the error, and I have surprisingly found that I'm returning rates_total = 36037 bars, but the very next call to OnCalculate, prev_calculated is equal to 0!!!
How is this even possible??? It doesn't only happen with ADBE.NAS, it happens randomly with other stocks or symbols when the respective market is closed. But it doesn't happen always, other times my code works like a charm. That's why I think it's a bug.
This is the example log where you can see the bug:
I hope somebody can confirm whether it's a bug or at least can shed some light on the matter.I have tried the code both on the latest MT5 Release version, and I have even installed the Beta 2431, but the problem remains.