Anyone know how to develop a multicurrency indicator ? - page 4

 

Well guys, the first part is done ( reading all pairs rates ).

Now i need use the rates of all paris copied with the function ArrayCopyRates to pot some graphic indicators like an RSI... as i draw in the image below:

 

In my initial question i intend know how to do this... and not about reading rates. I do not think i will need to copy rates before to draw it, but was good to know how to do... now i just need to discover a way to split the indicator area to plot all pairs...

 
Understand. Then all of the elements must be drawn as objects.
 

This is a Indicator I picked up somewhere, I never tried to decipher it. I shows a representation of 3 timeframes of the current chart. The crazy thing is the candles are drawn with Histograms. Pretty neat but not what I am into right now.

Best Wishes 

Files:
 
Ok, thanks. I an travelling at work and when return i willl test it.
 
Fernando Carreiro:

An update to those following this thread!

I have been helping the OP via PM fix his code as he has difficulty with English and we both speak Portuguese. In our testing we came across another "funny" that is happening with the "ArrayCopyRates()" function. When using an MqlRates array with "ArrayCopyRates()" in an EA, the data array is a virtual one that always reports the current status of things, so data is always fresh.

However, in an Indicator, this does not seem to be the case. The array is not a virtual copy but instead a static copy set in time at the moment that the "ArrayCopyRates()" was called. The data does not update when the Symbol is different to the chart symbol. When it is the same symbol as the chart, then the array data is "live" and updates as expected, but when it is of another symbol, it is a static copy.

So, in order for it to work in an Indicator, one must call the"ArrayCopyRates()" function on every call to OnCalculate() event if fresh data is needed.

Just to expand your findings Fernando - even if symbol is the same as chart symbol, if the timeframe is different then the array is static.

So in order to have a virtual copy, in an indicator, it must be the same symbol AND the same timeframe. Anything else is static.

 
honest_knave: Just to expand your findings Fernando - even if symbol is the same as chart symbol, if the timeframe is different then the array is static. So in order to have a virtual copy, in an indicator, it must be the same symbol AND the same timeframe. Anything else is static.
Thank you for the update!
 
Hi,

I've been looking all over for a solution for this problem and I'd like to thank everyone in this thread for this discussion.

That's my first message in the forum, so please let me know if I missed any protocol and I'd be happy to correct on the next message.

I'm trying to develop a very simple indicator, but my logic does seem sensitive to the chart being fully up-to-date, that is why I'm so interested in this discussion.

My indicator looks to draw a fib on the previous day range (day high to day low or day low to day high) and on the current day draw lines at the high, low and 50% of the fib. If the indicator is used on a GMT broker (Sunday daily candle) the user can set an input parameter to choose if on Monday it uses only Friday or Sunday range, or Friday + Sunday. On a NY close broker (GMT+2) that doesn't make difference given that there is no Sunday candles.

Another feature of this indicator is to allow the user to move the fib around and the lines (high, 50% and low) on the current day will adjust to the new range set by the fib. That will allow the user to ajust the range in case the range in contracting.

The indicator will be mostly used on multiple 1h charts, but the user should be able to switch timeframes without losing any changes made on the fib.

To draw the fib I need to find not only the high and the low of the previous day, but also the time for these points.

The idea is simple but I've been facing a few challenges.

Assuming it is mid week to find the high and low of previous day I simply use:

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

 That's fine, but now I need to find on the previous day what time was the high and the low. I decided to aproximate the time to the 1h candle at high and low using iHighest and iLowest. And that's when the problems begun.


To use iHighest and iLowest I need to specify the first 1h candle and the size of the range, therefore in my case that will be the first 1h and the last 1h candle of the previous day. So I used the open of the previous daily candle for the beginning of the previous day and the open on the current day daily candle -1, to find the end of previous day:

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

And that works great if you are only using the indicator on currencies (again assuming it is mid week) because PrevDayBegin will be the index of the 0:00 1h candle and PrevDayEnd will be the index of the 23:00 1h candle. The problem lies on futures (indices, gold, crude, etc). The daily candle opening is always at 0:00, but the 1st candle on futures is 1am on GMT+2 brokers, therefore the line of code above that calculates PrevDayBegin returns the 1h candle for 23:00 on the previous day.

I then decided to include a piece of code to accomodate for this situation and move the PrevDayBegin until it is on the same week day as PrevDayEnd:

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

And all that logic works great if you have all the 1h candles up-to-date, but take a look at the log below showing some prints of what happened today. Just for reference I closed down MT4 the day before in the evening and opened it back again today in the morning (around 7am UK), therefore there were only a few hours of data missing in the charts.

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTHER DAY OF WEEK ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 20 (2017.02.08 00:00)

Looking at the log it seems that the most up-to-date candle on the 1h chart was 2017.02.08 20:00 (index 0), therefore iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1) is aproximating that to (index 1) 2017.02.08 19:00. Consequently all the calculations for the indicator get mixed up, because iHighest and iLowest will be using the wrong range.

Based on the previous discussions I tried and used some of the solutions suggested to wait for all the candles to be loaded before doing the calculations but aparently is still not working.

For instance, at OnInit() I included the following lines of code to trigger the charts update on the 1h, Daily and the current timeframe (just in case the platform was close when the chart was open on a different timeframe):

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
Another thing I noticed is that it seems that MT4 updates the most recent candle Time[0] on the timeframe that is open in the chart before it loads all the missing history, therefore I decided to test if Time[1] was also a valid price.

That code was inserted on OnCalculate() and it was based on the codes by @whroeder1 (here) and @Fernando Carreiro & @Wemerson Guimaraes (here):

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

And this is the log when the platform was opened and the indicator loaded for the first time:

2017.02.09 06:56:18.492 Custom indicator Prev_Day_Range_LRT_50_v0.6 SPX500,H1: loaded successfully
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: initialized
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Chart up-to-date!
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Indicator doesn't exist! Creating it.
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTHER DAY OF WEEK ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Day of Week = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 28) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 20) (Price = 2287.88) (Time = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib from Time1=2017.02.07 14:00  Price1=2299.33  to  Time2=2017.02.07 23:00  Price2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 00:00  Price1=2299.33  to  Time2=2017.02.09 00:00  Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 00:00  Price1=2293.605  to  Time2=2017.02.09 00:00  Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 00:00  Price1=2287.88  to  Time2=2017.02.09 00:00  Price2=2287.88

It does seem that any reference to candles 0 and 1 or the ArrayCopyRates function are only accessing wherever information is already loaded in the charts, therefore ArrayCopyRates seems to be returning a valid number of elements copied and iTime(..., 0) and iTime(..., 1) are returning a valid price for the last 2 candles stored when the platform was shut on the previous day.

That means that the indicator was plotted as if it was yesterday (PERIOD_D1 [0] = (2017.02.08 00:00)).

The indicator is built so that the high, 50% and low lines are always plotted on the current day, even if the user moves the fib (these are the 3 trendlines showing in the log above). Therefore I have a piece of code on OnCalculate() that test whether the mid trendline is plotted on the current day (the user has an input option to disable the top and bottom line, so the only line that will always be plotted is the mid one). 

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

 After a few ticks the data is partially loaded and the piece of code above will detect that the lines have been plotted on a previous day, delete the fib and trigger a recalculation of the ranges and redraw of the objects (i.e. fib, trendlines, etc).


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Indicator in a past date! Deleting it and creating it today!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDRFibo 131296489639296384 deleted!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRRectangle 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend1 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend2 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend3 131296489639296384

And then we come back to the problem I was mentioning at the begining of this message. The test I've implemented above again doesn't make the indicator wait for the history to be fully loaded and therefore the ranges are miscalculated based on partial data.

This is a more complete version of the log showed at the begining of the message that shows that not only PrevDayEnd is being miscalculated as the 2nd candle (index 1) in the 1h chart is (2017.02.07 21:00) but also CurrDayBegin that is supposed to be 1st candle of the current day in the 1h chart is being aproximated by iBarShift to (2017.02.08 06:00).

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == OTHER DAY OF WEEK ==
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Day of Week = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 8) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 19) (Price = 2288.57) (Time = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib from Time1=2017.02.07 03:00  Price1=2288.57  to  Time2=2017.02.07 14:00  Price2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 06:00  Price1=2288.57  to  Time2=2017.02.09 06:00  Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 06:00  Price1=2293.95  to  Time2=2017.02.09 06:00  Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 06:00  Price1=2299.33  to  Time2=2017.02.09 06:00  Price2=2299.33

So, in a nutshell is there a why to test wether all the histoy has been loaded on a chart? Or am I missing somehting on my code?

Thank you for bearing with me in this very long message.

Please let me know if you'd like to see the whole code and log. I would rather not attach the code here, but I'd be happy to send it privately.

These are screenshots of the indicator:

 (1) Calculated  using incomplete history (please notice the horizontal lines don't start at the beginning of the day)

 Indicator calculated with incomplete history

 (2) Recalculated using the complete history (horizontal lines starting at the beginning of the day)

Indicator recalculated using full history 

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...
Reason: