Help Converting TDI Indicator on TradingView to MT5

 

As my first project I've started by trying to convert the following to MT5.


//
// @author LazyBear
// If you use this code in its orignal/modified form, do drop me a note. 
// 
// Modified by Bromley

study("TDI - Traders Dynamic Index [Goldminds]", shorttitle="TDIGM")

rsiPeriod = input(11, minval = 1, title = "RSI Period")
bandLength = input(31, minval = 1, title = "Band Length")
lengthrsipl = input(1, minval = 0, title = "Fast MA on RSI")
lengthtradesl = input(9, minval = 1, title = "Slow MA on RSI")

src = close                                                             // Source of Calculations (Close of Bar)
r = rsi(src, rsiPeriod)                                                 // RSI of Close
ma = sma(r, bandLength)                                                 // Moving Average of RSI [current]
offs = (1.6185 * stdev(r, bandLength))                                  // Offset
up = ma + offs                                                          // Upper Bands
dn = ma - offs                                                          // Lower Bands
mid = (up + dn) / 2                                                     // Average of Upper and Lower Bands
fastMA = sma(r, lengthrsipl)                                            // Moving Average of RSI 2 bars back
slowMA = sma(r, lengthtradesl)                                          // Moving Average of RSI 7 bars back

hline(30)                                                               // Oversold
hline(50)                                                               // Midline
hline(70)                                                               // Overbought

upl = plot(up, "Upper Band", color = blue)                              // Upper Band
dnl = plot(dn, "Lower Band", color = blue)                              // Lower Band
midl = plot(mid, "Middle of Bands", color = orange, linewidth = 2)      // Middle of Bands

plot(slowMA, "Slow MA", color=green, linewidth=2)                       // Plot Slow MA
plot(fastMA, "Fast MA", color=red, linewidth=2)                         // Plot Fast MA

fill(upl, midl, red, transp=90)                                         // Fill Upper Half Red
fill(midl, dnl, green, transp=90)                                       // Fill Lower Half Green


In my attempt I got this far using the MACD and RSI examples.

//+------------------------------------------------------------------+
//|                                                          TDI.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//#include <MovingAverages.mqh>

#property indicator_separate_window
#property indicator_plots   5
#property indicator_buffers 6

#property indicator_label1  "Upper Band" 
#property indicator_type1   DRAW_LINE 
#property indicator_color1  Blue 
#property indicator_style1  STYLE_SOLID 
#property indicator_width1  2 

#property indicator_label2  "Lower Band" 
#property indicator_type2   DRAW_LINE 
#property indicator_color2  Blue 
#property indicator_style2  STYLE_SOLID 
#property indicator_width2  2 

#property indicator_label3  "Middle of Bands" 
#property indicator_type3   DRAW_LINE 
#property indicator_color3  Orange 
#property indicator_style3  STYLE_SOLID 
#property indicator_width3  2 

#property indicator_label4  "Slow MA" 
#property indicator_type4   DRAW_LINE 
#property indicator_color4  Green 
#property indicator_style4  STYLE_SOLID 
#property indicator_width4  2 

#property indicator_label5  "Fast MA" 
#property indicator_type5   DRAW_LINE 
#property indicator_color5  Red 
#property indicator_style5  STYLE_SOLID 
#property indicator_width5  2 

//--- input parameters
input int rsiPeriod = 13;
input int bandLength = 31;
input int lengthrsipl = 2;
input int lengthtradesl = 7;

input ENUM_APPLIED_PRICE   InpAppliedPrice=PRICE_CLOSE; // Applied price

double up[];
double dn[];
double mid[];
double fastMA[];
double slowMA[];
double iRSIBuffer[];

int    ExtFastMaHandle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, up, INDICATOR_DATA);
   SetIndexBuffer(1, dn, INDICATOR_DATA);
   SetIndexBuffer(2, mid, INDICATOR_DATA);
   SetIndexBuffer(3, slowMA, INDICATOR_DATA);
   SetIndexBuffer(4, fastMA, INDICATOR_DATA);
   SetIndexBuffer(5, iRSIBuffer, INDICATOR_CALCULATIONS);
   
   PlotIndexSetString(0,PLOT_LABEL,"Band Upper");
   PlotIndexSetString(1,PLOT_LABEL,"Band Lower");
   PlotIndexSetString(2,PLOT_LABEL,"Band Middle");
   
   IndicatorSetString(INDICATOR_SHORTNAME,"TDI");
   
   //PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,bandLength);
 //--- sets first bar from what index will be drawn
   //PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,rsiPeriod-1);     

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   if(rates_total<bandLength)
      return(0);
//---
   int start;
   if(prev_calculated==0)
      start=0;
   else
      start=prev_calculated-1;

   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<0)
      to_copy=rates_total;
   else
     {
      to_copy=rates_total-prev_calculated;
      if(prev_calculated>0)
         to_copy++;
     }      
//--- calculate TDI
   CopyBuffer(iRSI(NULL, 0, rsiPeriod, InpAppliedPrice),5,0,to_copy,iRSIBuffer);
      
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double r = iRSIBuffer[i];
      double ma = iMA(NULL, 0, bandLength, 0, MODE_SMA, r);
      double offs = 1.6185 * iStdDev(NULL, 0, bandLength, 0, MODE_SMA, r);
      up[i] = ma + offs;
      dn[i] = ma - offs;
      mid[i] = (up[i] + dn[i]) / 2;
      fastMA[i] = iMA(NULL, 0, lengthrsipl, 0, MODE_SMA, r);
      slowMA[i] = iMA(NULL, 0, lengthtradesl, 0, MODE_SMA, r);
     }
     
   return(rates_total);
  }
//+------------------------------------------------------------------+

All I get are straight lines, with the fast and slow printing on the mid.  I know my issues is in iMA, since I want to get a MA of the RSI.  Anyone have any suggestions?

      fastMA[i] = iMA(r, 0, lengthrsipl, 0, MODE_SMA, i);
      slowMA[i] = iMA(r, 0, lengthtradesl, 0, MODE_SMA, i);

It should look like this

Files:
TDI_MT4.JPG  57 kb
 

From reading other forums it sems I should be using 

double SimpleMA(const int position,const int period,const double &price[])
 

I have it now at least looking closer to expected.

//+------------------------------------------------------------------+
//|                                                          TDI.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <MAArray.mqh>

#property indicator_separate_window
#property indicator_plots   5
#property indicator_buffers 6

#property indicator_label1  "Upper Band"
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "Lower Band"
#property indicator_type2   DRAW_LINE
#property indicator_color2  Blue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

#property indicator_label3  "Middle of Bands"
#property indicator_type3   DRAW_LINE
#property indicator_color3  Orange
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

#property indicator_label4  "Slow MA"
#property indicator_type4   DRAW_LINE
#property indicator_color4  Green
#property indicator_style4  STYLE_SOLID
#property indicator_width4  2

#property indicator_label5  "Fast MA"
#property indicator_type5   DRAW_LINE
#property indicator_color5  Red
#property indicator_style5  STYLE_SOLID
#property indicator_width5  2

//--- input parameters
input int rsiPeriod = 13;
input int bandLength = 31;
input int lengthrsipl = 2;
input int lengthtradesl = 7;

input ENUM_APPLIED_PRICE   InpAppliedPrice=PRICE_CLOSE; // Applied price

double up[];
double dn[];
double mid[];
double fastMA[];
double slowMA[];
double iRSIBuffer[];

int    rsiHandle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, up, INDICATOR_DATA);
   SetIndexBuffer(1, dn, INDICATOR_DATA);
   SetIndexBuffer(2, mid, INDICATOR_DATA);
   SetIndexBuffer(3, slowMA, INDICATOR_DATA);
   SetIndexBuffer(4, fastMA, INDICATOR_DATA);
   SetIndexBuffer(5, iRSIBuffer, INDICATOR_CALCULATIONS);

   PlotIndexSetString(0,PLOT_LABEL,"Band Upper");
   PlotIndexSetString(1,PLOT_LABEL,"Band Lower");
   PlotIndexSetString(2,PLOT_LABEL,"Band Middle");

   IndicatorSetString(INDICATOR_SHORTNAME,"TDI");

//PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,bandLength);
//--- sets first bar from what index will be drawn
//PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,rsiPeriod-1);

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
   if(rates_total<bandLength)
      return(0);
//---
   int start;
   if(prev_calculated==0)
      start=0;
   else
      start=prev_calculated-1;

   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<0)
      to_copy=rates_total;
   else
     {
      to_copy=rates_total-prev_calculated;
      if(prev_calculated>0)
         to_copy++;
     }
//--- calculate TDI
   rsiHandle = iRSI(NULL, 0, rsiPeriod, InpAppliedPrice);
//--- not all data may be calculated
   int calculated=BarsCalculated(rsiHandle);
   if(calculated<rates_total)
     {
      Print("Not all data of rsiHandle is calculated (",calculated," bars). Error ",GetLastError());
      return(0);
     }

   CopyBuffer(rsiHandle,0,0,to_copy,iRSIBuffer);

   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double ma = iMAOnArray(iRSIBuffer, bandLength, 0, MODE_SMA, i);
      double offs = 1.6185 * iStdDev(NULL, 0, bandLength, 0, MODE_SMA, rsiHandle);
      up[i] = ma + offs;
      dn[i] = ma - offs;
      mid[i] = (up[i] + dn[i]) / 2;

      fastMA[i] = iMAOnArray(iRSIBuffer, lengthrsipl, 0, MODE_SMA, i);
      slowMA[i] = iMAOnArray(iRSIBuffer, lengthtradesl, 0, MODE_SMA, i);
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+

Code for the include I found on an old forum post.

//+------------------------------------------------------------------+
//|                                                      MAArray.mqh |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property link      "https://www.mql5.com"

//+------------------------------------------------------------------+
//| iMAOnArray from MT4                                           |
//+------------------------------------------------------------------+
double iMAOnArray(double& array[], int period, int ma_shift, ENUM_MA_METHOD ma_method, int shift){

   double buf[], arr[];
   int total = ArraySize(array);   

   if(total <= period)
      return 0;      

   if(shift > total - period - ma_shift)
      return 0;     

   switch(ma_method) {

   case MODE_SMA: {

      total = ArrayCopy(arr, array, 0, shift + ma_shift, period);
      if (ArrayResize(buf, total) < 0)
         return 0;

      double sum = 0;
      int i, pos = total-1;      

      for (i = 1; i < period; i++, pos--)

         sum += arr[pos];

      while (pos >= 0) {

         sum += arr[pos];

         buf[pos] = sum / period;

         sum -= arr[pos + period - 1];

         pos--;

      }

      return buf[0];

   }

      

   case MODE_EMA: {

      if (ArrayResize(buf, total) < 0)

         return 0;

      double pr = 2.0 / (period + 1);

      int pos = total - 2;

      

      while (pos >= 0) {

         if (pos == total - 2)

            buf[pos+1] = array[pos+1];

         buf[pos] = array[pos] * pr + buf[pos+1] * (1-pr);

         pos--;

      }

      return buf[shift+ma_shift];

   }

   

   case MODE_SMMA: {

      if (ArrayResize (buf, total) < 0)

         return(0);

      double sum = 0;

      int i, k, pos;

      

      pos = total - period;

      while (pos >= 0) {

         if (pos == total - period) {

            for (i = 0, k = pos; i < period; i++, k++) {

               sum += array[k];

               buf[k] = 0;

            }

         }

         else

            sum = buf[pos+1] * (period-1) + array[pos];

         buf[pos]=sum/period;

         pos--;

      }

      return buf[shift+ma_shift];

   }

   

   case MODE_LWMA: {

         if (ArrayResize (buf, total) < 0)

            return 0;

         double sum = 0.0, lsum = 0.0;

         double price;

         int i, weight = 0, pos = total-1;

         

         for(i = 1; i <= period; i++, pos--) {

            price = array[pos];

            sum += price * i;

            lsum += price;

            weight += i;

         }

         pos++;

         i = pos + period;

         while (pos >= 0) {

            buf[pos] = sum / weight;

            if (pos == 0)

               break;

            pos--;

            i--;

            price = array[pos];

            sum = sum - lsum + price * period;

            lsum -= array[i];

            lsum += price;

         }         

         return buf[shift+ma_shift];

      }

   }

   return 0;

}
 
Is it solved using iMAonArray?

I got the MA of an RSI by designing the MA functions a particular way, and using a buffer to keep track of data per MA function