MQL4 Coding help - convert indicator logic to functions

 

Hi, Ive been trying to convert indicator logic to a function but it seems not to work and I get repainting issues. Please see the code attached and let me know where I've gone wrong because this doesnt make sense to me.


Attachments are original code and include containing the function.


Original Code:

//+------------------------------------------------------------------+
//|                                                  ATRStops_v1.mq4 |
//|                                  Copyright © 2006, Forex-TSD.com |
//|                         Written by IgorAD,igorad2003@yahoo.co.uk |   
//|            http://finance.groups.yahoo.com/group/TrendLaboratory |                                      
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Forex-TSD.com "
#property link      "http://www.forex-tsd.com/"

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Blue
#property indicator_color2 Red


//---- input parameters
extern int    Length=10;
extern int    ATRperiod=10;
extern double Kv=2.5;

//---- indicator buffers
double UpBuffer1[];
double DnBuffer1[];
double smin[];
double smax[];
double trend[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
  int init()
  {
   string short_name;
//---- indicator line
   SetIndexStyle(0,DRAW_LINE);
   SetIndexStyle(1,DRAW_LINE);
   IndicatorBuffers(5);
   SetIndexBuffer(0,UpBuffer1);
   SetIndexBuffer(1,DnBuffer1);
   SetIndexBuffer(2,smin);
   SetIndexBuffer(3,smax);
   SetIndexBuffer(4,trend);
//---- name for DataWindow and indicator subwindow label
   short_name="ATRStops("+Length+")";
   IndicatorShortName(short_name);
   SetIndexLabel(0,"Up");
   SetIndexLabel(1,"Dn");
//----
   SetIndexDrawBegin(0,Length);
   SetIndexDrawBegin(1,Length);
//----
   return(0);
  }

//+------------------------------------------------------------------+
//| ATRStops_v1                                                     |
//+------------------------------------------------------------------+
int start()
  {
   
   int shift,limit, counted_bars=IndicatorCounted();
   
   if ( counted_bars > 0 )  limit=Bars-counted_bars;
   if ( counted_bars < 0 )  return(0);
   if ( counted_bars ==0 )  limit=Bars-Length-1; 
     
        for(shift=limit;shift>=0;shift--) 
   {    
      smin[shift] = -100000; smax[shift] = 100000;
      for (int i = Length-1;i>=0;i--)
      {
      smin[shift] = MathMax( smin[shift], High[shift+i] - Kv*iATR(NULL,0,ATRperiod,shift+i)); 
      smax[shift] = MathMin( smax[shift], Low[shift+i] + Kv*iATR(NULL,0,ATRperiod,shift+i));
      }
        
          trend[shift]=trend[shift+1];
          if ( Close[shift] > smax[shift+1] ) trend[shift] =  1;
          if ( Close[shift] < smin[shift+1] ) trend[shift] = -1;
        
          if ( trend[shift] >0 ) 
          {
          if( smin[shift]<smin[shift+1] ) smin[shift]=smin[shift+1];
          UpBuffer1[shift]=smin[shift];
          DnBuffer1[shift] = EMPTY_VALUE;
          }
          if ( trend[shift] <0 ) 
          {
          if( smax[shift]>smax[shift+1] ) smax[shift]=smax[shift+1];
          UpBuffer1[shift]=EMPTY_VALUE;
          DnBuffer1[shift] = smax[shift];
          }
        
        }
        return(0);      
 }



As function:

//+------------------------------------------------------------------+
//| ATR STOP                                                                |
//+------------------------------------------------------------------+
double UpBuffer1[];
double DnBuffer1[];
double smin[];
double smax[];
double trend[];
bool atr_buffers_resized = false;
void IND_ATR_STOP( int period, double multiplier, int bars, int i, const double &_high[], const double &_low[], const double &_close[], bool drawing_mode = false)
{

   if(!drawing_mode)
   {
      if(!atr_buffers_resized)
      {
         ArrayResize(smin, bars);
         ArrayResize(smax, bars);
         ArrayResize(UpBuffer1, bars);
         ArrayResize(DnBuffer1, bars);
         ArrayResize(trend, bars);
         ArrayInitialize(smin, EMPTY_VALUE);
         ArrayInitialize(smax, EMPTY_VALUE);
         ArrayInitialize(trend, EMPTY_VALUE);
         ArrayInitialize(UpBuffer1, EMPTY_VALUE);
         ArrayInitialize(DnBuffer1, EMPTY_VALUE);
         atr_buffers_resized = true;
      }

      DnBuffer1[i]   = EMPTY_VALUE;
      UpBuffer1[i]   = EMPTY_VALUE;
      trend[i] = EMPTY_VALUE;
      smin[i] = EMPTY_VALUE;
      smax[i] = EMPTY_VALUE;
      smin[i] = -100000;
      smax[i] = 100000;
      for (int ii = period - 1; ii >= 0; ii--)
      {
         double mp = ( _high[i + ii] + _low[i + ii]) / 2;
         smin[i] = MathMax( smin[i], mp - multiplier * iATR(NULL, 0, period, i + ii));
         smax[i] = MathMin( smax[i], mp + multiplier * iATR(NULL, 0, period, i + ii));
      }

      trend[i] = trend[i + 1];
      double midian_price = ( _high[i] + _low[i]) / 2;
      if ( midian_price > smax[i + 1] ) trend[i] =  1;
      if ( midian_price < smin[i + 1] ) trend[i] = -1;

      if ( trend[i] > 0 )
      {
         if( smin[i] < smin[i + 1] ) smin[i] = smin[i + 1];
         UpBuffer1[i] = smin[i];
         DnBuffer1[i] = EMPTY_VALUE;
      }
      if ( trend[i] < 0 )
      {
         if( smax[i] > smax[i + 1] ) smax[i] = smax[i + 1];
         UpBuffer1[i] = EMPTY_VALUE;
         DnBuffer1[i] = smax[i];
      }
   }


}




How I call the 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 limit = MathMax(available_bars - 5  - prev_calculated, 5);
   int i = 0;

   for(i =  limit; i >= 0 && !IsStopped(); i--)
   {
 
         IND_ATR_STOP(20, 3, rates_total, i, high, low, close);
         //fill draw buffers
         atr_stop_dn[i] = UpBuffer1[i]; 
         atr_stop_up[i] = DnBuffer1[i];
   }
      
}



Any help will be highly appreciated, this has been pissing me off for almost a year now. Thanks.

Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
Documentation on MQL5: Constants, Enumerations and Structures / Named Constants / Predefined Macro Substitutions
  • www.mql5.com
//| Expert initialization function                                   | //| Expert deinitialization function                                 | //| Expert tick function                                             | //| test1                                                            |...
Files:
 
Paul Carissimo: Ive been trying to convert indicator logic to a function but it seems not to work and I get repainting issues. Please see the code attached and let me know where I've gone wrong because this doesnt make sense to me.
  1. Don't try to do that. There are no buffers, no IndicatorCounted() or prev_calculated. No way to know if older bars have changed or been added (history update.)

    Just get the value(s) of the indicator(s) into EA/indicator (using iCustom) and do what you want with it.

  2. You don't resize your arrays when a new bar forms.
  3. You are recomputing all bars every tick.
 
William Roeder:
  1. Don't try to do that. There are no buffers, no IndicatorCounted() or prev_calculated. No way to know if older bars have changed or been added (history update.)

    Just get the value(s) of the indicator(s) into EA/indicator (using iCustom) and do what you want with it.

  2. You don't resize your arrays when a new bar forms.
  3. You are recomputing all bars every tick.

Thank you for your response William, however I find your responses(on other posts in the forum as well) rather cryptic,  elucidating your points with more detail would really help.


1. I'm working under the assumption that OnCalculate() deals with bars being changed or added, for example if I pasted this code in OnCalculate();

      DnBuffer1[i]   = EMPTY_VALUE;
      UpBuffer1[i]   = EMPTY_VALUE;
      trend[i] = EMPTY_VALUE;
      smin[i] = EMPTY_VALUE;
      smax[i] = EMPTY_VALUE;
      smin[i] = -100000;
      smax[i] = 100000;
      for (int ii = period - 1; ii >= 0; ii--)
      {
         double mp = ( _high[i + ii] + _low[i + ii]) / 2;
         smin[i] = MathMax( smin[i], mp - multiplier * iATR(NULL, 0, period, i + ii));
         smax[i] = MathMin( smax[i], mp + multiplier * iATR(NULL, 0, period, i + ii));
      }

      trend[i] = trend[i + 1];
      double midian_price = ( _high[i] + _low[i]) / 2;
      if ( midian_price > smax[i + 1] ) trend[i] =  1;
      if ( midian_price < smin[i + 1] ) trend[i] = -1;

      if ( trend[i] > 0 )
      {
         if( smin[i] < smin[i + 1] ) smin[i] = smin[i + 1];
         UpBuffer1[i] = smin[i];
         DnBuffer1[i] = EMPTY_VALUE;
      }
      if ( trend[i] < 0 )
      {
         if( smax[i] > smax[i + 1] ) smax[i] = smax[i + 1];
         UpBuffer1[i] = EMPTY_VALUE;
         DnBuffer1[i] = smax[i];
      }


it would work without a hitch, so my understanding is that if I encapsulate this code in a function and only pass the current bar  "i"  obtained from this loop ;

 int limit = MathMax(available_bars - 5  - prev_calculated, 5);
   int i = 0;

   for(i =  limit; i >= 0 && !IsStopped(); i--)
   {
   }

It should work normally ? What exactly don't I understand about this whole process ?

iCustom is not a viable option for me especially since I'm getting data from 28 + symbols, I loathe iCustom. 

Aside from iCustom, would expressing the indicator logic as a class work ? I don't know how to use classes, however if it's the only viable option for my use case then I'm willing to invest time to learn more.


2.  Please elaborate, does my code not resize the arrays on new bars OR does my code resize the arrays on new bars ?  In other words should I be resizing the arrays on new bars or not ?

My assumption is to only resize the arrays used by the function when its first called, in this case available bars (rates_total) with this code;

      if(!atr_buffers_resized)
      {
         ArrayResize(smin, bars);
         ArrayResize(smax, bars);
         ArrayResize(UpBuffer1, bars);
         ArrayResize(DnBuffer1, bars);
         ArrayResize(trend, bars);
         ArrayInitialize(smin, EMPTY_VALUE);
         ArrayInitialize(smax, EMPTY_VALUE);
         ArrayInitialize(trend, EMPTY_VALUE);
         ArrayInitialize(UpBuffer1, EMPTY_VALUE);
         ArrayInitialize(DnBuffer1, EMPTY_VALUE);
         atr_buffers_resized = true;
      }


3. How am I recomputing every bars on every tick ? In the function or  OnCalculate() ?

If its in OnCalculate()

   int limit = MathMax(available_bars - 5  - prev_calculated, 5);
 

Doesn't this code only recompute the latest 5 bars ? available_bars = 500; in this case.


If it's in the function, the only bar the function receives is "i".


======================================================

Please elaborate William, you are obviously competent enough to solve such a miniscule issue. Aside from iCustom (which I utterly loathe) what options do I have ?


Why does this code work perfectly;

//+------------------------------------------------------------------+
//|                                               MovingAverages.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
//+------------------------------------------------------------------+
//| Linear Weighted Moving Average                                   |
//+------------------------------------------------------------------+
double LinearWeightedMA(const int position,const int period,const double &price[])
  {
//---
   double result=0.0,sum=0.0;
   int    i,wsum=0;
//--- calculate value
   if(position>=period-1 && period>0)
     {
      for(i=period;i>0;i--)
        {
         wsum+=i;
         sum+=price[position-i+1]*(period-i+1);
        }
      result=sum/wsum;
     }
//---
   return(result);
  }


and mine doesnt ?  I'm essentially trying to do the same thing.


Thank you.

 
Paul Carissimo:

Thank you for your response William, however I find your responses(on other posts in the forum as well) rather cryptic,  elucidating your points with more detail would really help.


1. I'm working under the assumption that OnCalculate() deals with bars being changed or added, for example if I pasted this code in OnCalculate();


it would work without a hitch, so my understanding is that if I encapsulate this code in a function and only pass the current bar  "i"  obtained from this loop ;

It should work normally ? What exactly don't I understand about this whole process ?

iCustom is not a viable option for me especially since I'm getting data from 28 + symbols, I loathe iCustom. 

Aside from iCustom, would expressing the indicator logic as a class work ? I don't know how to use classes, however if it's the only viable option for my use case then I'm willing to invest time to learn more.


2.  Please elaborate, does my code not resize the arrays on new bars OR does my code resize the arrays on new bars ?  In other words should I be resizing the arrays on new bars or not ?

My assumption is to only resize the arrays used by the function when its first called, in this case available bars (rates_total) with this code;


3. How am I recomputing every bars on every tick ? In the function or  OnCalculate() ?

If its in OnCalculate()

Doesn't this code only recompute the latest 5 bars ? available_bars = 500; in this case.


If it's in the function, the only bar the function receives is "i".


======================================================

Please elaborate William, you are obviously competent enough to solve such a miniscule issue. Aside from iCustom (which I utterly loathe) what options do I have ?


Why does this code work perfectly;


and mine doesnt ?  I'm essentially trying to do the same thing.


Thank you.

via mobile web:

if prev_calculated = 0, in the oncalculate first run,you will have an array of 495, and the next prev_calculated is more than 0 on the next call it will repaint for sure..i could be wrong, just a quick glance
 
roshjardine:
via mobile web:

if prev_calculated = 0, in the oncalculate first run,you will have an array of 495, and the next prev_calculated is more than 0 on the next call it will repaint for sure..i could be wrong, just a quick glance

Could you please elaborate with code ?

 
Paul Carissimo:

Could you please elaborate with code ?

can you test this if your expectation is answered? if this does answer, i will upload to codebase so others can use/improve

Files:
 
Sardion Maranatha:

can you test this if your expectation is answered? if this does answer, i will upload to codebase so others can use/improve

Very nice, however that's a whole lot of code; Please see and test the attached, I was thinking more along these lines.

Other than that, this piece of code crashes my system when using a multi currency indicator

int limit =  (prev_calculated < 1) ? rates_total - max_length - 1 : prev_calculated - max_length - 1;

How do you make this calculate only the latest bar ? lookups are something I haven't quite understood yet.

Files:
 
Paul Carissimo:

Very nice, however that's a whole lot of code; Please see and test the attached, I was thinking more along these lines.

Other than that, this piece of code crashes my system when using a multi currency indicator

How do you make this calculate only the latest bar ? lookups are something I haven't quite understood yet.

//--- indicator buffers
double         upBuffer[];
double         dnBuffer[];

 for(int i =  limit; i >= 0 && !IsStopped(); i--)
   {
      AtrStop(ATRperiod, Length, _Symbol, _Period, Kv, i);
      upBuffer[i] = upbfr[i];
      dnBuffer[i] = dnbfr[i];

   }

//atr specific buffers
double upbfr[];
double dnbfr[];


you are duplicating arrray which is not necessary, why? you could just pass it by reference

ArrayResize(upbfr, iBars(symbol, tframe));

every OnCalculate event call, you keep repainting with iBars, why? do you know what iBars returns? and multiply with multiple symbols like what you mentioned on every OnCalculate event call of course it will crash

int limit =  (prev_calculated < 1) ? rates_total - Length - 1 : prev_calculated - Length - 1;


   for(int i =  limit; i >= 0 && !IsStopped(); i--)

you should understand the direction of this loop vs what direction you should take on next call. and how they relate to the iATR calculation

How do you make this calculate only the latest bar ? lookups are something I haven't quite understood yet.

it's already given but you keep on insisting your assumption/thinking is correct, you just need to understand the logic and do what you want with it. If you need someone to explain it to you in non-developer/layman language, there's freelance service in freelance section who will be happy to explain to you (i'm not doing freelance)

 
Sardion Maranatha:


you are duplicating arrray which is not necessary, why? you could just pass it by reference

every OnCalculate event call, you keep repainting with iBars, why? do you know what iBars returns? and multiply with multiple symbols like what you mentioned on every OnCalculate event call of course it will crash

you should understand the direction of this loop vs what direction you should take on next call. and how they relate to the iATR calculation

it's already given but you keep on insisting your assumption/thinking is correct, you just need to understand the logic and do what you want with it. If you need someone to explain it to you in non-developer/layman language, there's freelance service in freelance section who will be happy to explain to you (i'm not doing freelance)

it's already given but you keep on insisting your assumption/thinking is correct, you just need to understand the logic and do what you want with it.

I'm not insisting on anything, understanding is precisely what I seek. Please forgive my difficulty in understanding.

you are duplicating arrray which is not necessary, why? you could just pass it by reference

I'm simply trying to make the function "portable/self-contained" without needing to re-declare buffers when writing new indicators/experts. Does this make sense ?

you should understand the direction of this loop vs what direction you should take on next call. and how they relate to the iATR calculation

If you can please break it down for me, I'm not interested in being spoon fed, I want to understand the framework/logic so I can build on it.

I've read and reread Williams post on how to  do lookbacks correctly however it seems beyond me to understand.


In anycase, thanks for your help thus far, I'll keep your code as reference.

 
Paul Carissimo:

I'm not insisting on anything, understanding is precisely what I seek. Please forgive my difficulty in understanding.

I'm simply trying to make the function "portable/self-contained" without needing to re-declare buffers when writing new indicators/experts. Does this make sense ?

If you can please break it down for me, I'm not interested in being spoon fed, I want to understand the framework/logic so I can build on it.

I've read and reread Williams post on how to  do lookbacks correctly however it seems beyond me to understand.


In anycase, thanks for your help thus far, I'll keep your code as reference.

i have explained it via message
Reason: