Download MetaTrader 5

OnTimer being delayed because of OnCalculate.

To add comments, please log in or register
Alexander Martinez
578
Alexander Martinez  

I set EventSetTimer(1) in OnInit (bool result is "true") , and I put my code in void OnTimer, but the indicator is still going through OnCalculate, which defeats the purpose of using OnTimer because the data received from the broker isn't faster than 1 second in some cases.

Is there a way around this issue?

int OnInit(){
   bool setTimer = EventSetTimer(1);
   return(INIT_SUCCEEDED);
}

void OnTimer(){
   // code for a countdown timer here
}
Documentation on MQL5: Standard Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Standard Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
Standard Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions - Reference on algorithmic/automated trading language for MetaTrader 5
honest_knave
Moderator
2342
honest_knave  
user3822:

I set EventSetTimer(1) in OnInit (bool result is "true") , and I put my code in void OnTimer, but the indicator is still going through OnCalculate, which defeats the purpose of using OnTimer because the data received from the broker isn't faster than 1 second in some cases.

Is there a way around this issue?


OnInit() will run, then immediately OnCalculate() runs (it doesn't wait for a tick), then it waits for the first tick before subsequent calls to OnCalculate().

It isn't usually a problem - if you don't want anything to run in OnCalculate() don't put any code in there!

If you want stuff to run in OnCalculate() only after OnTimer() has run, then use a simple flag e.g.

#property strict
#property indicator_chart_window

bool timer_run; // flag

//+------------------------------------------------------------------+
//| OnInit()                                                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   timer_run = false;
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| OnCalculate()                                                    |
//+------------------------------------------------------------------+
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[])
  {
   if(!timer_run) return(rates_total);
   // rest of your code that only runs after OnTimer() has been run
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| OnTimer()                                                        |
//+------------------------------------------------------------------+
void OnTimer()
  {
   timer_run = true;
  }
Alexander Martinez
578
Alexander Martinez  
honest_knave:


OnInit() will run, then immediately OnCalculate() runs (it doesn't wait for a tick), then it waits for the first tick before subsequent calls to OnCalculate().

It isn't usually a problem - if you don't want anything to run in OnCalculate() don't put any code in there!

If you want stuff to run in OnCalculate() only after OnTimer() has run, then use a simple flag e.g.

There's no code in OnCalculate, though, other than return(rates_total).

The program is a countdown timer in the form of mm:ss.

I want the code to execute every second, but if new tick data isn't received in a second or less, the program doesn't execute any further because it's waiting for OnCalculate to receive new data.

I hope that clears it up.

honest_knave
Moderator
2342
honest_knave  
user3822:

There's no code in OnCalculate, though, other than return(rates_total).

The program is a countdown timer in the form of mm:ss.

I want the code to execute every second, but if new data isn't received in a second or less, the program doesn't execute any further because it's waiting for OnCalculate to receive new data.

I hope that clears it up.


That's not what should happen; post up some more of your code. Are you using TimeCurrent()? That will cause the issues you describe.
Alexander Martinez
578
Alexander Martinez  
honest_knave:

That's not what should happen; post up some more of your code.
#property copyright "Copyright 2015,user3822"
#property link      "ForexFactory.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
input int X_Axis = 280;
input int Y_Axis = 2;
input bool Set_Alarm = true;
input int Alarm_Time_Minutes = 12;
input int Alarm_Duration_Seconds = 10;
input color Font_Color = C'60,60,60';
input string Font_Face = "Arial";
input int Font_Size = 9;

bool Alarm_Triggered = true;
bool timer = true;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

int OnInit(){
   if(ObjectFind(NULL,"Clock") !=0){
      ObjectCreate(NULL,"Clock",OBJ_LABEL,0,0,0);
      ObjectSetInteger(NULL,"Clock",OBJPROP_XDISTANCE,X_Axis);
      ObjectSetInteger(NULL,"Clock",OBJPROP_YDISTANCE,Y_Axis);
   }
   bool setTimer = EventSetTimer(1);
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+

void OnTimer(){
   int currentSecond = 59-Seconds();
   int currentMinute = 59-Minute();
   string second = (string)currentSecond;
   string minute = (string)currentMinute;
   if (currentSecond <= 9){   
      second = StringConcatenate("0",(string)currentSecond);
   }
   ObjectSetText("Clock",minute+":"+second,Font_Size,Font_Face,Font_Color);
   
   checkAlarm(currentMinute,currentSecond,Alarm_Time_Minutes,Alarm_Duration_Seconds);   

}
void checkAlarm(int minute, int second, int alarm_time, int alarm_duration){
   if (alarm_time == minute && (alarm_duration >= second)){
      PlaySound("stops.wav");
   }
}

//+------------------------------------------------------------------+
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[]){
   return(rates_total);
}
honest_knave
Moderator
2342
honest_knave  
user3822:


Your code in OnTimer() will be running every second. You can check by adding this and checking the Experts log in the terminal:

void OnTimer(){
   Print("OnTimer() running");

The problem is that Seconds() and Minutes() are based on Server time. If a tick doesn't come in from the server, they don't change. This creates the illusion that OnTimer() isn't running.

You can use TimeLocal() instead - this is your computer's time - but you will run into some problems depending on how you implement it:

  • You may be running a different GMT offset from your broker's server
  • Sometimes server time and local time are a few seconds offset.
Rather than re-inventing the wheel, see if @whroeder1's code here helps.
CandleCountDown / Period() - TimeFrame M15
CandleCountDown / Period() - TimeFrame M15
  • www.mql5.com
Hello, I would like to write some code for Indicator "Candle CountDown" but I need some help...
Alexander Martinez
578
Alexander Martinez  
honest_knave:


Your code in OnTimer() will be running every second. You can check by adding this and checking the Experts log in the terminal:

The problem is that Seconds() and Minutes() are based on Server time. If a tick doesn't come in from the server, they don't change.

You can use TimeLocal() instead - this is your computer's time - but you will run into some problems:

  • You may be running a different GMT offset from your broker's server
  • Sometimes server time and local time are a few seconds offset.

Thanks. When you asked me to post my code, I went looking at it again and that Minute() / Hour() looked suspect. But when I looked it up, it said it used the last known data, so I didn't think it would cause the program to wait for new data to arrive.

I'll look into TimeLocal(). Thanks again, knave.

honest_knave
Moderator
2342
honest_knave  
user3822:

Thanks. When you asked me to post my code, I went looking at it again and that Minute() / Hour() looked suspect. But when I looked it up, it said it used the last known data, so I didn't think it would send a request to the server for data.

I'll look into TimeLocal(). Thanks again, knave.


No problem - check out the link I added in my previous reply (countdown_timer.mq4). It should help
To add comments, please log in or register