ATR like trading view in MT5

 

Hi,


I need to use the same ATR calculation from trading view in Metatrader 5. This is the code I have so far, it work, but is not getting similar results with Trading View. I know the data is slightly different, but my results in the strategy are very different and I have checked everything, the think that makes big differences is the ATR calculation. This is the code I have so far, the highlighted part is what I changed from the ATR indicator by default in MT5 (only 2 lines).

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  DodgerBlue
#property indicator_label1  "ATR"
//--- input parameters
input int InpAtrPeriod=20;  // ATR period
//--- indicator buffers
double    ExtATRBuffer[];
double    ExtTRBuffer[];
//--- global variable
int       ExtPeriodATR;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input value
   if(InpAtrPeriod<=0)
     {
      ExtPeriodATR=20;
      printf("Incorrect input parameter InpAtrPeriod = %d. Indicator will use value %d for calculations.",InpAtrPeriod,ExtPeriodATR);
     }
   else ExtPeriodATR=InpAtrPeriod;
//--- indicator buffers mapping
   SetIndexBuffer(0,ExtATRBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,ExtTRBuffer,INDICATOR_CALCULATIONS);
//---
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- sets first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpAtrPeriod);
//--- name for DataWindow and indicator subwindow label
   string short_name="ATR("+string(ExtPeriodATR)+")";
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   PlotIndexSetString(0,PLOT_LABEL,short_name);
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Average True Range                                               |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
double alpha=1/ExtPeriodATR;

   int i,limit;
//--- check for bars count
   if(rates_total<=ExtPeriodATR)
      return(0); // not enough bars for calculation
//--- preliminary calculations
   if(prev_calculated==0)
     {
      ExtTRBuffer[0]=0.0;
      ExtATRBuffer[0]=0.0;
      //--- filling out the array of True Range values for each period
      for(i=1;i<rates_total && !IsStopped();i++)
         ExtTRBuffer[i]=MathMax(high[i],close[i-1])-MathMin(low[i],close[i-1]);
      //--- first AtrPeriod values of the indicator are not calculated
      double firstValue=0.0;
      for(i=1;i<=ExtPeriodATR;i++)
        {
         ExtATRBuffer[i]=0.0;
         firstValue+=ExtTRBuffer[i];
        }
      //--- calculating the first value of the indicator
      firstValue/=ExtPeriodATR;
      ExtATRBuffer[ExtPeriodATR]=firstValue;
      limit=ExtPeriodATR+1;
     }
   else limit=prev_calculated-1;
//--- the main loop of calculations
   for(i=limit;i<rates_total && !IsStopped();i++)
     {
      ExtTRBuffer[i]=MathMax(high[i],close[i-1])-MathMin(low[i],close[i-1]);
      ExtATRBuffer[i]=(ExtTRBuffer[i] - ExtATRBuffer[i-1]) * (alpha) +ExtATRBuffer[i-1] ; // Exponential Moving Average with Alpha=1/ExtPeriodATR
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

In the documentation in Trading view this is what it says about the RMA calculations, once you got the True Range (the True Range is a simple calculation and the problem is not there):


plot(rma(close, 15))

// same on pine, but much less efficient
pine_rma(x, y) =>
	alpha = y
    sum = 0.0
    sum := (x + (alpha - 1) * nz(sum[1])) / alpha
plot(pine_rma(close, 15))
RETURNS

Exponential moving average of x with alpha = 1 / y.


Anyone understand the problem here? Like I said the ATR itself is different from Trading View and is making the Strategy is very different from the results I get on Metatrader 5. Thank you!

 
THIS IS A GREAT QUESTION !  why the<..> you cant have the same <..> thing  " ATR " to behave in the same way ??? <...>

first to answer you: your highlighted line is very different from the actual RMA in TW : thats not even close
pine_rma(src, length) =>
    alpha = 1/length
    sum = 0.0
    sum := na(sum[1]) ? ta.sma(src, length) : alpha * src + (1 - alpha) * nz(sum[1])


I can convert almost anything from pinescript to MT4/5 but this part is always impossible ta.atr()  But enough is enough and I needed to have it done so here it is:


TRADINGVIEW ATR INDICATOR IN METATRADER 4 : cheers 

//+------------------------------------------------------------------+
//|                                              Tradingview ATR.mq4 |
//|                                   Copyright 2023, Filip Valkovic |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Filip Valkovic"
#property version   "1.00"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_label1  "ATR_TradingView"

//--- input parameters
input int period=14;  // ATR period
//--- indicator buffers
double    ATRBuffer[];
double    ExtTRBuffer[];
//--- global variable

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input value
//--- indicator buffers mapping
//IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   SetIndexBuffer(0,ATRBuffer);
   SetIndexBuffer(1,ExtTRBuffer);

   string short_name="TW ATR("+string(period)+")";
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   SetIndexLabel(1,"TrueRange");
   SetIndexStyle(1,DRAW_NONE);

//--- initialization done
  }
//+------------------------------------------------------------------+
//| Average True Range                                               |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   double alpha=1.0/period;
   int i=rates_total-prev_calculated+1;
   
   if(i<0)
      i=0;
   for(; i>=0 && !IsStopped(); i--)
     {
      if(i+1>rates_total-1)
         continue;
         
      ExtTRBuffer[i]=MathMax(MathMax(high[i]-low[i],MathAbs(high[i]-close[i+1])),MathAbs(low[i]-close[i+1]));
      ATRBuffer[i]=ExtTRBuffer[i];
     }
   
   i=rates_total-prev_calculated+1;
   if(i<0)
      i=0;
   for(; i>=0 && !IsStopped(); i--)
     {
     // DONT ASK ABOUT THIS PART it was error catching, it doesnt matter, it works
      if(i+period>rates_total && i>rates_total-2*(period+1))
         continue;
      if(i+period>ArraySize(ExtTRBuffer) && prev_calculated<2*period)
         continue;
         
      ATRBuffer[i]=rma(ExtTRBuffer,period,i);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double rma(double &array[],int len,int i)
  {
   double result = 0;
   double alpha = 1.0/(double)len;

   for(int j=0; j<len; j++)
     {
      if(j==0) // HERE'S THE TRICK - cannot use iMAOnArray() that throws access violation error
         result = SimpleMA(i+2*len,len+1,array); // and to get most precise TW output you use double len backstep (i+2*LEN) and then must use LEN+1 
      else
         result=(alpha* array[i+len-j] + (1.0-alpha)*result); //array[i+len-j] another big brain point
     }
   return result;
  }
//+------------------------------------------------------------------+

double SimpleMA(const int position,const int len,const double &price[])
  {
//---
   double result=0.0;
//--- check position
   if(position>=len-1 && len>0)
     {
      //--- calculate value
      for(int i=0;i<len;i++) result+=price[position-i];
      result/=len;
     }
//---
   return(result);
  }
  



 
patagonia2015: RMA calculations,
RETURNS

Exponential moving average of x with alpha = 1 / y.

Trading View's RMA is the same as MT's SMMA. Never any reason to use the SMMA(L) or RMA(L). They are equivalent to the EMA(2L-1).

 
Filip Valkovic #:

      ExtTRBuffer[i]=MathMax(MathMax(high[i]-low[i],MathAbs(high[i]-close[i+1])),MathAbs(low[i]-close[i+1]))

Simplified
ExtTRBuffer[i]=MathMax(high[i],close[i-1])-MathMin(low[i],close[i-1]);
 
William Roeder #:
Simplified

yeah these 2 points work better, thanks for clarification,  I wanted to have most alike looking code to tradingview

 

My version. Same for MT4. I do not know if there are any differences from the exemple above. I don't have time to compare, although it would be interesting

Forum on trading, automated trading systems and testing trading strategies

Could you please help me convert this pine script to mql4? Some of this like NZ function is very complex to me.

Vladislav Boyko, 2023.01.05 00:18

In the end, this

ta.atr

is what I turned into this😄

#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_label1  "pine_atr"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue

input int inpAtrLength = 14; // Length

double tr[];
double atr[];

int OnInit()
  {
   IndicatorShortName(StringFormat("pine_atr(%i)", inpAtrLength));
   int buffersNumber = 2;
   IndicatorBuffers(buffersNumber);
   SetIndexBuffer(0, atr);
   SetIndexBuffer(1, tr);
   for(int i = 0; i < buffersNumber; i++)
      SetIndexEmptyValue(i, EMPTY_VALUE);
   return(INIT_SUCCEEDED);
  }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   pine_buffer_tr(tr, high, low, close, rates_total, prev_calculated);
   pine_buffer_atr(inpAtrLength, atr, tr, rates_total, prev_calculated);
   return(rates_total);
  }

void pine_buffer_atr(int period, double &buffer[], const double &tr_data[], int rates_total, int prev_calculated)
// Different from the built-in MT4 ATR. Most likely, a different averaging is used in MT4
  {
   pine_buffer_rma(buffer, tr_data, period, rates_total, prev_calculated, 1);
  }

void pine_buffer_rma(double &buffer[], const double &source[], int period, int rates_total, int prev_calculated, int sourceBeginOffset = 0)
  {
   for(int i = bufferCalculFrom(rates_total, prev_calculated, period, sourceBeginOffset); i >= 0; i--)
      buffer[i] = pine_rma(source, period, i, buffer[i+1]);
  }

double pine_rma(const double &source[], int length, int bar, double prevValue = EMPTY_VALUE)
  {
   double alpha = 1.0 / length;
   return(prevValue == EMPTY_VALUE ? pine_sma(source, length, bar) : alpha * source[bar] + (1.0 - alpha) * prevValue);
  }

double pine_sma(const double &source[], int period, int bar)
  {
   double sum = 0.0;
   for(int i = 0; i <= period - 1; i++)
      sum += source[bar + i] / period;
   return(sum);
  }

void pine_buffer_tr(double &buffer[], const double &high[], const double &low[], const double &close[], int rates_total, int prev_calculated)
  {
   for(int i = bufferCalculFrom(rates_total, prev_calculated, 2, 0); i >= 0; i--)
      buffer[i] = pine_tr(high[i], low[i], close[i + 1]);
  }

double pine_tr(double high, double low, double prevClose)
  {
   return(MathMax(high - low, MathMax(MathAbs(high - prevClose), MathAbs(low - prevClose))));
  }

int bufferCalculFrom(int rates_total, int prev_calculated, int period, int sourceBeginOffset)
  {
   int notCalculated = rates_total - prev_calculated;
   int lastIndex = rates_total - 1;
   return((notCalculated == 0 || notCalculated == 1) ? notCalculated : (lastIndex - (period - 1)) - sourceBeginOffset);
  }

 
Filip Valkovic #:
I can convert almost anything from pinescript to MT4/5 but this part is always impossible ta.atr()  But enough is enough and I needed to have it done so here it is:

Oh, I've been interested in this for a long time: ta.linreg()

Could you share your conversion please (if you have worked with it)?

 
Vladislav Boyko #:

Oh, I've been interested in this for a long time: ta.linreg()

Could you share your conversion please (if you have worked with it)?

I see, linreg is a pain too, I hope I can help.  I don't have MQL4 code, but I have pretty simple script in pinescript, this should help you get the linreg() equivalent result with ease.

study("Linear Regression Line",overlay=true)
length = input(14)
//
x = n
y = close
x_ = sma(x,length)
y_ = sma(y,length)
mx = stdev(x,length)
my = stdev(y,length)
c = correlation(x,y,length)
slope = c * (my/mx)
//
inter = y_ - slope*x_
//
reg = x*slope + inter
plot(reg,color=red,transp=0)


https://

so for sma(x) you would best use iMAOnArray(array x, .....)
and same for stdev(X) = iStdDevOnArray() 

everything else have its direct equivalent in MQL4 so its should be straightforward conversion.

 
I was comparing and looking at 2 different ways to get TW ATR
1. iMAOnArray(ExtTRBuffer,0,2*period-1,0,MODE_EMA,i);  = 100 % IDENTICAL RESULT  as tradingview ATR 
and 
2. rma(ExtTRBuffer,period,i);

and I couldn't get them to return same results, mainly because in RMA im using: SimpleMA(const int position,const int len,const double &price[])  and I think it works differently as iMAOnArray
I did try many variations of period and shift/position parameters and it just never returned identical results

So in RMA I ended up using THIS:  because it was most precise to correct output.
SimpleMA(i+2*(len-1),2*len-1,array)


here is the updated indicator code, with both calculations plotted: (the correct one is 1st plot = iMAonarray = clrDodgerBlue = ( light blue) the 2nd plot is with RMA = clrBlue = ( darker blue)


TRADINGVIEW ATR INDICATOR IN METATRADER 4: (both plots 1.MAonArray 2.RMA)

//+------------------------------------------------------------------+
//|                                              Tradingview ATR.mq4 |
//|                                   Copyright 2023, Filip Valkovic |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Filip Valkovic"
#property version   "1.20"

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_label1  "ATR_TradingView"

#property indicator_type2   DRAW_LINE
#property indicator_color2  clrBlue
#property indicator_label2  "ATR_TradingView"

//--- input parameters
input int period=14;  // ATR period
//--- indicator buffers
double    ATRBuffer[];
double    ATRBuffer2[];

double    ExtTRBuffer[];
//--- global variable

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
//--- check for input value
//--- indicator buffers mapping
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1);
   SetIndexBuffer(0,ATRBuffer);
   SetIndexBuffer(1,ATRBuffer2);
   SetIndexBuffer(2,ExtTRBuffer);

   string short_name="TW ATR("+string(period)+")";
   IndicatorSetString(INDICATOR_SHORTNAME,short_name);
   SetIndexLabel(1,"RMA ATR");
   SetIndexStyle(2,DRAW_NONE);

//--- initialization done
  }
//+------------------------------------------------------------------+
//| Average True Range                                               |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int i=rates_total-prev_calculated+1;
   if(i<0)
      i=0;
   for(; i>=0 && !IsStopped(); i--)
     {
      if(i+2>rates_total)
        {
        //SET START OF HISTORY DATA
         ExtTRBuffer[rates_total-1]=0;
         ExtTRBuffer[rates_total-2]=0;
         ATRBuffer[rates_total-1]=0;
         ATRBuffer[rates_total-2]=0;
         
          ATRBuffer2[rates_total-1]=0;
         ATRBuffer2[rates_total-2]=0;
         continue;
        }
      ExtTRBuffer[i]=MathMax(MathMax(high[i]-low[i],MathAbs(high[i]-close[i+1])),MathAbs(low[i]-close[i+1]));
      ATRBuffer[i]=ExtTRBuffer[i];
      
      ATRBuffer2[i]=ExtTRBuffer[i];
     }

   i=rates_total-prev_calculated+1;
   if(i<0)
      i=0;
   for(; i>=0 && !IsStopped(); i--)
     {
      int lenght = 2*period-1;

      if(i+2>rates_total)
         continue;

      ATRBuffer2[i]=rma(ExtTRBuffer,period,i);
      ATRBuffer[i]=iMAOnArray(ExtTRBuffer,0,lenght,0,MODE_EMA,i);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+                                 |
//  could use the SMMA(L) or RMA(L).
//  Trading View's RMA is equivalent to the EMA(2L-1).
//+------------------------------------------------------------------+
double rma(double &array[],int len,int i)
  {
   double result = 0;
   double alpha = 1.0/(double)len;

   for(int j=0; j<len; j++)
     {
      if(j==0) //iMAOnArray(array,len,len,0,MODE_SMA,i); throws access violation error
         result = SimpleMA(i+2*(len-1),2*len-1,array); //i+2*len-1, len
      else
         result=(alpha* array[i+len-1-j] + (1.0-alpha)*result); //array[i+len-1-j]
     }
   return result;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double SimpleMA(const int position,const int len,const double &price[])
  {
//---
   double result=0.0;
//--- check position
   if(position>=len-1 && len>0)
     {
      //--- calculate value
      for(int i=0; i<len; i++)
         result+=price[position-i];
      result/=(double)len;
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
 
Filip Valkovic #:

I see, linreg is a pain too, I hope I can help.  I don't have MQL4 code, but I have pretty simple script in pinescript, this should help you get the linreg() equivalent result with ease.

so for sma(x) you would best use iMAOnArray(array x, .....)
and same for stdev(X) = iStdDevOnArray() 

everything else have its direct equivalent in MQL4 so its should be straightforward conversion.

Very interesting, thanks a lot!

Reason: