I'm trying to find the most code-efficient way to do the MQL5 version of calling iATR(NULL,1440,20,0) from lower time-frames for using in stop loss calculations etc.
//MQL4 code = iATR(NULL,1440,20,0);
//Calculate Daily ATR--------
double ATRValue; // Variable to store the value of ATR
int ATRPeriod = 20; // Variable to store the value of ATR
int ATRHandle = iATR(_Symbol,PERIOD_D1,ATRPeriod); // returns a handle for ATR
ArraySetAsSeries( ATRValue,true ); // Set the ATRValue to timeseries, 0 is the oldest.
CopyBuffer( ATRHandle,0,0,1,ATRValue ); // Copy only the 1st value of ATR to ATRValue
double DailyATR = ATRValue;
Print("DailyATR: "+DoubleToString(DailyATR)); // Print the value of the ATR
here's what I have, but it only works when the daily timeframe is selected. This is a super common function so how do you guys do it?
Well, you already have the syntax for daily here:
int ATRHandle = iATR(_Symbol,PERIOD_D1,ATRPeriod);
If you want ATR for a lower time frame, e.g. hourly, simply open another handle and do the same setup for it, i.e. have another array, set the array as series, copybuffer values into that array, etc.
int ATRHandle = iATR(_Symbol,PERIOD_H1,ATRPeriod);
So, would that look similar to the code example (at the bottom) here?
That is, one would check BarsCalculated() in the OnTick() event at (time % 3600 == 0), and then sleep until the values have come in? (3600 assumes shorter timeframe of hourly.)
Yes and probably 21 times faster at execution time too if you want more than 1 value.
You have to check if your handle is valid.
You have to check the value returned by CopyBuffer().
Using handles to indicators like that tends to be clumsy (what if we decide to change the time frame or the period "on the fly" - new handle? ... yeeah ...)
More or less mt5 is making us code a bit more to get better results - ATR is a simple case (excluding the time frame and the period, it is not so much lines of code after all, and allows us flexibility that handle usage would not let us). I did not bother with the case explanation when there is less data available than the ATR desired period+1 rates available in the target time frame data - that is the case that built in ATR does not solve intuitively, and this simple code does that better (at least that is my opinion ...). Making this a function is no big deal either and will work better, faster, and in more flexible way than the built in ATR ...
ENUM_TIMEFRAMES _atrTimeFrame = PERIOD_D1;
int _atrPeriod = 20;
double _atrValue = 0;
MqlRates _rates; int _ratesCopied = CopyRates(_Symbol,_atrTimeFrame,0,_atrPeriod+1,_rates);
for (int i=1; i<_ratesCopied; i++) _atrValue += MathMax(_rates[i].high,_rates[i-1].close)-MathMin(_rates[i].low,_rates[i-1].close);
_atrValue /= MathMax(_ratesCopied,1);
I remember back to Linux back in the mid 90's . . . they introduced the concept of loadable kernel modules. Thus, they shifted code from the OS to these separate entities, leaving hooks in the OS, but not the overhead.
Similar to add-ons for a browser, I imagine.
I got the sense MT5 was doing the same thing. A more scalable solution for the product at the expense of additional code in the EA.
And 21 times slower if you just need one value.
Especially if you need just one value from 20 Instruments, it's a complete nightmare.
This is awesome! it was exactly what I hoped somebody would post, thank you!!