Just when you think you've gotten the hang of it: Function/Global scope issue

 

Good morning all. Totally though i'd gotten the hang of it then started receiving the following issue...

1. Just for general awareness: I've elected for the current bar to be the value of IndicatorCounted () - and consistently refer to this as "i" - therefore, the oldest bar on the chart is always [0] - right or wrong i found it easier to understand this way
2. I've written two functions (highlighted in pink) which i'm having issues placing within the body of my code; wherever i choose to place text i receive the error message "function can be declared only in the global scope"

//+------------------------------------------------------------------+
//|                                   Heiken Ashi Trend Detector.mq4 |
//|       Copyright © 2016 Carl Carver Software. All Rights Reserved |
//|                                          carl_carver@hotmail.com |
//+------------------------------------------------------------------+

//Indicator Basic Properties
#property copyright "Copyright © 2016 Carl Carver Software. All Rights Reserved."
#property link      "carl_carver@hotmail.com"
#property version   "1.00"
#property description "Heiken Ashi Trend Detector"
#property strict
#property indicator_chart_window
#property indicator_buffers 11

//Indicator Format Properties
//HA Properties
#property indicator_color1 clrBlack
#property indicator_color2 clrRed
#property indicator_color3 clrLimeGreen
#property indicator_width1 1
#property indicator_width2 1
#property indicator_width3 3
#property indicator_width4 3

//Swing Properties
#property indicator_color5 clrBlack
#property indicator_color6 clrBlack
#property indicator_color7 clrBlack
#property indicator_color8 clrBlack
#property indicator_color9 clrBlack
#property indicator_color10 clrBlack
#property indicator_width5 2
#property indicator_width6 2
#property indicator_width7 2
#property indicator_width8 2
#property indicator_width9 2
#property indicator_width10 2 

//User Inputs
//HA Candle Properties                                                      
input color Shadow=clrBlack;
input color Bear_Body = clrRed;
input color Bull_Body = clrLimeGreen;

//Buffer Arrays
//HA Buffers                                               
double HA_High_Buffer[];
double HA_Low_Buffer[];
double HA_Open_Buffer[];
double HA_Close_Buffer[];

//Swing Buffers   
double Swing_1_Buffer[];    //Wingding symbol code: 140 - On-screen symbol: 1
double Swing_2_Buffer[];    //Wingding symbol code: 141 - On-screen symbol: 2
double Swing_LL_Buffer[];   //Wingding symbol code: 142 - On-screen symbol: 3
double Swing_LH_Buffer[];   //Wingding symbol code: 143 - On-screen symbol: 4
double Swing_HL_Buffer[];   //Wingding symbol code: 144 - On-screen symbol: 5
double Swing_HH_Buffer[];   //Wingding symbol code: 145 - On-screen symbol: 6

//Counter Buffer
double Counter_Buffer[];

//Pre-program buffer implementation and mapping
void OnInit(void)
  {
   IndicatorDigits(Digits());

//HA Buffers
   SetIndexBuffer(0,HA_High_Buffer);
   SetIndexStyle(0,DRAW_HISTOGRAM,0,1,Shadow);
   SetIndexDrawBegin(0,0);
   SetIndexLabel(0,"HA High");

   SetIndexBuffer(1,HA_Low_Buffer);
   SetIndexStyle(1,DRAW_HISTOGRAM,0,1,Shadow);
   SetIndexDrawBegin(1,0);
   SetIndexLabel(1,"HA Low");

   SetIndexBuffer(2,HA_Open_Buffer);
   SetIndexStyle(2,DRAW_HISTOGRAM,0,3,Bear_Body);
   SetIndexDrawBegin(2,0);
   SetIndexLabel(2,"HA Open");

   SetIndexBuffer(3,HA_Close_Buffer);
   SetIndexStyle(3,DRAW_HISTOGRAM,0,3,Bull_Body);
   SetIndexDrawBegin(3,0);
   SetIndexLabel(3,"HA Close");

//Swing Buffers   
   SetIndexBuffer(4,Swing_1_Buffer);
   SetIndexStyle(4,DRAW_ARROW);
   SetIndexArrow(4,140);
   SetIndexLabel(4,"Sw. Low");

   SetIndexBuffer(5,Swing_2_Buffer);
   SetIndexStyle(5,DRAW_ARROW);
   SetIndexArrow(5,141);
   SetIndexLabel(5,"Sw. High");

   SetIndexBuffer(6,Swing_LL_Buffer);
   SetIndexStyle(6,DRAW_ARROW);
   SetIndexArrow(6,142);
   SetIndexLabel(6,"Sw. Lower Low");

   SetIndexBuffer(7,Swing_LH_Buffer);
   SetIndexStyle(7,DRAW_ARROW);
   SetIndexArrow(7,143);
   SetIndexLabel(7,"Sw. Lower High");

   SetIndexBuffer(8,Swing_HL_Buffer);
   SetIndexStyle(8,DRAW_ARROW);
   SetIndexArrow(8,144);
   SetIndexLabel(8,"Sw. Higher Low");

   SetIndexBuffer(9,Swing_HH_Buffer);
   SetIndexStyle(9,DRAW_ARROW);
   SetIndexArrow(9,145);
   SetIndexLabel(9,"Sw. Higher High");

//Counter Buffer
   SetIndexBuffer(10,Counter_Buffer,INDICATOR_DATA);
   SetIndexStyle(10,DRAW_LINE,STYLE_SOLID,1,CLR_NONE);
   SetIndexLabel(10,"Bar #");

  }
//Main program
int OnCalculate
(
 //Standard bar price and data arrays
 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[]
 )
  {

//Price Arrays
   ArraySetAsSeries(open,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(close,false);
   ArraySetAsSeries(time,false);

//Heiken Ashi Arrays
   ArraySetAsSeries(HA_High_Buffer,false);
   ArraySetAsSeries(HA_Low_Buffer,false);
   ArraySetAsSeries(HA_Open_Buffer,false);
   ArraySetAsSeries(HA_Close_Buffer,false);

//Swing Arrays
   ArraySetAsSeries(Swing_1_Buffer,false);
   ArraySetAsSeries(Swing_2_Buffer,false);
   ArraySetAsSeries(Swing_LL_Buffer,false);
   ArraySetAsSeries(Swing_LH_Buffer,false);
   ArraySetAsSeries(Swing_HL_Buffer,false);
   ArraySetAsSeries(Swing_HH_Buffer,false);

//Counter Array
   ArraySetAsSeries(Counter_Buffer,false);
    
   int i;
   int Lookback=IndicatorCounted();
   int Counter=0;
   int Last_Swing=0;
   int Swing_Rule=0;
   double HA_Open,HA_High,HA_Low,HA_Close;

//Error Check - Sufficient candles on chart to complete calculations? 
   if(Lookback<1) return(-1);

   for(i=0; i<1; i++)
     {
      if(open[i]<close[i] || open[i]>close[i])
        {
         //Update the counter on each iteration of the loop - in this case once
         Counter=i;
         Counter_Buffer[i]=Counter;
         //Prints as follows
         HA_Low_Buffer[i]=low[i];
         HA_High_Buffer[i]=high[i];
         HA_Open_Buffer[i]=open[i];
         HA_Close_Buffer[i]=close[i];
        }
      //Setting the first swing - If the first candle is red
      if(open[i]<close[i])
        {
         Swing_1_Buffer[i]=HA_Low_Buffer[i];
        }
      //Setting the first swing - If the first candle is green
      else if(open[i]>close[i])
        {
         Swing_2_Buffer[i]=HA_High_Buffer[i];
        }
     }

//Setting the first 3 HA candles - necessary so to avoid an "array out of range" error during the swing calc
   for(i=1; i<4; i++)
     {
      //Update the counter on each iteration of the loop - in this case thrice
      Counter=i;
      Counter_Buffer[i]=Counter;
      //Establish current bar OHLC on each iteration of the loop
      HA_Open=(HA_Open_Buffer[i-1]+HA_Close_Buffer[i-1])/2;
      HA_Close=(open[i]+high[i]+low[i]+close[i])/4;
      HA_High=MathMax(high[i],MathMax(HA_Open,HA_Close));
      HA_Low=MathMin(low[i],MathMin(HA_Open,HA_Close));
      //Prints as follows:
      HA_Low_Buffer[i]=HA_Low;
      HA_High_Buffer[i]=HA_High;
      HA_Open_Buffer[i]=HA_Open;
      HA_Close_Buffer[i]=HA_Close;
     }
//Range/swing detection variables/functions     
   //Custom range function 1
   int RangeStart(int CurrentBarVal)
     {
      return (CurrentBarVal-CurrentBarVal);
     }
     
   //Custom range function 2
   int BarsInRange(int HighVal,int LowVal)
     {
      return (HighVal-LowVal);
     }
   int Range_Start=RangeStart(Counter);    int Bars_In_Range=BarsInRange(Last_Swing,Counter);    int SL_Range = iLowest(NULL, 0, MODE_LOW, Bars_In_Range, Range_Start);    int SH_Range = iHighest(NULL, 0, MODE_HIGH, Bars_In_Range, Range_Start); //Main HA candle and swing detection calculations and loop    for(i=4; i<=Lookback; i++)      {       //Update the counter on each iteration of the loop - in this case on every new candle       Counter=i;       Counter_Buffer[i]=Counter;       //Establish current bar OHLC on each iteration of the loop       HA_Open=(HA_Open_Buffer[i-1]+HA_Close_Buffer[i-1])/2;       HA_Close=(open[i]+high[i]+low[i]+close[i])/4;       HA_High=MathMax(high[i],MathMax(HA_Open,HA_Close));       HA_Low=MathMin(low[i],MathMin(HA_Open,HA_Close));       //Prints as follows:       HA_Low_Buffer[i]=HA_Low;       HA_High_Buffer[i]=HA_High;       HA_Open_Buffer[i]=HA_Open;       HA_Close_Buffer[i]=HA_Close;      }    return(rates_total);   }       

Can anyone suggest where i'm going wrong, please?

Any and all help, as always, is very much appreciated. 

Thanks,
Carl.  

 

These 2 functions need to be moved outside OnCalculate(). You can't declare a function inside an other function.

//Main program
int OnCalculate(...)
  {
   ...
  }
//Custom range function 1
int RangeStart(int CurrentBarVal)
  {
   return (CurrentBarVal-CurrentBarVal);
  }
//Custom range function 2
int BarsInRange(int HighVal,int LowVal)
  {
   return (HighVal-LowVal);
  }
 

Alain, you're a wonderful, wonderful man. That simple fact had sailed straight past me. Thank you very much. :)

Carl.  

 

Just as a suggestion - try not to mix the use of the parameter arrays (open[], high[], etc.)  with the old style Chart data arrays (Open[], High[], etc.).

Instead of the iHighest() and iLowest() which works on the Chart Data arrays, rather use ArrayMaximum() and ArrayMinimum() on the high[] and low[] arrays which are the parameters of the function.

This will surely prevent any future inconsistencies (as there may be differences between the data sources) and make your OnCalculate() portable.

 

Fernando, i was yet to make the distinction between the two and this was what was causing me to go this route - creating the functions - in the first place. Thanks for taking the time to point this out. Hopefully things should be somewhat more straightforward. :)

Carl.

 
Quick question: am i right in thinking that iLowest/Highest has the benefit, over ArrayMaximum/Minimum, of being able to pull data from other timeframes? I'm working towards making this a multi-timeframe EA. 
 
The_Rezzer:
Quick question: am i right in thinking that iLowest/Highest has the benefit, over ArrayMaximum/Minimum, of being able to pull data from other timeframes? I'm working towards making this a multi-timeframe EA. 
You can do the similar things with both, but ArrayMaximum/Minimum are more generic, as they are working with any arrays. So if you provide them an array of data from any timeframe, it will work.
 
Ok. It's just clicked. Fernando, your advice makes sense as per the way i count bars/index positions. What i'll plan to do is create the EA which will utilise an iCustom function call to the indicator i'm creating - as ArrayMax/Min will be a inherent part of the indicator i don't need to use iLowest/Highest. This works way better for me. Thank you both! :)