Manual ATR function vs inBuilt iATR

 

I purchased a EA. it is based on ATR but when i reviewed the code, there is no iATR function. it have


double fATR(string sy, ENUM_TIMEFRAMES tf,int ATRper,int shift)
  {
   double atrBuf[];
   ArrayResize(atrBuf,ATRper+shift+1);
   int i=ATRper+shift;
   while(i>=0)
     {
      double high=iHigh(sy,tf,i);
      double low =iLow(sy,tf,i);
      double prevclose=iClose(sy,tf,i+1);
      atrBuf[i]=fmax(high,prevclose)-fmin(low,prevclose);
      i--;
     }
   return(SMA(ATRper+shift+1,atrBuf,ATRper,shift));
  }
//+------------------------------------------------------------------+
double SMA(const int rates_total,const double &array_src[],const int period,const int shift)
  {
   if(period<1 || shift>rates_total-period-1)
      return array_src[shift];
   double sum=0;
   for(int i=0; i<period; i++)
      sum+=array_src[shift+i];
   return(sum/period);
  }


Instead of https://www.mql5.com/en/docs/indicators/iatr


When i asked the seller, he said this do exact same thing and also it faster than iATR

 
Not really sure. There’s a reason MQL5 used copy buffer instead of this, copying lets you call iAtr once. And copy anytime and any where. So it is way better than this. 
 

Mladen Rakic's MTF ATR code is the fastest that I've found:

[Edit from moderator] Source: https://www.mql5.com/en/forum/223235#comment_6251628

//+------------------------------------------------------------------+
//| Custom iATR function                                             |
//+------------------------------------------------------------------+
double iATRcustom()
  {
   ENUM_TIMEFRAMES _atrTimeFrame = ATRtimeframe;
   int             _atrPeriod    = ATRperiod;
   double          _atrValue     = 0;
      MqlRates _rates[]; int _ratesCopied = CopyRates(_Symbol,_atrTimeFrame,0,_atrPeriod+1,_rates);
                         if (_ratesCopied>0)
                              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);
   return _atrValue;
  }

(This code is a snippet containing undefined inputs and hence, will not compile in and of itself).

 

@Ryan L Johnson @Arinze Michael Ejike


Can you confirm the manual code which i posted is do exactly same iATR function/operation? 
 
Shanmugi #:

@Ryan L Johnson @Arinze Michael Ejike


Can you confirm the manual code which i posted is do exactly same iATR function/operation? 
Yes, it has the same price elements and merely uses fmin and fmax in lieu of MathMin and MathMax.
 
#property copyright "Copyright 2026, Shalome."
#property link      "https://www.mql5.com"
#property version   "1.00"



int ATRHandle = INVALID_HANDLE;
double ATR[];


input int TestPeriod = 21;




int OnInit()
  {
  
  ATRHandle = iATR(Symbol(), PERIOD_CURRENT, TestPeriod);
  if(ATRHandle == INVALID_HANDLE){
  
  Print("ATR Failed to Initialize");
  return INIT_FAILED;
  
  }
  ArrayInitialize(ATR, EMPTY_VALUE);
  ArraySetAsSeries(ATR, true); 
  return INIT_SUCCEEDED;
  }
  
  
  
  
  void OnDeinit(const int reason){
  if(ATRHandle != INVALID_HANDLE){
  IndicatorRelease(ATRHandle);
  }
  }
  
  
  
  
  
  
  double fATR(string sy, ENUM_TIMEFRAMES tf,int ATRper,int shift)
  {
   double atrBuf[];
   ArrayResize(atrBuf,ATRper+shift+1);
   int i=ATRper+shift;
   while(i>=0)
     {
      double high=iHigh(sy,tf,i);
      double low =iLow(sy,tf,i);
      double prevclose=iClose(sy,tf,i+1);
      atrBuf[i]=fmax(high,prevclose)-fmin(low,prevclose);
      i--;
     }
   return(SMA(ATRper+shift+1,atrBuf,ATRper,shift));
  }
  
  
  double SMA(const int rates_total,const double &array_src[],const int period,const int shift)
  {
   if(period<1 || shift>rates_total-period-1)
      return array_src[shift];
   double sum=0;
   for(int i=0; i<period; i++)
      sum+=array_src[shift+i];
   return(sum/period);
  }
  
  
  
  
  
  double MQL5ATR, CustomATR;
  
  
  
  void OnTick(){
  
  
  
  CopyBuffer(ATRHandle, 0, 0, 5, ATR);
  MQL5ATR = NormalizeDouble(ATR[1], Digits());
  CustomATR = NormalizeDouble(fATR(Symbol(),PERIOD_CURRENT, TestPeriod, 1),Digits());
  
  
  
  
  
  Print("MQL5 ATR - ", MQL5ATR);
  Print("Custom ATR - ", CustomATR);
  
  
  
  if(MQL5ATR == CustomATR){
  
  Print("Both ATR values are the same");
  }
  
  }
Same value as MQL5 ATR.
Shanmugi:

I purchased a EA. it is based on ATR but when i reviewed the code, there is no iATR function. it have



Instead of https://www.mql5.com/en/docs/indicators/iatr


When i asked the seller, he said this do exact same thing and also it faster than iATR

Here.

But this.

CopyBuffer(ATRHandle, 0, 0, 5, ATR);
  MQL5ATR = NormalizeDouble(ATR[1], Digits());
  CustomATR = NormalizeDouble(fATR(Symbol(),PERIOD_CURRENT, TestPeriod, 1),Digits());
  
 You are calculating ATR for every shift, very bad for programs, like this is main reason it suck to backtest custom indicators in MQL4, getting data every tick, but MQL5 creates handle once and very possible, it creates (calculate) indicator value for shift 0 to max shift possible (Since int should be 


2 147 483 646, in virtual memory and use CopyBuffer to get data anytime you need it. just saying, like might be totally wrong.

 
Arinze Michael Ejike #:
Same value as MQL5 ATR.

Thanks for the sample code. i tested and founded both value is same. 


Arinze Michael Ejike #:
You are calculating ATR for every shift, very bad for programs, like this is main reason it suck to backtest custom indicators in MQL4, getting data every tick, but MQL5 creates handle once and very possible, it creates (calculate) indicator value for shift 0 to max shift possible (Since int should be


My EA is MultiSymbol EA. it trade on multiple currency. if iATR is declared in OnInt then it cannot process the other symbol. Any idea how to use iATR with multisymbol. 

 

Yes. For multi symbols make sense to use the ATR function.

Or you can Declare multiple symbols handle.

int Symbol1, Symbol2;

iATR(Symbol(), for symbol 1, 2);

Normally we use struct and you might not like that approach. Would send a demo shortly.

 
Arinze Michael Ejike #:
int Symbol1, Symbol2;

iATR(Symbol(), for symbol 1, 2); 

I've applied formatting to the code in your post (how to insert code).

Arinze Michael Ejike #:
Would send a demo shortly. 

We are waiting for you to publish here the demo code you announced.

 
Fill Symbol array and Timeframe with your data.
Not beginner friendly but gets the job done.  Prefer you stick to functions. Example above is a Multi Symbol & Timeframe Dashboard, To get data simply.
 string sym = rsiData[i].symbol; or any index number (Symbol num in Array). 
Use the function method we used this mainly if we are copying value from Indicators we have and don't want to create it function.
And sorry for the late response.
Could find an example for ATR.

But RSI Multi Symbol -
struct RSIData {
    string symbol;
    ENUM_TIMEFRAMES timeframe;
    int handle;
    double currentValue;
    double previousValue;
    bool wasOverbought;
    bool wasOversold;
};
RSIData rsiData[];




bool InitializeRSIData() {
    int totalCells = symbolCount * timeframeCount;
    ArrayResize(rsiData, totalCells);
    
    int index = 0;
    for(int s = 0; s < symbolCount; s++) {
        for(int t = 0; t < timeframeCount; t++) {
            rsiData[index].symbol = symbolList[s]; Fill with Symbol, Symbol1, Symbol2 or Simply use Symbol()
            rsiData[index].timeframe = timeframeList[t]; Fill Array with Timeframe or simply use PERIOD_CURRENT 
            rsiData[index].currentValue = 0;
            rsiData[index].previousValue = 0;
            rsiData[index].wasOverbought = false;
            rsiData[index].wasOversold = false;
            
            rsiData[index].handle = iRSI(symbolList[s], timeframeList[t], RSIPeriod, RSIPrice);
            
            if(rsiData[index].handle == INVALID_HANDLE) {
                Print("Failed to create RSI handle for ", symbolList[s], " ", EnumToString(timeframeList[t]));
                return false;
            }
            
            index++;
        }
    }
    
    Sleep(100);
    return true;
}

void UpdateAllRSI() {
    int totalCells = ArraySize(rsiData);
    
    for(int i = 0; i < totalCells; i++) {
        if(rsiData[i].handle == INVALID_HANDLE) continue;
        
        double buffer[];
        ArraySetAsSeries(buffer, true);
        
        int copied = CopyBuffer(rsiData[i].handle, 0, 0, 3, buffer);
        
        if(copied > 0) {
            rsiData[i].previousValue = rsiData[i].currentValue;
            rsiData[i].currentValue = buffer[0];
        }
    }
}




Fill Symbol array and Timeframe with your data. Not beginner friendly but gets the job done. Prefer you stick to functions. Example above is a Multi Symbol & Timeframe Dashboard, To get data simply. string sym = rsiData[i].symbol; or any index number (Symbol num in Array). Use the function method we used this mainly if we are copying value from Indicators we have and don't want to create it function. And sorry for the late response.