Scanning 28 symbols in 5 timeframes

 

Hi all!

I made an indicator which scans 28 forex pairs in 5 timeframes for a pre-defined setup. In this example I just scan for a candle's close above the previous candle's high.

My question is now if my code is an elegant and efficient way to do it. I don't think so because the indicator is constantly looping and waiting for a timestamp to change.

Please have a look at my code and if there is a more intelligent or better logic, I would be happy if you told me about it.

#property strict
#property indicator_chart_window

string sym[] =    {"AUDCAD", "AUDCHF", "AUDJPY", "AUDNZD", "AUDUSD",
                   "CADCHF", "CADJPY", "CHFJPY", "EURAUD", "EURCAD",
                   "EURCHF", "EURGBP", "EURJPY", "EURNZD", "EURUSD",
                   "GBPAUD", "GBPCAD", "GBPCHF", "GBPJPY", "GBPNZD",
                   "GBPUSD", "NZDCAD", "NZDCHF", "NZDJPY", "NZDUSD",
                   "USDCAD", "USDCHF", "USDJPY"};
int tf[]= {PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4};
datetime times[28][5];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   for (int s=0; s<ArraySize(sym); s++) {   
      for (int t=0; t<ArraySize(tf); t++) {
         if (times[s][t]!=iTime(sym[s], tf[t], 0)) {
            times[s][t]=iTime(sym[s], tf[t], 0);
            if (iClose(sym[s], tf[t], 1)>iHigh(sym[s], tf[t], 2)) {
               Alert(sym[s]+" "+(string)tf[t]);
            }
         }
      }
   }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Marbo:

Please have a look at my code and if there is a more intelligent or better logic, I would be happy if you told me about it.

It depends whether you're happy to make an assumption about something which is undocumented in MT4: whether you can rely on ticks being received, and sent to indicators, in strict chronological order across all markets.

If you're happy to make that assumption, then an optimisation is available. Once you detect that any market has entered a new candle, you can assume that the candles on the other markets are now complete. But making use of that optimisation is a little tricky, because you need to check whether or not MT4 has started a new candle on these other markets, or whether you need to compare #0 against #1 instead of #1 against #2.

And there's a further variant of that optimisation depending on how timely you want your checks to be. It's already the case that you're doing the check in OnCalculate, not a timed loop. Therefore, if you're running the indicator on EURUSD, you're only going to be checking for new candles on GBPUSD, AUDUSD etc each time there's a new EURUSD tick. It's unlikely and uncommon but possible that other markets could start a new candle significantly before the first tick of a new candle on EURUSD, and that there'll be a delay in you doing your comparison.

But if you're happy to keep that behaviour, then you can just watch TimeCurrent(), do some simple maths to detect whether it's entered a new M5 candle, a new M15 candle etc, and then do your checks on all markets accordingly.

 
JC:

[...]

... The tl;dr version of that is that I'd personally do the check in a timed loop, not in OnCalculate, and I'd use TimeCurrent() to check whether it was time for a new scan of each timeframe on all markets (though, again, needing to check whether to compare #1 against #2 or #0 against #1).

 

No you should use a timer because now it only triggers on a new tick for the chart instrument.

If you use a timer you compare all bar times with each other and when they are all equal, it is safe to do the calculations.

Whenever one of your 28 instruments receives a new bar this will break the condition of all bars equal and you reject all calculations because they are faulty since you have old and new bars mixed.

As soon as all bar times are equal again you know they are synchronized and you can continue you calculations.

So if you use a fast timer you do not even have to put any code in the OnCalculate Function.

 
JC:

It depends whether you're happy to make an assumption about something which is undocumented in MT4: whether you can rely on ticks being received, and sent to indicators, in strict chronological order across all markets.

If you're happy to make that assumption, then an optimisation is available. Once you detect that any market has entered a new candle, you can assume that the candles on the other markets are now complete. But making use of that optimisation is a little tricky, because you need to check whether or not MT4 has started a new candle on these other markets, or whether you need to compare #0 against #1 instead of #1 against #2.

And there's a further variant of that optimisation depending on how timely you want your checks to be. It's already the case that you're doing the check in OnCalculate, not a timed loop. Therefore, if you're running the indicator on EURUSD, you're only going to be checking for new candles on GBPUSD, AUDUSD etc each time there's a new EURUSD tick. It's unlikely and uncommon but possible that other markets could start a new candle significantly before the first tick of a new candle on EURUSD, and that there'll be a delay in you doing your comparison.

But if you're happy to keep that behaviour, then you can just watch TimeCurrent(), do some simple maths to detect whether it's entered a new M5 candle, a new M15 candle etc, and then do your checks on all markets accordingly.

I forgot to say that this scanner runs on a EURUSD chart. I think the most and earliest ticks will be received by the most traded pair. And I am very sure that with a new candle on EURUSD it is not uncommon that there is still no new candle-tick on not so heavily traded pairs like NZDCHF, AUDCHF, etc...

I am not really sure what you mean with working with TimeCurrent() in this case. In my opinion the time is not so important because I have to make sure that a new candle started and that is not always with XX:XX:00. More often that not the first tick of a new candle comes (in quiet times) 10 seconds late.

 
Marco vd Heijden:

No you should use a timer because now it only triggers on a new tick for the chart instrument.

If you use a timer you compare all bar times with each other and when they are all equal, it is safe to do the calculations.

Whenever one of your 28 instruments receives a new bar this will break the condition of all bars equal and you reject all calculations because they are faulty since you have old and new bars mixed.

As soon as all bar times are equal again you know they are synchronized and you can continue you calculations.

So if you use a fast timer you do not even have to put any code in the OnCalculate Function.

I never worked with the OnTimer function but it might be a good idea.

So if I have different timeframes to check the timer-interval must be set to the smallest timeframe to be checked, correct?

 
Marbo:

I never worked with the OnTimer function but it might be a good idea.

So if I have different timeframes to check the timer-intervallmust be set to the smallest timeframe to be checked, correct?

No. OnTimer() does not have anything to do with the time frames. See here : https://www.mql5.com/en/docs/event_handlers/ontimer

Documentation on MQL5: Event Handling / OnTimer
Documentation on MQL5: Event Handling / OnTimer
  • www.mql5.com
//|                                               OnTimer_Sample.mq5 | //|                        Copyright 2018, MetaQuotes Software Corp. | //|                                             https://www.mql5.com | "It is recommended to run the EA at the end of a trading week before the weekend...
 
Mladen Rakic:

No. OnTimer() does not have anything to do with the time frames. See here : https://www.mql5.com/en/docs/event_handlers/ontimer

Sorry, I meant that I have to set the timer-event to 300 seconds in my case. 300 seconds are 5 minutes and the M5 timeframe is the smallest in my code. And so I have to check every 5 minutes if there is a new M5/M15/M30/H1/H4 candle.

 
I just noticed a problem. The timer-event is active from the moment I set the timer. But if I start the indicator for example at 08:02:40 in the morning and I use a 300 second timer-event, the OnTimer() function would start at 08:07:40 and not at 08:05:00. So I need the exact times when a new candle starts and not an interval, don't I?
 
Marbo:

Sorry, I meant that I have to set the timer-event to 300 seconds in my case. 300 seconds are 5 minutes and the M5 timeframe is the smallest in my code. And so I have to check every 5 minutes if there is a new M5/M15/M30/H1/H4 candle.

That does not guarantee that you shall get the change (a new bar) when it happens - on the contrary : it might cause missing some change for one entire bar

This part of your code :

if (times[s][t]!=iTime(sym[s], tf[t], 0))

Is quite enough to avoid missing data checking, and it is simply up to your discretion how often you want to check (ie: what will be the maximal lag - the timer setting - to get the change)

 
Mladen Rakic:

That does not guarantee that you shall get the change (a new bar) when it happens - on the contrary : it might cause missing some change for one entire bar

This part of your code :

Is quite enough to avoid missing data checking, and it is simply up to your discretion how often you want to check (ie: what will be the maximal lag - the timer setting - to get the change)

Mladen, do I understand you correct that you don't recommend using a timer? Do you think my code is the most efficient way to make sure that no candle is missing?

If I loop all symbols and all timeframes constantly with every tick I can be pretty sure that I don't miss any new candle.

Reason: