MT4 visual mode using multiple timeframe data

 

Hello,

My custom indicator uses price action and other indicator info from higher timeframes which I use to determine various parameters to assess the confidence level of the trade setup. While this works fine in real time, the higher time frame parameters don't seem to refresh when running the indicator in the strategy tester in visual mode on its own or when using it with an EA that calls it via iCustom.

Can you provide some guidance on issues with higher timeframe data in the strategy tester?

Thanks

Narayan

 
Hi, as far as I know, MT4 does not support multiple time frames in the strategy tester. Regards Greg
 
Greg Pawlak:
Hi, as far as I know, MT4 does not support multiple time frames in the strategy tester. Regards Greg

MT4 does support multiple TimeFrames in the tester.

I have noticed in the past that when a Multi TimeFrame indicator is used in an EA and the indicator is shown on the chart, it can give incorrect values, but iCustom values used by the EA are correct. 

 
  1. Multiple TFs are fine, just not weekly, or Monthly.

              'Testing Features and Limits in MetaTrader 4' - MQL4 Articles 2012 (The comment about "Zero bar of another timeframe," is no longer valid.)

  2. If the indicator doesn't handle 4066/4072 it gets bad data. The EA then runs with good data because of the indicator.

    On MT4: Unless the current chart is that specific symbol(s)/TF(s) referenced, you must handle 4066/4073 errors before accessing candle/indicator values.
              Download history in MQL4 EA - Forex Calendar - MQL4 programming forum - Page 3 #26 № 4 2019.05.20

 
Keith Watford:

MT4 does support multiple TimeFrames in the tester.

I have noticed in the past that when a Multi TimeFrame indicator is used in an EA and the indicator is shown on the chart, it can give incorrect values, but iCustom values used by the EA are correct. 

good to hear that:)

 
Keith Watford:

MT4 does support multiple TimeFrames in the tester.

I have noticed in the past that when a Multi TimeFrame indicator is used in an EA and the indicator is shown on the chart, it can give incorrect values, but iCustom values used by the EA are correct. 

Yes, Keith, I've noticed this too in real time. And to correct it, I change the timeframe and revert to the initial one and if that doesn't work I reload the template thereby reloading the indicator which always works.

Hopefully these are all manifestations of the same issue of the data for the other timeframes not having been updated as William has suggested.

Narayan

 
William Roeder:
  1. Multiple TFs are fine, just not weekly, or Monthly.

              'Testing Features and Limits in MetaTrader 4' - MQL4 Articles 2012 (The comment about "Zero bar of another timeframe," is no longer valid.)

  2. If the indicator doesn't handle 4066/4072 it gets bad data. The EA then runs with good data because of the indicator.

Thanks, William. Looks promising, I'll make the changes based on these and revert with my results.

Narayan

 
William Roeder:
  1. Multiple TFs are fine, just not weekly, or Monthly.

              'Testing Features and Limits in MetaTrader 4' - MQL4 Articles 2012 (The comment about "Zero bar of another timeframe," is no longer valid.)

  2. If the indicator doesn't handle 4066/4072 it gets bad data. The EA then runs with good data because of the indicator.

OK folks,

I used the download_history function that @whroeder1 had provided with a couple of tweaks and dropping the #defines as follows:

bool download_history (ENUM_TIMEFRAMES period=PERIOD_CURRENT)
     export
{
   return download_history (_Symbol, period);
}


//bool download_history (SYMBOL symbol, ENUM_TIMEFRAMES period=PERIOD_CURRENT)
bool download_history (string symbol, ENUM_TIMEFRAMES period=PERIOD_CURRENT)
     export
{
   if (period == PERIOD_CURRENT)
      period = (ENUM_TIMEFRAMES)_Period;        // necessary as _Period being a variable can't be specified as a default value; so a constant PERIOD_CURRENT is used to enter and then replaced
   
   ResetLastError();
   
   datetime other = iTime (symbol, period, 0);
   
   if (_LastError == 0 && other != 0)
      return true;
      
   if (_LastError != ERR_HISTORY_WILL_UPDATED && _LastError != ERR_NO_HISTORY_DATA)
      PrintFormat ("iTime(%s,%i) Failed: %i", symbol, period, _LastError);
      
   return false;
}

in my custom indicator as follows. While I have noted William's comment that the 4066/4072 should be handled before accessing the candle/indicators I believe they refer to the higher TF candle data. My indicator generates signals on new bars, so I have called the function after checking for a new bar.

int OnCalculate(const int rates_total, ...

{
   static datetime prevtime;
   
   if (prevtime == Time[0]) {
      return (0);
   }
   prevtime = Time[0];

   if (!(h1Period > 0 ? download_history (h1Period) : 1) || !(h2Period > 0 ? download_history (h2Period) : 1))
      return (prev_calculated);


   int counted_bars = IndicatorCounted();
   if (counted_bars > 0)
      counted_bars--;
      
   int limit = MathMin (rates_total-counted_bars, CandleHist ? MathMin(rates_total-5, CandleHist) : (rates_total-5)) - 1;

   for (int shift=limit; shift>=0; shift--)
   {
      fSignal (shift);
   }

   ChartRedraw();

   return (rates_total);
}

I tested the following scenarios:

  1. Real time with custom indicator - this seemed to be working fine previously, so no obvious difference, but I imagine the code will be more robust now
  2. Real time with custom indicator and the EA which also calls the custom indicator through iCustom for signals - as above, no obvious difference
  3. Strategy Tester in Visual mode with custom indicator alone - works now and the higher TF data is now used to influence the signals correctly
  4. Strategy Tester in Visual mode with custom indicator and a separate EA - FXBlue Simulator v3 https://www.fxblue.com/appstore/u39/mt4-trading-simulator/user-guide that I am using for manual backtesting with multiple timeframes - doesn't work. As before, the higher TF data doesn't seem to come through until I reload the chart template (and thereby the indicator)
  5. Strategy Tester in Visual mode with custom indicator and my custom EA which also calls the indicator through iCustom for signals - doesn't work either. The code I've embedded in the EA within OnTick() is as follows:
void OnTick()
{
//--- 
// Determine if New Bar
   static datetime newTime=0;                        // Time of the current bar /// 3) To avoid repeat of 1st bar, just make newTime global and assign it to the time of the 1st bar (not signal) in OnInit
   newBar = 0;                                     // No new bar - moved to Global variable for use within functions to prevent repeated printing of Error messages
   
   if (newTime != Time[0])  {                      // Compare time
      newTime = Time[0];                           // Now time is so
      newBar = 1;                                  // A new bar detected
      
      //while (!download_history (h1Period) && !download_history (h2Period))   {
      while (!(h1Period > 0 ? download_history (h1Period) : 1) || !(h2Period > 0 ? download_history (h2Period) : 1))    {
         if (IsTesting() || IsVisualMode())
            PauseTest ();          // Sleep doesn't work in test mode
         else
            Sleep (500);           /// 1) Does this need any adjustment for Test mode?
         
         RefreshRates();
      }
      
      if (signal)
         signal_prev = signal;                     // store previous signal on chart
      
   // Look for a signal on just closed bar
      //HideTestIndicators (false);
      HideTestIndicators (true);
      
      //signal = (int) iCustom (NULL, 0, "PA_Indicator\\PA_Indicator", "",0,0,0,0,"","",1,1,1,1,1,1,"",1,1,1,1,1,1,1,1,1, 0, 1);      // Although the signal is triggered upon current bar (shift 0), iCustom retrieves this value stored against the just closed bar with index 1 from the buffer of PA_Indicator
      
      signal = (int) iCustom (NULL, 0, "PA_Indicator\\PA_Indicator",                // Symbol, TF, Indicator Name
                              "",                                                // Section1 Title
                              0,0,0,0,"",                                        // Show_Alert, alertsMessage, alertsSound, alertsEmail, Alert_Sound
                              "",                                                // Section2 Title
                              GlobalVariableGet ("gtDisplay_PinBar"),
                              GlobalVariableGet ("gtDisplay_Inside"),
                              GlobalVariableGet ("gtDisplay_Outside"),
                              GlobalVariableGet ("gtDisplay_Ringed"),
                              GlobalVariableGet ("gtDisplay_StrongClose"),
                              GlobalVariableGet ("gtDisplay_NakedClose"),
                              "",                                                // Section3 Title
                              GlobalVariableGet ("gtTrendVol_Flag"),
                              GlobalVariableGet ("gtPSAR_Flag"),
                              GlobalVariableGet ("gtSessionVol_Flag"),
                              GlobalVariableGet ("gtCandleSize_Flag"),
                              GlobalVariableGet ("gth1Check_Flag"),
                              GlobalVariableGet ("gth2Check_Flag"),
                              GlobalVariableGet ("gtMinorArrow_Flag"),
                              GlobalVariableGet ("gtCounter_Flag"),
                              "",                                                // Section4 Title
                              //1, 1,                                              // candleHist for OnInit but 1 for OnTick, EA_Flag=1 when called from an EA through iCustom - is there any standard variable?
                              1,                                                 // candleHist for OnInit but 1 for OnTick
                              8, 1);                                                // buffer Index, shift within the buffer Index
                              //0, shift);                                            // buffer Index, shift within the buffer Index
                                                                                    // Although the signal is triggered upon current bar (shift 0), iCustom retrieves this value stored against the just closed bar with index 1 from the buffer of PA_Indicator
      HideTestIndicators (false);
      

// 3rd Approach
      if (signal)    {                          // signal on a newBar

.....
      }

}

Any thoughts and guidance on scenarios 3 and 4 would be a great help.

Regards

Narayan

PS: PauseTest () is another function Will has posted for VisualMode to programmatically pause the strategy tester and goes as follows:

void PauseTest ()    //(bool pause=true)
     export
{
   datetime now = TimeCurrent();
   static datetime oncePerTick;
   
   //if (oncePerTick != now && IsVisualMode() && IsTesting() && IsDllsAllowed())   {
   if (IsTesting() && IsVisualMode() && IsDllsAllowed() && oncePerTick != now)   {
      oncePerTick = now;
      
      //for (int i=0; i<100000; i++)  {
      for (int i=0; i<200000; i++)  {                                               // Delay required for speed=32 (max)
         if (IsStopped())   break;                                                  // http://forum.mql4.com/32837 WH-DL
         
         int main = GetAncestor (WindowHandle (Symbol(), Period()), 2);             // Retrieves the root window by walking the chain of parent windows.
         
         if (i==0)
            PostMessageA (main, WM_COMMAND, 0x57a, 0);                              // 1402. Pause key
            
//         if (i==0 && !pause)
//            PostMessageA (main, WM_COMMAND, 0x57a, 0);                              // 2 calls to have prev status
//            
       // The PostMessage above sends the command to the main terminal. Thus it
       // only affects the active chart window. To maximize a window for example
       // must activate it first. http://forum.mql4.com/35336#538848
       // See also SetForgroundWindow(h) https://www.mql5.com/en/code/10146
      }
      
      //if (!pause)  {
      //   int main = GetAncestor (WindowHandle (Symbol(), Period()), 2);             // Retrieves the root window by walking the chain of parent windows.
      //   PostMessageA (main, WM_COMMAND, 0x57a, 0);                              // 2 calls to have prev status
      //}
   }  
}
 
Narayan Ramachandran My indicator generates signals on new bars, so I have called the function after checking for a new bar.
  1. Therefor, if higher timeframes (HTF) have been purged because of the new bar code, you start skipping an entire bars, instead of one tick.

    You could have kept the HTFs cached, by always calling it.

    You could, on the start of a new bar, try to update the cache. If successful, then save prevtime, otherwise return and retry next tick.


  2.           Sleep (500);           /// 1) Does this need any adjustment for Test mode?
    Indicators can not sleep.
 
William Roeder:
  1. Therefor, if higher timeframes (HTF) have been purged because of the new bar code, you start skipping an entire bars, instead of one tick.

    You could have kept the HTFs cached, by always calling it.

    You could, on the start of a new bar, try to update the cache. If successful, then save prevtime, otherwise return and retry next tick.


  2. Indicators can not sleep.

1) Thanks for bringing this to my notice. So, essentially, by calling the download_history function first thing in OnCalculate, as per your initial suggestion in this post, it will always try to cache the HTFs and then try to determine a new bar on the chart TF only if it is successful. This, I think will address all the points you mention above.

2) I haven't used the sleep in the indicator. It is used within OnTick () in my custom EA that calls the above custom indicator through iCustom. I've highlighted it because when I run the EA in the Strategy Tester the Sleep function doesn't work, so I've tried to work around it using your PauseTest () function.

Nevertheless, with the above code, the HTF data doesn't seem to be accessible to the indicator or the EA. I infer this because while the EA manages to get the signal based on the chart TF via a iCustom call of the custom indicator, the signal is not qualified by the HTF data as it does on live charts. Furthermore, the custom indicator itself that is also running on the test chart and which worked on it own (without the EA) on Strategy Tester, doesn't seem to get the data.

I'd be grateful for any guidance.

Regards

Narayan

 

Hello, I encountered a problem with accessing data from other TF than the one tested in Visual Mode. For example

iTime(NULL,PERIOD_M1,0)

or similar function (iOpen, iClose etc.) always returns data of M1 bar 0 from the moment of tester start - like access to other TF data is frozen and fixed to time of start. Data from M1 is downloaded and accessible in tester. I noticed, that if I recompile indicator running in tester time of the bar 0 changes to current time but it remains the same for the rest of the test.

I searched the forum but did not find the solution.

Thank you in advance for your help.

-- EDIT 2021.08.09 --

After further investigation up to date information from other TFs is available to EAs, but not to indicators. I am not able to find this information anywhere in the documentation.

Marcin

Reason: