Before anyone jumps on me, I found the noob mistake courtesy of this that I had overlooked:
"in the end I just forgot to call SetIndexBuffer(...) for this buffer array in onInit() {...} of my indicator."
Feel free to modify, correct the mistake and use.
#property strict #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 3 //--- plot ADX #property indicator_label1 "ADX" #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- plot PDI #property indicator_label2 "+DI" #property indicator_type2 DRAW_LINE #property indicator_color2 clrMediumSeaGreen #property indicator_style2 STYLE_DOT #property indicator_width2 1 //--- plot NDI #property indicator_label3 "-DI" #property indicator_type3 DRAW_LINE #property indicator_color3 clrTomato #property indicator_style3 STYLE_DOT #property indicator_width3 1 //--- input int ADXPeriod=14; input int ADXSMPeriod=14; //--- indicator buffers double ADXBuffer[]; double PDIBuffer[]; double NDIBuffer[]; double HAOBuffer[]; double HACBuffer[]; double TRGBuffer[]; double PDMBuffer[]; double NDMBuffer[]; double ADLBuffer[]; //--- double up, down, trur, pdi, ndi, sum, diff; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,ADXBuffer); SetIndexBuffer(1,PDIBuffer); SetIndexBuffer(2,NDIBuffer); IndicatorBuffers(8); SetIndexBuffer(3,HACBuffer); SetIndexBuffer(4,TRGBuffer); SetIndexBuffer(5,PDMBuffer); SetIndexBuffer(6,NDMBuffer); SetIndexBuffer(7,ADLBuffer); //--- 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[]) { //--- int begin=(rates_total!=prev_calculated)?rates_total-1-prev_calculated:0; if(prev_calculated<1) { HACBuffer[begin]=(open[begin]+high[begin]+low[begin]+close[begin])/4; PDMBuffer[begin]=NDMBuffer[begin]=TRGBuffer[begin]=PDIBuffer[begin]=NDIBuffer[begin]=ADLBuffer[begin]=ADXBuffer[begin]=0; begin--; } //---- main loop for(int i=begin; i>=0; i--) HACBuffer[i] = (open[i]+high[i]+low[i]+close[i])/4;// HA modified close //--- for(int i=begin; i>=0; i--) { up = high[i]-high[i+1]; //up = change(high) down = -(low[i]-low[i+1]); //down = -change(low) PDMBuffer[i] = !up ? NULL : (up > down && up > 0 ? up : 0); //plusDM = na(up) ? na : (up > down and up > 0 ? up : 0) NDMBuffer[i] = !down ? NULL : (down > up && down > 0 ? down : 0);//minusDM = na(down) ? na : (down > up and down > 0 ? down : 0) TRGBuffer[i] = MathMax(high[i],HACBuffer[i+1])-MathMin(low[i],HACBuffer[i+1]);// --tr definition for line 91 } //--- for(int i=begin; i>=0; i--) { trur = iMAOnArray(TRGBuffer,rates_total,ADXPeriod,0,MODE_EMA,i);//trur = rma(tr, len) -- line 91 PDIBuffer[i] = (!(pdi=100*iMAOnArray(PDMBuffer,rates_total,ADXPeriod,0,MODE_EMA,i)) || !trur) ? PDIBuffer[i+1] : pdi/trur;//plus = fixnan(100 * rma(plusDM, ADXperiod) / trur) NDIBuffer[i] = (!(ndi=100*iMAOnArray(NDMBuffer,rates_total,ADXPeriod,0,MODE_EMA,i)) || !trur) ? NDIBuffer[i+1] : ndi/trur;//minus = fixnan(100 * rma(minusDM, len) / trur) sum = PDIBuffer[i] + NDIBuffer[i];//sum == 0 ? 1 : sum --from line 96 diff = MathAbs(PDIBuffer[i] - NDIBuffer[i]);//abs(plus - minus) --from line 96 ADLBuffer[i] = sum ? diff / sum : diff / 1;//abs(plus - minus) / (sum == 0 ? 1 : sum) -- line 96 from line line 100 } //--- for(int i=begin; i>=0; i--) ADXBuffer[i] = 100*iMAOnArray(ADLBuffer,rates_total,ADXSMPeriod,0,MODE_EMA,i);//adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen) // line 100 //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
So here is the amended code, still not producing equivalent plots - see pics. Any ideas?
//+------------------------------------------------------------------+ //| SmoothedHAADX.mq4 | //| Copyright 2021, andydoc1@gmail.com | //| mailto://andydoc1@gmail.com | //+------------------------------------------------------------------+ //---- port of DMI from Tradingview //---- (https://www.tradingview.com/pine-script-reference/v4/#fun_dmi) //---- applied to Heiken-Ashi Candles. //---- Still not correct as plots differently. //---- //---- PINE source code for DMI: //---- up = change(security(heikinashi(syminfo.tickerid), timeframe.period, high)) //---- down = -change(security(heikinashi(syminfo.tickerid), timeframe.period, low)) //---- plusDM = na(up) ? na : (up > down and up > 0 ? up : 0) //---- minusDM = na(down) ? na : (down > up and down > 0 ? down : 0) //---- trur = rma(tr, di_len) //---- plus = fixnan(100 * rma(plusDM, di_len) / trur) //---- minus = fixnan(100 * rma(minusDM, di_len) / trur) //---- sum = plus + minus //---- adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adx_len) //---- //---- na fills an empty value with NULL //---- tr is true range //---- rma is EMA //---- fixnan fills empty value with previous value //---- //---- original inputs: //---- di_len = ADX period //---- adx_len = ADX Smoothing period #property copyright "Copyright 2020, andydoc1" #property link "mailto://andydoc1@gmail.com" #property version "1.00" #property strict #property indicator_separate_window #property indicator_buffers 9 #property indicator_color1 White #property indicator_width1 2 #property indicator_color2 Green #property indicator_width2 1 #property indicator_style2 1 #property indicator_color3 Red #property indicator_width3 1 #property indicator_style3 2 //---- buffers double ExtMapBufferADX[]; //ADX double ExtMapBufferPDI[]; //+DI double ExtMapBufferNDI[]; //-DI double ExtMapBufferHAO[]; //O double ExtMapBufferHAC[]; //C double ExtMapBufferTR[]; //tr double ExtMapBufferPDM[]; //plusDM double ExtMapBufferMDM[]; //minusDM double ExtMapBufferDIratio[]; //DI ratio double up, down, trur, sum, diff; extern int ADXperiod=14; extern int ADXsmperiod =14; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //---- indicators SetIndexStyle(0,DRAW_LINE); SetIndexBuffer(0,ExtMapBufferADX); //ADX SetIndexLabel(0,"ADX"); SetIndexStyle(1,DRAW_LINE); SetIndexBuffer(1,ExtMapBufferPDI); //+DI SetIndexLabel(1,"Plus DI"); SetIndexStyle(2,DRAW_LINE); SetIndexBuffer(2,ExtMapBufferNDI); //-DI SetIndexLabel(2,"Minus DI"); SetIndexBuffer(3,ExtMapBufferHAO); //Heiken-Ashi Open SetIndexBuffer(4,ExtMapBufferHAC); //Heiken-Ashi Close SetIndexBuffer(5,ExtMapBufferTR); //True Range SetIndexBuffer(6,ExtMapBufferPDM); //+DM SetIndexBuffer(7,ExtMapBufferMDM); //-DM SetIndexBuffer(8,ExtMapBufferDIratio); //Ratio of Diff(+DI, -DI):Sum(+DI, -DI) IndicatorShortName("ADX("+IntegerToString(ADXperiod)+"), based on Heiken Ashi Candles, smoothed over "+IntegerToString(14)+" periods."); //---- 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[]) { //--- int counted_bars=IndicatorCounted(); if(counted_bars < 0) return(-1); if(counted_bars>0) counted_bars--; int limit=Bars-counted_bars; if(counted_bars==0) limit-=1+ADXperiod+ADXsmperiod; //---- main loop for(int i=limit-1; i>=0; i--) { ExtMapBufferHAO[i] = (Open[i+1]+Close[i+1])/2; ExtMapBufferHAC[i] = (Open[i]+High[i]+Low[i]+Close[i])/4; } for(int i=limit-1; i>=0; i--) { up = High[i]-High[i+1]; //up = change(high) down = -(Low[i]-Low[i+1]); //down = -change(low) ExtMapBufferPDM[i] = !up ? NULL : (up > down && up > 0 ? up : 0); //+DM = na(up) ? na : (up > down and up > 0 ? up : 0) ExtMapBufferMDM[i] = !down ? NULL : (down > up && down > 0 ? down : 0);//-DM = na(down) ? na : (down > up and down > 0 ? down : 0) ExtMapBufferTR[i] = MathMax(High[i] - Low[i+1], MathMax(MathAbs(High[i] - ExtMapBufferHAC[i+1]), MathAbs(Low[i+1] - ExtMapBufferHAC[i+1])));// --tr definition for line 122 } // -- line 94 for(int i=limit-(2+ADXperiod); i>=0; i--) { trur = iMAOnArray(ExtMapBufferTR,0,ADXperiod,0,1,i);//trur = rma(tr, len) -- line 122 ExtMapBufferPDI[i] = !(100*iMAOnArray(ExtMapBufferPDM,0,ADXperiod,0,1,i)/trur) ? ExtMapBufferPDI[i+1] : 100*iMAOnArray(ExtMapBufferPDM,0,ADXperiod,0,1,i)/trur;//plus = fixnan(100 * rma(plusDM, ADXperiod) / trur) ExtMapBufferNDI[i] = !(100*iMAOnArray(ExtMapBufferMDM,0,ADXperiod,0,1,i)/trur) ? ExtMapBufferNDI[i+1] : 100*iMAOnArray(ExtMapBufferMDM,0,ADXperiod,0,1,i)/trur;//minus = fixnan(100 * rma(minusDM, len) / trur) sum = ExtMapBufferPDI[i] + ExtMapBufferNDI[i] == 0.0 ? 1.0 : ExtMapBufferPDI[i] + ExtMapBufferNDI[i];//sum == 0 ? 1 : sum -- for line 127 diff = MathAbs(ExtMapBufferPDI[i] - ExtMapBufferNDI[i]);//abs(plus - minus) -- for line 127 ExtMapBufferDIratio[i] = diff / sum;//abs(plus - minus) / (sum == 0 ? 1 : sum) -- line 127 for line 131 } for(int i=limit-(3+ADXperiod+ADXsmperiod); i>=0; i--) { ExtMapBufferADX[i] = 100*iMAOnArray(ExtMapBufferDIratio,0,ADXsmperiod,0,1,i);//adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen) -- line 131 } //--- Debugging for(int i = 0;i<100;i++) { //Print(ExtMapBufferHAO[i],",",ExtMapBufferHAC[i],",",ExtMapBufferPDM[i],",",ExtMapBufferMDM[i],",",ExtMapBufferTR[i],",",ExtMapBufferPDI[i],",",ExtMapBufferNDI[i],",",ExtMapBufferDIratio[i],",",ExtMapBufferADX[i]); } //--- return value of prev_calculated for next call return(rates_total); } //+------------------------------------------------------------------+
Ernst Van Der Merwe:
Thank you, Ernst, for tidying that up - and well done for spotting that the HA open is not actually used :)
However, the ADX line is still not as smooth as that of Trading View...
Andrew Thompson:
Thank you, Ernst, for tidying that up - and well done for spotting that the HA open is not actually used :)
However, the ADX line is still not as smooth as that of Trading View...
You're welcome. Should probably have to bring the open buffer back then:)
//---- main loop for(int i=begin; i>=0; i--) { HAOBuffer[i]=haop=(HAOBuffer[i+1]+HACBuffer[i+1])/2; HACBuffer[i]=hacl=(open[i]+high[i]+low[i]+close[i])/4;// HA modified close HAHBuffer[i]=hahi=MathMax(high[i],haop,hacl); HALBuffer[i]=halo=MathMin(low[i],haop,hacl); up = hahi-HAHBuffer[i+1]; //up = change(high) down = -(halo-HALBuffer[i+1]); //down = -change(low) up = !up ? NULL : (up > down && up > 0 ? up : 0); //plusDM = na(up) ? na : (up > down and up > 0 ? up : 0) down = !down ? NULL : (down > up && down > 0 ? down : 0);//minusDM = na(down) ? na : (down > up and down > 0 ? down : 0) PDMBuffer[i] = iEMA(up,PDMBuffer[i+1],ADXPeriod); NDMBuffer[i] = iEMA(down,NDMBuffer[i+1],ADXPeriod); trur = MathMax(hahi,HACBuffer[i+1])-MathMin(halo,HACBuffer[i+1]);//or MathMax(MathMax(MathAbs(high[i]-low[i]),MathAbs(high[i]-HACBuffer[i+1])),MathAbs(low[i]-HACBuffer[i+1])); ATRBuffer[i] = iEMA(trur,ATRBuffer[i+1],ADXPeriod); PDIBuffer[i] = pdi = (!(pd=100*PDMBuffer[i]) || !(trur=ATRBuffer[i])) ? PDIBuffer[i+1] : pd/trur;//plus = fixnan(100 * rma(plusDM, ADXperiod) / trur) NDIBuffer[i] = ndi = (!(nd=100*NDMBuffer[i]) || !(trur=ATRBuffer[i])) ? NDIBuffer[i+1] : nd/trur;//minus = fixnan(100 * rma(minusDM, len) / trur) sum = pdi + ndi;//sum == 0 ? 1 : sum --from line 96 diff = MathAbs(pdi - ndi);//abs(plus - minus) --from line 96 sum = sum ? diff / sum : diff / 1;//abs(plus - minus) / (sum == 0 ? 1 : sum) -- line 96 from line line 100 ADLBuffer[i] = adl = iEMA(sum,ADLBuffer[i+1],ADXPeriod); ADXBuffer[i] = 100*adl;//adx = 100 * rma(abs(plus - minus) / (sum == 0 ? 1 : sum), adxlen) // line 100 }
Files:
Smoothed_HA_ADX.mq4
7 kb
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
You are missing trading opportunities:
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
Registration
Log in
You agree to website policy and terms of use
If you do not have an account, please register
TradingView calculates their DMI (equivalent to MT4 ADX) on the
bars used, i.e. when you select Heiken Ashi bars for the price display, the Open and Close values for the ADX calculation are the modified HA values. In addition, their DMI takes an extra input, a smoothing period, by which the ADX line is smoothed.
Their code for the DMI is freely available. I have tried to replicate the use of their DMI on Heken Ashi Bars in the quoted script below, but have become stuck with an array out of range error in line 78.
Relevant line numbers are in comments which also contain the original PINE code.
Update:
The obvious errors have been corrected (see my comment below), but, even when the scale is fixed at 1:100 I get 3 horizontal lines. Clearly there is an error in the iterations after line 94 as the buffers up to that point change:
Does anyone see where I have yet to find more errors?
Any ideas on how to get this working? The indicator is the basis for a very profitable backtest in Tradingview and I will be happy to share the strategy with anyone who helps get this working...