How to code an alternative to IndicatorCounted()?

 

Hi. I am converting a single currency indicator to a multipairs indicator and I would like to know the correct way to proceed. The indicator I am working on is a keltner channel, which works ok on the current symbol, however, I don't fully understand how to use IndicatorCounted() on a external pair(a pair that's not the current). Below, you will find the context in which I am using IndicatorCounted() and hopefully that will show you what I would like to accomplish.

//+------------------------------------------------------------------+
//|                                               KeltnerChannel.mq4 |
//|                                                  Coded by Gilani |
//|                      Copyright © 2019, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net"
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
#include <BreakPoint.mqh>

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 White
#property indicator_color2 White
#property indicator_color3 White


double upper[], middle[], lower[];
extern string               aSymbol = "";
extern int                  MA_PERIOD = 20;
extern ENUM_MA_METHOD       MA_METHOD = MODE_SMA;
extern ENUM_APPLIED_PRICE   PRICE_MODE = PRICE_CLOSE; //Price type
extern int                  ATR_PERIOD = 20;
extern double               MA_DISTANCE = 1.5; // Coefficient of distance from mean
extern bool                 ATR_MODE = true; //Use ATR instead of Sum(High-Low)
extern ENUM_TIMEFRAMES      ChartTimeframe=0;
void OnInit(void)
  {
   SetIndexStyle(0,DRAW_LINE);
   SetIndexShift(0,0);
   SetIndexDrawBegin(0,0);
   SetIndexBuffer(0,upper);

   SetIndexStyle(1,DRAW_LINE,STYLE_DOT);
   SetIndexShift(1,0);
   SetIndexDrawBegin(1,0);
   SetIndexBuffer(1,middle);

   SetIndexStyle(2,DRAW_LINE);
   SetIndexShift(2,0);
   SetIndexDrawBegin(2,0);
   SetIndexBuffer(2,lower);   
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
 int timediff=0,xseconds=1;
 static datetime lasttime=0;
 datetime currenttime=0;
 
 currenttime = TimeLocal();
 timediff = (int)(currenttime - lasttime);  
     
      //control the number of processing calls
      if(timediff>=xseconds)
      {      
       //processing
       int limit=0,x=0;
       double avg=0,tmp=0;   
       int counted_bars=0;//IndicatorCounted();    
          if(counted_bars<0) return(-1);
          if(counted_bars>0) counted_bars--;
          limit=iBars(aSymbol,ChartTimeframe)-counted_bars;
          
          while(x<limit && limit>0) //for(int x=0; x<limit; x++) 
          {     
           middle[x] = iMA(aSymbol, ChartTimeframe, MA_PERIOD, 0, MA_METHOD, PRICE_MODE, x);
              if (ATR_MODE)
              avg  = iATR(aSymbol,0,ATR_PERIOD, x);
              else 
              avg  = findAvg(ATR_PERIOD, x);           
           upper[x] = middle[x] + MA_DISTANCE*avg;
           lower[x] = middle[x] - MA_DISTANCE*avg;
           
           x++;
          } 
       tmp=middle[0];   
       BreakPoint("","","",true,"iMA",DoubleToStr(tmp),"currenttime",TimeToString(currenttime),"lasttime",TimeToString(lasttime),"timediff",IntegerToString(timediff));   
       counted_bars = iBars(aSymbol,ChartTimeframe);   
       lasttime = currenttime; 
       Print("timediff = "+IntegerToString(timediff)+" seconds");   
      }     
   return(0);
  }
//+------------------------------------------------------------------+

   double findAvg(int period, int shift) {
      double sum=0;
      for (int x=shift;x<(shift+period);x++) {     
         //sum += High[x]-Low[x];
         sum += iHigh(aSymbol,ChartTimeframe,x) - iLow(aSymbol,ChartTimeframe,x);
      }
         if(period>0)sum = sum/period;
      return (sum);
   }

The code also shows my attempt at reducing cpu usage by limiting the amount of calls to calculate the bands to once per second, using local time. The BreakPoint() is NOT part of the indicator but I left it in just incase you might want to see the values that are coming out of the indicator. They can be commented out.

Files:
BreakPoint.mqh  10 kb
 

I think I got something. It's a bit clunky but it gets the job done:


//+------------------------------------------------------------------+
//|                                               KeltnerChannel.mq4 |
//|                                                  Coded by Gilani |
//|                      Copyright © 2019, MetaQuotes Software Corp. |
//|                                        http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net"
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
#include <BreakPoint.mqh>
#include <multipairsfunctions.mqh>

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 White
#property indicator_color2 White
#property indicator_color3 White

double upper[], middle[], lower[];
extern string               aSymbol = "";
extern int                  MA_PERIOD = 20;
extern ENUM_MA_METHOD       MA_METHOD = MODE_SMA;//MA type. should be MODE_EMA
extern ENUM_APPLIED_PRICE   PRICE_MODE = PRICE_CLOSE; //Price type
extern int                  ATR_PERIOD = 20;//10 
extern double               MA_DISTANCE = 1.5; // Coefficient of distance from mean
extern bool                 ATR_MODE = true; //Use ATR instead of Sum(High-Low)
extern ENUM_TIMEFRAMES      ChartTimeframe=0;

string indicatorfilename;
void OnInit(void)
  {
   SetIndexStyle(0,DRAW_LINE);
   SetIndexShift(0,0);
   SetIndexDrawBegin(0,0);
   SetIndexBuffer(0,upper);

   SetIndexStyle(1,DRAW_LINE,STYLE_DOT);
   SetIndexShift(1,0);
   SetIndexDrawBegin(1,0);
   SetIndexBuffer(1,middle);

   SetIndexStyle(2,DRAW_LINE);
   SetIndexShift(2,0);
   SetIndexDrawBegin(2,0);
   SetIndexBuffer(2,lower);   
   indicatorfilename = __FILE__;  
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{     
 //processing
 int x=0,cnt=0;
 double avg=0;   
 int counted_bars=0;
//BreakPoint("","","",true,"aSymbol",aSymbol,"ChartTimeframe",IntegerToString(ChartTimeframe),"MA_PERIOD",IntegerToString(MA_PERIOD),"MA_METHOD",IntegerToString(MA_METHOD),"PRICE_MODE",IntegerToString(PRICE_MODE),"ATR_PERIOD",IntegerToString(ATR_PERIOD),"MA_DISTANCE",DoubleToStr(MA_DISTANCE),"ATR_MODE",IntegerToString(ATR_MODE) );    
 counted_bars=IndicatorCounted2(aSymbol,indicatorfilename); // Number of counted bars
 x = iBars(aSymbol,ChartTimeframe) - counted_bars - 1;// Index of the first uncounted
    if( (x+1)>limit )x=limit;
 cnt = x;
    while(x>=0)//Loop for uncounted bars 
    {     
     middle[x] = iMA(aSymbol, ChartTimeframe, MA_PERIOD, 0, MA_METHOD, PRICE_MODE, x);//value of  1 buffer on x bar
        if (ATR_MODE)
        avg  = iATR(aSymbol,0,ATR_PERIOD, x);
        else 
        avg  = findAvg(ATR_PERIOD, x);           
     upper[x] = middle[x] + MA_DISTANCE*avg;//value of  0 buffer on x bar
     lower[x] = middle[x] - MA_DISTANCE*avg;//value of  2 buffer on x bar          
     x--;
    } 
 updateIndicatorCounted2( aSymbol,indicatorfilename,(cnt-1) );//total bars that have been processed. i minus 1 inorder to always force update of shift 1.  
 return(0);
}
//+------------------------------------------------------------------+

   double findAvg(int period, int shift) {
      double sum=0;
      for (int x=shift;x<(shift+period);x++) {     
         //sum += High[x]-Low[x];
         sum += iHigh(aSymbol,ChartTimeframe,x) - iLow(aSymbol,ChartTimeframe,x);
      }
         if(period>0)sum = sum/period;
      return (sum);
   }



And the result:

Keltner


Limitation:

This can be used to trade several currencies simultaneously in one EA, as long as you don't request a keltner value for shift 2 and above. This is because the buffer line will contain previous values from other currency pairs. I know each pair should get its own line but I really don't want this to consume too much cpu and my machine is old. I don't need values above shift 1 so I am ok with this. If you are doing just one currency within the EA then there is no discernible problem.

Files: