Am I wrong or is it the new mql5 build 1915? - page 3

 
Anthony Garot:

Yeah, I hate that. Especially when loading data for other currency pairs or time frames.

To limit to the number of bars available on the chart, I do this in OnCalculate().

Where pEnsureData() is basically the code I described above, and pFillBuffers() calls CopyBuffer().

Could you explain the problem exactly ? You "hate" what ? And what is your code solving ?
 
Anthony Garot:

One other thing to note:

I've noticed that sometimes BarsCalculated() returns 0, even though the data is already there. That is, BarsCalculated() may have been returning 510 for two or three dozen ticks when, all of a sudden, it returns 0. Then, on the very next tick, BarsCalculated() returns 510 again.

I've got a simple:

in my code for now to compensate for this.

I suppose your BarsCalculated is run just when OnCalculate is run on the indicator, so number of bars is undetermined and it returns 0. I should be checked to confirm but that seems logic.

It should not happen if both your BarsCalculated() is used in an indicator and OnCalculate() are on the same symbol though (as they are running in the same thread).

 
Alain Verleyen:
Could you explain the problem exactly ? You "hate" what ? And what is your code solving ?

When my loading code brings more and more data from the server.

Scenario:

  • I want data for 8 currency pairs.
  • I delete all historical data from my cache.
  • When I start Terminal, say I have USDCAD,D1 as my initial chart.

So, Terminal begins loading USDCAD,D1 values. Usually it brings in about 510 or so for the first batch. The indicator considers this as rates_total.

Now my code starts looping over the other 7 currency pairs. I only want/need 510 values for these also.

My code (as described elsewhere) requests data from the server. Over several iterations of OnCalculate(), eventually I get all 510 bars for the other 7 currency pairs.

This is good. The indicator displays correctly on the chart. This is what I wanted.

Then I get what I call "data creep."

For some reason, my code begins to bring more data from the server for the other 7 currency pairs than the 510 bars on USDCAD.

Eventually, all the other currency pairs will receive -ALL- historical data from the broker server—everything it can source.

So I may be sitting with USDCAD at 510 bars but the rest of the symbols with tens of thousands of bars.

Thus, this code snippet keeps all pairs at 510 bars until the next legitimate bar comes in.

 
Alain Verleyen:

It should not happen if both your BarsCalculated() is used in an indicator and OnCalculate() are on the same symbol though (as they are running in the same thread).

You may be on to something. I think it only happens on symbols other than the chart symbol. I'll keep an eye on it.

 
Anthony Garot:

When my loading code brings more and more data from the server.

Scenario:

  • I want data for 8 currency pairs.
  • I delete all historical data from my cache.
  • When I start Terminal, say I have USDCAD,D1 as my initial chart.

So, Terminal begins loading USDCAD,D1 values. Usually it brings in about 510 or so for the first batch. The indicator considers this as rates_total.

Now my code starts looping over the other 7 currency pairs. I only want/need 510 values for these also.

My code (as described elsewhere) requests data from the server. Over several iterations of OnCalculate(), eventually I get all 510 bars for the other 7 currency pairs.

This is good. The indicator displays correctly on the chart. This is what I wanted.

Then I get what I call "data creep."

For some reason, my code begins to bring more data from the server for the other 7 currency pairs than the 510 bars on USDCAD.

Eventually, all the other currency pairs will receive -ALL- historical data from the broker server.

So I may be sitting with USDCAD at 510 bars but the rest with tens of thousands of bars.

Thus, this code snippet keeps all pairs at 510 bars until the next legitimate bar comes in.

Thanks for the detailed explanation. I would be very surprised all the data (tens of thousands of bars as you noted) are download without being requested.

It's not easy to understand the process with only a few snippets of code. But I noticed this :

        WrapCopyTimeSingle(time[0], symbol, 0);

Used in on Calculate. If there is no data yet for the "time[0]" candle, data will be downloaded. But index 0 is the oldest bar by default with mql5. So when data are download the OnCalculate() is called withon prev_calculated=0 and maybe the above code is run again ? Then time[0] could request more data downloading and like that up to when all data are downloaded.

It doesn't do it on USDCAD as it's the chart symbol. It's just a guess would also need to be checked.

EDIT: By the way, even if the explanation is not the good one, I am not sure what is the problem to download all data ? Once you have data they will not be downloaded anyway, so it happens only once.

 

Alain Verleyen:

EDIT: By the way, even if the explanation is not the good one, I am not sure what is the problem to download all data ? Once you have data they will not be downloaded anyway, so it happens only once.

This is true. Once Terminal has all data, the indicator works flawlessly.

I actually thought of capitalizing on this "data creep" concept to write an indicator for the Code Base that downloads all data for all currency pairs, within a user defined list, of course. Thus, a person could run this indicator rather than going through Symbols (CTRL-U) and requesting data for each currency pair they want.

But there is probably already something out there that does this.
 

I feel like I may have taken the OP's original thread off topic by introducing multi-currency concerns/details.

I've decided to just attach the whole indicator that I have been playing with to clear up any confusion.

It's MT5, it compiles, and it worked last Friday. :-D

Of course, this version won't work on a weekend because —you know—no ticks.

Files:
OtherPairs.mq5  18 kb
 
Anthony Garot:

Of course, this version won't work on a weekend because —you know—no ticks.

You can actually circumvent that by setting a 1ms Event timer from OnInit, refreshing your external indicators in OnTimer, and for some reason OnCalculate will be called a second time. Check it out. 

//+------------------------------------------------------------------+
//|                                                    OthersAlt.mq5 |
//|                                                      nicholishen |
//|                                                    interwebs.com |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link      "interwebs.com"
#property version   "1.00"
#property indicator_separate_window
#include <Indicators\Indicators.mqh>
#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
class MyIndicators : public CIndicators
{
protected:
   int      m_min_bars;
public:
   MyIndicators():m_min_bars(1000){}
   void set_min_bars(int min_bars){ m_min_bars = min_bars;}
   CIndicator *operator[](int i){ return this.At(i);}
   bool all_ready(){
      this.Refresh();
      for(int i=this.Total()-1; i>=0; --i)
         if(this[i].BarsCalculated() < m_min_bars)
            return false;
      return true;
   }
};
//+------------------------------------------------------------------+
bool is_allowed_symbol(string symbol)
{
   string currencies[] = {
      "USD", "EUR", "GBP", "CAD",
      "NZD", "JPY", "AUD", "CHF"
   };
   CSymbolInfo s;
   s.Name(symbol);
   if(s.TradeCalcMode() != SYMBOL_CALC_MODE_FOREX)
      return false;
   return (
      in(s.CurrencyBase(), currencies)
      && in(s.CurrencyProfit(), currencies)
   );
}
//+------------------------------------------------------------------+
template <typename T>
bool in(T item, T &array[])
{
   for(int i=ArraySize(array)-1; i>=0; --i)
      if(item == array[i])
         return true;
   return false;
}
//+------------------------------------------------------------------+




MyIndicators g_indicators;

input int                               InpMaFastPeriod=20;                             // Fast MA period
input int                               InpMaSlowPeriod=50;                     // Medium MA period

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   g_indicators.set_min_bars(fmax(InpMaFastPeriod, InpMaSlowPeriod));
   for(int i=SymbolsTotal(false)-1; i>=0; --i){
      string i_symbol = SymbolName(i, false);
      if(is_allowed_symbol(i_symbol)){
         CiMACD *macd = new CiMACD();
         bool macd_create = macd.Create(i_symbol, _Period, 
            InpMaFastPeriod, InpMaSlowPeriod, 9, PRICE_CLOSE
         );
         if(!macd_create || !g_indicators.Add(macd)){
            printf("macd_create failed, %d", _LastError);
            return INIT_FAILED;
         }
      }
   }
   Print("OnInit called");
   EventSetMillisecondTimer(1);
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
{
   static int call=0;
   Print("OnCalc call #", ++call);
   if(g_indicators.all_ready()){
      for(int i=g_indicators.Total()-1; i>=0; --i){
         printf("%s on %s: BarsCalculated = %d", 
            g_indicators[i].Name(), 
            g_indicators[i].Symbol(), 
            g_indicators[i].BarsCalculated()
         );
      }
   }
   return(rates_total);
}
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
{
   static int call=0;
   Print("OnTimer call #", ++call);
   if(g_indicators.all_ready()){
      EventKillTimer();
      Print("ALL READY!!!");
   }
}
 
Anthony Garot:

One other thing to note:

I've noticed that sometimes BarsCalculated() returns 0, even though the data is already there. That is, BarsCalculated() may have been returning 510 for two or three dozen ticks when, all of a sudden, it returns 0. Then, on the very next tick, BarsCalculated() returns 510 again.

I guess this is because the terminal once and a while resets prev_calculated to 0. When I wrote my tool to control the server connection I additionally check when prev_calculatedis reset to 0 and this is surprisingly often!

 
nicholi shen:

You can actually circumvent that by setting a 1ms Event timer from OnInit, refreshing your external indicators in OnTimer, and for some reason OnCalculate will be called a second time. Check it out. 

I have heard about using OnTimer() to get multi-currency indicators working on the weekend, but after trying it myself, I figured it was some sort of mythical beast, like a unicorn or liopleurodon.

Well, I wiped out all my historical data, started MT5, and loaded your code on USDCAD,D1.

It spun and spun and spun without stopping . . . .

spinning

I'll be honest, though—I didn't really look at your code yet. I'm pretty exhausted after a long run this morning and too much coffee thereafter.

I'll look through the code this week and test it next weekend.

Thank you for the snippet. I am sure there is a kernel of truth in it that I can use.

Oh, and it appears I forgot an 'n' on your name when I renamed your file (unintentional), and I misstated the mythical nature of liopleurodons (intentional).

Reason: