Why are MT5 ENUM_TIMEFRAMES strange? - page 2

 
MOHAMED AMR MOHAMED OSAMA I ABDELWAHAB: here is my solution f

Never hard code constants. Write self-documenting code.

Not compiled, not tested, just typed.

enum TF{                               TF_M1,      TF_M2,      TF_M3,
   TF_M4,      TF_M5,      TF_M6,      TF_M10,     TF_M12,     TF_M15,
   TF_M20,     TF_M30,     TF_H1,      TF_H2,      TF_H3,      TF_H4,
   TF_H6,      TF_H8,      TF_H12,     TF_D1,      TF_W1,      TF_MN1   };
const ENUM_TIMEFRAMES periods[]={      PERIOD_M1,  PERIOD_M2,  PERIOD_M3,
   PERIOD_M4,  PERIOD_M5,  PERIOD_M6,  PERIOD_M10, PERIOD_M12, PERIOD_M15,
   PERIOD_M20, PERIOD_M30, PERIOD_H1,  PERIOD_H2,  PERIOD_H3,  PERIOD_H4,
   PERIOD_H6,  PERIOD_H8,  PERIOD_H12, PERIOD_D1,  PERIOD_W1,  PERIOD_MN1  }

TF                to_tf(ENUM_TIMEFRAMES p){
   if(p == PERIOD_CURRENT) p  = (ENUM_TIMEFRAMES)_Period;
   for(int i=0;; ++i)   if(periods[i] == p)  return (TF)i;
   return WRONG_VALUE;
}
TF                to_period(TF t){           return periods[t];               }
TF                next_tf(TF t){             return MathMin(TF_MN1, t+1);     }
TF                next_tf(ENUM_TIMEFRAMES p){return next_tf(to_tf(p)); }
ENUM_TIMEFRAMES   next_period(ENUM_TIMEFRAMES p){
                                             return to_period(next_tf(p));    }
ENUM_TIMEFRAMES   larger_period(ENUM_TIMEFRAMES p){
   if(p == PERIOD_CURRENT) p  = (ENUM_TIMEFRAMES)_Period;
   int   want  = 3 * PeriodSeconds(p);
   int   i     = 0;  while(PeriodSeconds(periods[i]) < want && i < TF_MN1) ++i;
   return   periods[i];
}
string   as_string(ENUM_TIMEFRAMES period){
   if(period == PERIOD_CURRENT)  period   = (ENUM_TIMEFRAMES) _Period;
   string   period_xxx  = EnumToString(period);                // PERIOD_XXX
   return StringSubstr(period_xxx, 7);                         // XXX
}
Not compiled, not tested, just typed.
 
Jian Chen 2015.06.12 04:50   EN

I agree with you, the definition of these values in MT5 is a little strange.

I think it depends on the design. Let me decode these values:

1. minutes time frames:

   M1 = 0<<15+1, M5 = 0<<15+5, M15 = 0<<15+15, M30=0<<15+30

2. hours and days time frames:

   H1 = 1<<15+1, H4 = 1<<15+4, D1 = 1<<15+24

3. week time frame:

   W1 = 2<<15+1

4. month time frame:

   MN1 = 3<<15+1 


It looks like the bit shift is 14 not 15.

We can get the MQL4 equivalent minute values as follows:

int MQL5_TIMEFRAMES_ToMins (ENUM_TIMEFRAMES TF)
{
   int hiWord = 0;
   int loWord = 0;
   int intTF = (int)TF;
   int resultMins = 0;
   int convertMins[4] = {1,60,10080,43200};
   
   hiWord = intTF >> 14;
   loWord = intTF - (hiWord << 14);
   
   resultMins = convertMins[hiWord] * loWord;
   
   return resultMins;
}
 
MDT: We can get the MQL4 equivalent minute values as follows:
We can get the MQL4 equivalent minute values as follows: PeriodSeconds(TF)/60
 
William Roeder:
We can get the MQL4 equivalent minute values as follows: PeriodSeconds(TF)/60
Thanks. Yes, that works and looks much neater than my code. I guess it is probably doing something similar, but much easier to use the built in function.
 

Here is one way. It might not be the best but it gets the job done.

string period_as_string="";

if (_Period==PERIOD_M1){period_as_string="M1";}

if (_Period==PERIOD_M2){period_as_string="M2";}

if (_Period==PERIOD_M3){period_as_string="M3";}

if (_Period==PERIOD_M4){period_as_string="M4";}

if (_Period==PERIOD_M5){period_as_string="M5";}

if (_Period==PERIOD_M6){period_as_string="M6";}

if (_Period==PERIOD_M10){period_as_string="M10";}

if (_Period==PERIOD_M12){period_as_string="M12";}

if (_Period==PERIOD_M15){period_as_string="M15";}

if (_Period==PERIOD_M20){period_as_string="M20";}

if (_Period==PERIOD_M30){period_as_string="M30";}

if (_Period==PERIOD_H1){period_as_string="H1";}

if (_Period==PERIOD_H2){period_as_string="H2";}

if (_Period==PERIOD_H3){period_as_string="H3";}

if (_Period==PERIOD_H4){period_as_string="H4";}

if (_Period==PERIOD_H6){period_as_string="H6";}

if (_Period==PERIOD_H8){period_as_string="H8";}

if (_Period==PERIOD_H12){period_as_string="H12";}

if (_Period==PERIOD_D1){period_as_string="D1";}

if (_Period==PERIOD_W1){period_as_string="W1";}

if (_Period==PERIOD_MN1){period_as_string="MN1";}

 
  1. Learning2: Here is one way. It might not be the best but it gets the job done.
    string      as_string(ENUM_TIMEFRAMES aePeriod){
       if(aePeriod == PERIOD_CURRENT)   aePeriod = ENUM_TIMEFRAMES(_Period);
       string   period_xxx  = EnumToString(aePeriod);                 // PERIOD_XXX
       return StringSubstr(period_xxx, 7);                            // XXX
    }
 
Alain Verleyen #:

There is no point to use the numeric values. Your code doesn't make sense even with MT4.

You probably need PeriodSeconds() function.

1. If there was no point to having the ENUM_TIMEFRAMES match the number of minutes represented in the bars on the chart then why would the developers have thought to do so in the first place.

2. Why not simply explain the reasoning behind the new method? If there is any. Why be rude?

3. I've personally used the fact that the numbers match the number of minutes per bar for multiple projects in MT4 and I wanted to convert them to MT5 so the change made that more difficult.

4. It's great that the developers had the foresight to make a function like Period Seconds but that just adds calculations to something that was simple. On a small scale it wouldn't make a noticeable difference but when back testing on a large scale it would add a significant amount of time to completion.

 

parse the ENUM variables to integer type. It will take care of any future changes to assigned constant values.

//--User input region
input ENUM_TIMEFRAMES selectedTimeframe =  PERIOD_H1;
//---variables region
const string indicatorName = "\\indicators\\.....\Path\\to\\ex5\\file";
MqlParam param[2];
//--region assign values
param[0].type = TYPE_STRING; param[0].string_value = indicatorName ;
param[1].type = TYPE_INT; param[1].integer_value = (int) selectedTimeframe ;
//-- create indicator handle
int handle = IndicatorCreate(_Symbol,PERIOD_CURRENT,IND_CUSTOM,2,param);


That is all it requires.

 
MDT #:
Jian Chen 2015.06.12 04:50   EN

I agree with you, the definition of these values in MT5 is a little strange.

I think it depends on the design. Let me decode these values:

1. minutes time frames:

   M1 = 0<<15+1, M5 = 0<<15+5, M15 = 0<<15+15, M30=0<<15+30

2. hours and days time frames:

   H1 = 1<<15+1, H4 = 1<<15+4, D1 = 1<<15+24

3. week time frame:

   W1 = 2<<15+1

4. month time frame:

   MN1 = 3<<15+1 


It looks like the bit shift is 14 not 15.

We can get the MQL4 equivalent minute values as follows:

Thanks @Jian Chen for the pointer!! I converted it to python to use in my work. And here is the reverse in python:

def mintotf(min):
  index = np.array([59,1440,10080])
  offset = [1,60,10080,43200]
  x = int(index.searchsorted(min))
  return int((x<<14) + min/offset[x])

And a test script:

for min in [1,5,15,30,60,240,720,1440,10080,43200]:
  print(str(min)+' minutes = '+str(mintotf(min)))

Giving:

1 minutes = 1 

5 minutes = 5 

15 minutes = 15 

30 minutes = 30 

60 minutes = 16385 

240 minutes = 16388 

720 minutes = 16396 

1440 minutes = 16408 

10080 minutes = 32769 

43200 minutes = 49153

Reason: