-
Always use strict. Fixing the warnings will save you hours of debugging, but you must understand the differences.
-
for(i = rates_total; i >= 0; i--) { ATRValue[i] = iATR(NULL, 0, 1, i);
The buffer has rates_total values. The indexes are then [0 … rates_total-1]. What are you accessing?
-
Always use strict. Fixing the warnings will save you hours of debugging, but you must understand the differences.
-
The buffer has rates_total values. The indexes are then [0 … rates_total-1]. What are you accessing?
Here I believe the problem is with array ranges – in the code you didn’t check if there are enough elements in the array to call. So you simply need to change all loops to be going from rates_total-1 (not rates total) :
for(i = rates_total-1; i >= 0; i--)
and before calling array elements you need to be sure that it’s smaller than their size (so add in line 114:
if(i+1<ArraySize(down))prev_down = down[i+1];
and 119:
if(i+1<ArraySize(down))prev_down = down[i+1];
As William Roeder mentioned above – use strict always.
Here I believe the problem is with array ranges – in the code you didn’t check if there are enough elements in the array to call. So you simply need to change all loops to be going from rates_total-1 (not rates total) :
for(i = rates_total-1; i >= 0; i--)
and before calling array elements you need to be sure that it’s smaller than their size (so add in line 114:
if(i+1<ArraySize(down))prev_down = down[i+1];
and 119:
if(i+1<ArraySize(down))prev_down = down[i+1];
Thank you very much, now it works perfectly.
For those who need a SuperTrend indicator like the one in Tradingview in Metatrader, I am republishing the code of the project here;
#property copyright "Copyright © 2022, Ahmet Akçay." #property link "" #property version "1.00" #property strict enum ENUM_ATR_MA_TYPE { ATR_MA_TYPE_SMA=0,// SMA ATR_MA_TYPE_EMA=1,// EMA ATR_MA_TYPE_SMMA=2,// SMMA ATR_MA_TYPE_LWMA=3,// LWMA }; #property indicator_chart_window #property indicator_buffers 2 #property indicator_color1 Green #property indicator_color2 Red #property indicator_width1 2 #property indicator_width2 2 double TrendUpBuffer[], TrendDownBuffer[], ATRValue[]; int trendup = 0,trenddown = 0; string MA_Name; extern int Nbr_Periods = 10; extern double Multiplier = 3.0; input ENUM_ATR_MA_TYPE ATR_MA_Type = ATR_MA_TYPE_SMMA; input ENUM_APPLIED_PRICE Source = PRICE_MEDIAN; int OnInit() { if (ATR_MA_Type == 0) { MA_Name="SMA"; } else if (ATR_MA_Type == 1) { MA_Name="EMA"; } else if (ATR_MA_Type == 2) { MA_Name="SMMA"; } else if (ATR_MA_Type == 3) { MA_Name="LWMA"; } IndicatorDigits(Digits); IndicatorBuffers(3); SetIndexBuffer(0, TrendUpBuffer); SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(0, "ST Up"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexBuffer(1, TrendDownBuffer); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(1, "ST Down"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexStyle(2,DRAW_NONE); SetIndexBuffer(2,ATRValue); 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[]) { int i; double up[], down[], SourcePrice, atr, prev_up, prev_down; int xsize = ArraySize(ATRValue); ArrayResize(up,xsize); ArrayResize(down,xsize); for(i = rates_total-1; i >= 0; i--) { ATRValue[i] = iATR(NULL, 0, 1, i); } for(i = rates_total-1; i >= 0; i--) { if (ATR_MA_Type == 0) { atr = iMAOnArray(ATRValue,0,Nbr_Periods,0,MODE_SMA,i); } else if (ATR_MA_Type == 1) { atr = iMAOnArray(ATRValue,0,Nbr_Periods,0,MODE_EMA,i); } else if (ATR_MA_Type == 2) { atr = iMAOnArray(ATRValue,0,Nbr_Periods,0,MODE_SMMA,i); } else if (ATR_MA_Type == 3) { atr = iMAOnArray(ATRValue,0,Nbr_Periods,0,MODE_LWMA,i); } if(Source == 0)SourcePrice = Close[i]; if(Source == 1)SourcePrice = Open[i]; if(Source == 2)SourcePrice = High[i]; if(Source == 3)SourcePrice = Low[i]; if(Source == 4)SourcePrice = (High[i]+Low[i])/2; if(Source == 5)SourcePrice = (High[i]+Low[i]+Close[i])/3; if(Source == 6)SourcePrice = (High[i]+Low[i]+Close[i]+Close[i])/4; up[i] = SourcePrice - (Multiplier * atr); if(i+1<ArraySize(up))prev_up = up[i+1]; if(Close[i] > prev_up){up[i] = MathMax(up[i],prev_up);} down[i] = SourcePrice + (Multiplier * atr); if(i+1<ArraySize(down))prev_down = down[i+1]; if(Close[i] < prev_down){down[i] = MathMin(down[i],prev_down);} if(Close[i] > prev_down && trendup != 1) { trendup = 1; trenddown = 0; } if(Close[i] < prev_up && trenddown != -1) { trenddown = -1; trendup = 0; } if(trendup == 0) {TrendUpBuffer[i] = EMPTY_VALUE;} if(trendup == 1){TrendUpBuffer[i] = up[i];} if(trenddown == 0){TrendDownBuffer[i] = EMPTY_VALUE;} if(trenddown == -1){TrendDownBuffer[i] = down[i];} } return(rates_total); }
@Marzena Maria Szmit beat me to it , but here is a different adaptation . Lets say this has a carbon fiber exterior and is more aerodynamic .
Great work though @Marzena Maria Szmit @Ahmet Akçay 👏 👏 👏
#property copyright "Copyright © 2022, Ahmet Akçay." #property link "https://www.mql5.com/en/users/ahmetakcay" #property version "1.00" #property strict #property indicator_buffers 10 #property indicator_plots 2 #property indicator_chart_window #property indicator_color1 Green #property indicator_color2 Red #property indicator_width1 2 #property indicator_width2 2 extern int Nbr_Periods = 10; extern double Multiplier = 3.0; input ENUM_MA_METHOD ATR_MA_Type = MODE_SMMA; input ENUM_APPLIED_PRICE Source = PRICE_MEDIAN; /* first we turn up down prev up prev down into buffers , why? if a new tick comes it resets your prevs variables if new data comes in the past the prevs it has will be from the present , or , it's future which is impossible Also since you are sequencing previous states you will need a hard reset function for when new data comes in Same for the trendup and trenddown */ double TrendUpBuffer[], TrendDownBuffer[], ATRValue[],up[],down[],prev_up[],prev_down[],trendup[],trenddown[],range[]; string MA_Name; //here is the reset function void reset(){ ArrayFill(TrendUpBuffer,0,ArraySize(TrendUpBuffer),0.0); ArrayFill(TrendDownBuffer,0,ArraySize(TrendDownBuffer),0.0); ArrayFill(ATRValue,0,ArraySize(ATRValue),0.0); ArrayFill(up,0,ArraySize(up),0.0); ArrayFill(down,0,ArraySize(down),0.0); ArrayFill(prev_up,0,ArraySize(prev_up),0.0); ArrayFill(prev_down,0,ArraySize(prev_down),0.0); ArrayFill(trendup,0,ArraySize(trendup),0.0); ArrayFill(trenddown,0,ArraySize(trenddown),0.0); ArrayFill(range,0,ArraySize(range),0.0); /* one may ask , "aren't there better more efficient ways to reset depending on where the new data landed ? i think this code would crash the cpu of a 1976 jumbo jet 747 !" yes there are better ways. For now , we'll use this though */ } int OnInit() { if (ATR_MA_Type == 0) { MA_Name="SMA"; } else if (ATR_MA_Type == 1) { MA_Name="EMA"; } else if (ATR_MA_Type == 2) { MA_Name="SMMA"; } else if (ATR_MA_Type == 3) { MA_Name="LWMA"; } SetIndexBuffer(0, TrendUpBuffer); SetIndexEmptyValue(0,0.0); SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(0, "ST Up"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexBuffer(1, TrendDownBuffer); SetIndexEmptyValue(1,0.0); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(1, "ST Down"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexStyle(2,DRAW_NONE); SetIndexBuffer(2,ATRValue); SetIndexStyle(3,DRAW_NONE); SetIndexBuffer(3,up); SetIndexStyle(4,DRAW_NONE); SetIndexBuffer(4,down); SetIndexStyle(5,DRAW_NONE); SetIndexBuffer(5,prev_up); SetIndexStyle(6,DRAW_NONE); SetIndexBuffer(6,prev_down); SetIndexStyle(7,DRAW_NONE); SetIndexBuffer(7,trendup); SetIndexStyle(8,DRAW_NONE); SetIndexBuffer(8,trenddown); SetIndexStyle(9,DRAW_NONE); SetIndexBuffer(9,range); 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[]) { /* Some basics first when you set index buffers they are automatically sized to this : rates_total The first element in an array is [0] So if we have 5 items in an array and the first one is [0] the last one will be [4] [0][1][2][3][4] or it will be [items-1] or in this case rates_total-1 Secondly , if you have periods in your parameters you will need to start calculations after the max period can be attained For instance Let's say i have 10 items and i want the MA5 i cannot take the MA5 on items [0][1][2][3] because there are <5 items So , similarly . The indicator provides the size of the indexes as rates_total and we saw we must start from rates_total-1 so we will also subtract the maximum period out of that Before that though we need to run another check : Lets assume again you have a box with 5 golden bars. I cannot see in the box and i have my eyes closed Your task is to keep a tab of how many golden bars are in the box and how many i have seen. So at first Golden Bars = 5 , I have seen =0 (i have not opened the box yet so i have not seen anything) then i open the box i see there is 5 Golden Bars you log it Golden Bars = 5 , I have seen =5 what if you add a Golden Bar in the box Golden Bars = 6 , I have seen =5 now the next time i check the box you will know i saw 1 golden bar more The box is the indexes The golden bars is rates_total How many i have seen is prev_calculated The looking event is OnCalculate By looking at this its evident there are some variants which will assist in making your indicator more efficient : a.There have been no bars processed(seen) at all (prev_calculated=0) b.All bars have been processed(seen) and there are no new bars (prev_calculated=rates_total) You can think of this as a tick in the latest bar c.A new bar forms and all have been processed but not this one (rates_total=prev_calculated+1) d.New data has come in because the user went back in time or your broker filled a gap (rates_total>prev_calculated , prev_calculated!=0) So based on this lets create a variable that is going to tell you -how many new bars are there -manage the access loop with a from integer We first identify how many new bars exist (so if prev calculated is 0 it will mean all the bars are new) */ int to_calc=rates_total-prev_calculated; /* to_calc guides on how much we will access in the loop and wether or not reset will be called So , we create a from integer which holds where the loop is going to start and we assign it to_calc value , why ? -> If no new bars exist you will get to_calc=0 and you will just check the live bar , from 0 to 0 -> If one new bar comes in you will get to_calc=1 and you will just check bar [1] and the live bar [0] -> and then you can set a threshold for when you think a reset is needed Again , one may say : "But this code would crash the Apollo 1 cpu , how do you determine how many bars justify a reset ? " You estimate , usually you are interested if its bigger than your period but lets say 100 . Its a relatively safe amount So , step 1 set from to calcs */ int from=to_calc; //and if its bigger than 100 , call reset if(from>100){ reset(); /* and one more thing , set the from to the earliest valid bar (with data if you take into account your period) so */ from=rates_total-1-Nbr_Periods; /* from is total bars - 1 because we are counting from [0] , and minus the period so let's enter the loop */ } double atr=0.0,SourcePrice=0.0; //loop from to 0 for(int i=from; i>=0; i--) { range[i] = High[i]-Low[i]; ATRValue[i]=simpleSTR8forwardAndFastMaOnArray(range,i,Nbr_Periods,ATR_MA_Type,true,from-i,ATRValue[i+1]); atr=ATRValue[i]; if(Source == 0){SourcePrice = Close[i];} else if(Source == 1){SourcePrice = Open[i];} else if(Source == 2){SourcePrice = High[i];} else if(Source == 3){SourcePrice = Low[i];} else if(Source == 4){SourcePrice = (High[i]+Low[i])/2;} else if(Source == 5){SourcePrice = (High[i]+Low[i]+Close[i])/3;} else if(Source == 6){SourcePrice = (High[i]+Low[i]+Close[i]+Close[i])/4;} /* dont forget prev up and prev down are now buffers and so are trendup and trenddown and we need to propagate (carry) the previous values of trendup and trendown */ trendup[i]=trendup[i+1]; trenddown[i]=trenddown[i+1]; up[i] = SourcePrice - (Multiplier * atr); prev_up[i] = up[i+1]; down[i] = SourcePrice + (Multiplier * atr); prev_down[i] = down[i+1]; if(Close[i] > prev_up[i]){up[i] = MathMax(up[i],prev_up[i]);} if(Close[i] < prev_down[i]){down[i] = MathMin(down[i],prev_down[i]);} if(Close[i] > prev_down[i] && trendup[i+1] != 1) { trendup[i] = 1; trenddown[i] = 0; } if(Close[i] < prev_up[i] && trenddown[i] != -1) { trenddown[i] = -1; trendup[i] = 0; } if(trendup[i] == 1) {TrendUpBuffer[i] = up[i];} if(trenddown[i] == -1){TrendDownBuffer[i] = down[i];} } return(rates_total); } /* ma of array */ double simpleSTR8forwardAndFastMaOnArray(const double &which_array[], int where,//start from where int period, ENUM_MA_METHOD mode, bool is_series, int calc_index,//this measures which calculation this is starting from 0 double previous_ma){//and this receives the previous value double result=0.0; //starting point int from=0; int step=0; int until=where; if(!is_series){ from=where-period+1; step=1; } else{ from=where+period-1; step=-1; } if(until>=0&&until<ArraySize(which_array)&&from>=0&&from<ArraySize(which_array)){ //sma or first ema or first smma if(mode==MODE_SMA||(mode==MODE_EMA&&calc_index==0)||(mode==MODE_SMMA&&calc_index==0)){ int i=from-step; while(i!=until) { i+=step; result+=which_array[i]; } result/=((double)period); } //ema non first else if(mode==MODE_EMA){ double w=2.00/((double)period+1.0); result=which_array[until]*w+previous_ma*(1-w); } //smma non first else if(mode==MODE_SMMA){ result=((previous_ma*((double)period))-previous_ma+which_array[until])/((double)period); } //lwma else if(mode==MODE_LWMA){ int i=from-step; double divider=0.0; int weight=0.0; while(i!=until) { i+=step; weight+=1.0; result+=which_array[i]*weight; divider+=weight; } result/=divider; } } return(result); }
and the compact version :
#property copyright "Copyright © 2022, Ahmet Akçay." #property link "https://www.mql5.com/en/users/ahmetakcay" #property version "1.00" #property strict #property indicator_buffers 8 #property indicator_plots 2 #property indicator_chart_window #property indicator_color1 Green #property indicator_color2 Red #property indicator_width1 2 #property indicator_width2 2 extern int Nbr_Periods = 10; extern double Multiplier = 3.0; input ENUM_MA_METHOD ATR_MA_Type = MODE_SMMA; input ENUM_APPLIED_PRICE Source = PRICE_MEDIAN; double TrendUpBuffer[],TrendDownBuffer[],ATRValue[],up[],down[],trendup[],trenddown[],range[]; string MA_Name; //here is the reset function void reset(){ ArrayFill(TrendUpBuffer,0,ArraySize(TrendUpBuffer),0.0); ArrayFill(TrendDownBuffer,0,ArraySize(TrendDownBuffer),0.0); ArrayFill(ATRValue,0,ArraySize(ATRValue),0.0); ArrayFill(up,0,ArraySize(up),0.0); ArrayFill(down,0,ArraySize(down),0.0); ArrayFill(trendup,0,ArraySize(trendup),0.0); ArrayFill(trenddown,0,ArraySize(trenddown),0.0); ArrayFill(range,0,ArraySize(range),0.0); } int OnInit() { if (ATR_MA_Type == 0) { MA_Name="SMA"; } else if (ATR_MA_Type == 1) { MA_Name="EMA"; } else if (ATR_MA_Type == 2) { MA_Name="SMMA"; } else if (ATR_MA_Type == 3) { MA_Name="LWMA"; } SetIndexBuffer(0, TrendUpBuffer); SetIndexEmptyValue(0,0.0); SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(0, "ST Up"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexBuffer(1, TrendDownBuffer); SetIndexEmptyValue(1,0.0); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, 2); SetIndexLabel(1, "ST Down"+" ("+Nbr_Periods+","+Multiplier+","+MA_Name+")"); SetIndexStyle(2,DRAW_NONE); SetIndexBuffer(2,ATRValue); SetIndexStyle(3,DRAW_NONE); SetIndexBuffer(3,up); SetIndexStyle(4,DRAW_NONE); SetIndexBuffer(4,down); SetIndexStyle(5,DRAW_NONE); SetIndexBuffer(5,trendup); SetIndexStyle(6,DRAW_NONE); SetIndexBuffer(6,trenddown); SetIndexStyle(7,DRAW_NONE); SetIndexBuffer(7,range); 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[]) { int to_calc=rates_total-prev_calculated; int from=to_calc; if(from>100){ reset(); from=rates_total-1-Nbr_Periods; } double SourcePrice=0.0; for(int i=from; i>=0; i--) { range[i] = High[i]-Low[i]; ATRValue[i]=simpleSTR8forwardAndFastMaOnArray(range,i,Nbr_Periods,ATR_MA_Type,true,from-i,ATRValue[i+1]); if(Source == 0){SourcePrice = Close[i];} else if(Source == 1){SourcePrice = Open[i];} else if(Source == 2){SourcePrice = High[i];} else if(Source == 3){SourcePrice = Low[i];} else if(Source == 4){SourcePrice = (High[i]+Low[i])/2;} else if(Source == 5){SourcePrice = (High[i]+Low[i]+Close[i])/3;} else if(Source == 6){SourcePrice = (High[i]+Low[i]+Close[i]+Close[i])/4;} trendup[i]=trendup[i+1]; trenddown[i]=trenddown[i+1]; up[i] = SourcePrice - (Multiplier * ATRValue[i]); down[i] = SourcePrice + (Multiplier * ATRValue[i]); if(Close[i] > up[i+1]){up[i] = MathMax(up[i],up[i+1]);} if(Close[i] < down[i+1]){down[i] = MathMin(down[i],down[i+1]);} if(Close[i] > down[i+1] && trendup[i+1] != 1) { trendup[i] = 1; trenddown[i] = 0; } if(Close[i] < up[i+1] && trenddown[i] != -1) { trenddown[i] = -1; trendup[i] = 0; } if(trendup[i] == 1) {TrendUpBuffer[i] = up[i];} if(trenddown[i] == -1){TrendDownBuffer[i] = down[i];} } return(rates_total); } /* ma of array */ double simpleSTR8forwardAndFastMaOnArray(const double &which_array[], int where,//start from where int period, ENUM_MA_METHOD mode, bool is_series, int calc_index,//this measures which calculation this is starting from 0 double previous_ma){//and this receives the previous value double result=0.0; //starting point int from=0; int step=0; int until=where; if(!is_series){ from=where-period+1; step=1; } else{ from=where+period-1; step=-1; } if(until>=0&&until<ArraySize(which_array)&&from>=0&&from<ArraySize(which_array)){ //sma or first ema or first smma if(mode==MODE_SMA||(mode==MODE_EMA&&calc_index==0)||(mode==MODE_SMMA&&calc_index==0)){ int i=from-step; while(i!=until) { i+=step; result+=which_array[i]; } result/=((double)period); } //ema non first else if(mode==MODE_EMA){ double w=2.00/((double)period+1.0); result=which_array[until]*w+previous_ma*(1-w); } //smma non first else if(mode==MODE_SMMA){ result=((previous_ma*((double)period))-previous_ma+which_array[until])/((double)period); } //lwma else if(mode==MODE_LWMA){ int i=from-step; double divider=0.0; int weight=0.0; while(i!=until) { i+=step; weight+=1.0; result+=which_array[i]*weight; divider+=weight; } result/=divider; } } return(result); }
@Marzena Maria Szmit beat me to it , but here is a different adaptation . Lets say this has a carbon fiber exterior and is more aerodynamic .
Great work though @Marzena Maria Szmit @Ahmet Akçay 👏 👏 👏
and the compact version :
I only know mql4 at the beginning stage, these codes are too heavy for me for now.But I will try to understand it :D
![MQL5 - Language of trade strategies built-in the MetaTrader 5 client terminal](https://c.mql5.com/i/registerlandings/logo-2.png)
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hello, I am new to MQL4 programming language and I am trying to write the SuperTrend indicator in Tradingview in mql4. My problem is that when I use the #properties strict code, my program does not work, but when I delete this code, the program runs smoothly. What do you think I should change in my code, can you help me ?
Note: The program works without using 'properties #strict', but will it cause a problem in the future if I run this code without using it?