How to use an array in the OnInit() ?

 

Hey guys,

 it seemed to be a simple thing but I don't know how to do it:

I wanted to make an indicator which prints arrows above a Pinbar. Pretty easy so far. But I don't want the indicator check the whole chart with every tick. The Pinbars in the past do not change and therefore I wanted to print the arrows in the OnInit(). The OnCalculate() should only check if the last closed bar is a Pinbar. Therefore I put the loop to check all bars in the OnInit(). No error while compiling. But when I drag the indicator into the chart I always receive an "array out of range" error. The error occurs where I want to put data into the (double-)array:

   for(i = 1000; i >= 0; i--) {
      LongPinbar[i+1] = EMPTY;
      ShortPinbar[i+1] = EMPTY;

Can somebody please explain how I can use this array in the OnInit() ?

Thanks!!

 

Consider creating 2 buffers (LongPinbar and ShortPinbar) to store the high/low for valid pinbars. 

These buffers will be filled in OnCalculate, not in OnInit. 

Compare rates_total and prev_calculated from within OnCalculate to avoid reprocessing old bars.

You can further restrict OnCalculate to only look once per bar using a static datetime variable and comparison of Time[0]. 

I'd suggest taking a look at the code of some of the simpler standard indicators to get an idea about how to do all that.

 
mar: But when I drag the indicator into the chart I always receive an "array out of range" error. The error occurs where I want to put data into the (double-)array:

Can somebody please explain how I can use this array in the OnInit() ?

How are the arrays defined? Only: double LonPinbar[],ShortPinbar[];?
 
mar: make an indicator ...  Can somebody please explain how I can use this array in the OnInit() ?
  1. Look at the examples. The arrays are not used in init. They are made buffers OnInit() or init()
  2. They are given values in OnCalculate() or start()
  3. EMPTY is -1. It is NOT the same as EMPTY_VALUE
 

Hey guys,

first thanks for you feedback! I understand that it is not possible to fill an array in the init. Like I wrote, my intention was that the code printing the past arrows (which do not change) should only be executed once. Now I found another solution. I use the bool-variable "test" now to check if the code is already executed. Do you agree with that or is there a more "elegant" way? 

#property copyright "Copyright 2014, Marcus Riemenschneider"
#property link      "http://www.facebook.com/marcus.riemenschneider"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Lime
#property indicator_color2 Red
double LongSignal[], ShortSignal[];
int i;
bool test = true;

//--- Functions

double Candle (int shift)  { return(High[shift] - Low[shift]); }
double BodyHi (int shift)  { return(MathMax(Open[shift], Close[shift])); }
double BodyLo (int shift)  { return(MathMin(Open[shift], Close[shift])); }

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   IndicatorBuffers(2);
   SetIndexBuffer(0, LongSignal); 
   SetIndexStyle(0, DRAW_ARROW, EMPTY,1);
   SetIndexArrow(0, 233);
   SetIndexBuffer(1, ShortSignal);
   SetIndexStyle(1, DRAW_ARROW, EMPTY,1);
   SetIndexArrow(1, 234);
   
//---
   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 (!test) return(0);
  
//--- space between the candles and the arrows
  
   double dy = 0;
   for (i = 1; i <= 10; i++) dy += (High[i] - Low[i]);
   dy /= 10;
   
//---
  
   int counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   int limit=MathMin(Bars-counted_bars,Bars-10);
   
//--- main loop
   
   for(i=limit; i>=0; i--) {                  
      if (BodyLo(i+1) - Low[i+1] >= 0.66*Candle(i+1))
         LongSignal[i+1] = Low[i+1] - 0.3*dy;
      else if (High[i+1] - BodyHi(i+1) >= 0.66*Candle(i+1))
         ShortSignal[i+1] = High[i+1] + 0.3*dy;
   }
   Alert("Arrows printed");
   test = false;
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 

This should only check the previous bar after the first run.

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, Marcus Riemenschneider"
#property link      "http://www.facebook.com/marcus.riemenschneider"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 Lime
#property indicator_color2 Red
double LongSignal[],ShortSignal[];

//--- Functions

double Candle (int shift)  { return(High[shift] - Low[shift]); }
double BodyHi (int shift)  { return(MathMax(Open[shift], Close[shift])); }
double BodyLo (int shift)  { return(MathMin(Open[shift], Close[shift])); }

bool   NewBar (datetime time)
  {
   static datetime prev_time;
   if(prev_time!=time)
     {
      prev_time=time;
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

   IndicatorBuffers(2);
   SetIndexBuffer(0,LongSignal);
   SetIndexStyle(0,DRAW_ARROW,EMPTY,1);
   SetIndexArrow(0,233);
   SetIndexBuffer(1,ShortSignal);
   SetIndexStyle(1,DRAW_ARROW,EMPTY,1);
   SetIndexArrow(1,234);

//---
   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<=10)
      return(0);

   int i,j,limit;

//---
   if(prev_calculated==0)
      limit=rates_total-10;
   else
      limit=rates_total-prev_calculated;
//--- main loop
   if(prev_calculated==0 || NewBar(time[0]))
     {
      for(i=limit; i>=0; i--)
        {
         if(BodyLo(i+1)-Low[i+1]>=0.66*Candle(i+1))
           {
            //--- space between the candles and the arrows
            double dy=0;
            for(j=i+1; j<=i+10; j++)
               dy+=(Candle(j));
            dy/=10;
            LongSignal[i+1]=Low[i+1]-0.3*dy;
            if(prev_calculated>0) Alert("Buy!");
           }
         else if(High[i+1]-BodyHi(i+1)>=0.66*Candle(i+1))
           {
            //--- space between the candles and the arrows
            double dy=0;
            for(j=i+1; j<=i+10; j++)
               dy+=(Candle(j));
            dy/=10;
            ShortSignal[i+1]=High[i+1]+0.3*dy;
            if(prev_calculated>0) Alert("Sell!");
           }
        }
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 

Hey pipPod,

thank you for that code-example! I never used rates_total or prev_calculated. To be honest I had no idea what it means before honest_knave and you told me about these pre defined variables. 

 
mar:

Hey pipPod,

thank you for that code-example! I never used rates_total or prev_calculated. To be honest I had no idea what it means before honest_knave and you told me about these pre defined variables. 

It's more advantageous to use prev_calculated rather than IndicatorCounted() as it interacts with OnCalculate() and resets to zero when history changed.
 

I understand, thank you! Then I will modify my old indicators and remove IndicatorCounted().

One last question: what does the &-sign before the const time[], open[], high[] ...in the OnCalculate() mean? I see that these are arrays and no normal int-variables like rates_total and prev_calculated. But why is there a & ?

 
mar:

I understand, thank you! Then I will modify my old indicators and remove IndicatorCounted().

One last question: what does the &-sign before the const time[], open[], high[] ...in the OnCalculate() mean? I see that these are arrays and no normal int-variables like rates_total and prev_calculated. But why is there a & ?

I would also like a definitive answer to this.

As I understand it, the arrays are not loaded at every tick but are passed by reference. So I don't know whether it is actually quicker to access open[i] or Open[i]

 
mar:

I understand, thank you! Then I will modify my old indicators and remove IndicatorCounted().

One last question: what does the &-sign before the const time[], open[], high[] ...in the OnCalculate() mean? I see that these are arrays and no normal int-variables like rates_total and prev_calculated. But why is there a & ?

It means the array element is referenced by position number rather than value, so it should be accessed faster.