Need some collaboration and verification of this Ichimoku project

 
Hi. I am currently converting an indicator into a multipairs indicator, using the same technique I used on the Keltner Channel indicator.
This indicator I am converting to multicurrency is the Ichimoku Kinko Hyo indicator. 

I think I am finished, I just want some folks to verify this on their demo MT4:

//+------------------------------------------------------------------+
//|                                                     Ichimoku.mq4 |
//|                   Copyright 2005-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Ichimoku Kinko Hyo"
#property strict
#include <BreakPoint.mqh>
#include <multipairsfunctions.mqh>

#property indicator_chart_window
#property indicator_buffers 7
#property indicator_color1 Red          // Tenkan-sen
#property indicator_color2 Blue         // Kijun-sen
#property indicator_color3 SandyBrown   // Up Kumo
#property indicator_color4 Thistle      // Down Kumo
#property indicator_color5 Lime         // Chikou Span
#property indicator_color6 SandyBrown   // Up Kumo bounding line
#property indicator_color7 Thistle      // Down Kumo bounding line
//--- input parameters
input string               aSymbol = NULL;
input ENUM_TIMEFRAMES      ChartTimeframe=0;
input int InpTenkan=9;   // Tenkan-sen
input int InpKijun=26;   // Kijun-sen
input int InpSenkou=52;  // Senkou Span B
extern double ResultThick=0;   
//--- buffers
double ExtTenkanBuffer[];
double ExtKijunBuffer[];
double ExtSpanA_Buffer[];
double ExtSpanB_Buffer[];
double ExtChikouBuffer[];
double ExtSpanA2_Buffer[];
double ExtSpanB2_Buffer[];
//---
int    ExtBegin;
string indicatorfilename;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit(void)
  {
   IndicatorDigits(Digits);
//---
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtTenkanBuffer);
   SetIndexDrawBegin(0,InpTenkan-1);
   SetIndexLabel(0,"Tenkan Sen");
//---
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,ExtKijunBuffer);
   SetIndexDrawBegin(1,InpKijun-1);
   SetIndexLabel(1,"Kijun Sen");
//---
   ExtBegin=InpKijun;
   if(ExtBegin<InpTenkan)
      ExtBegin=InpTenkan;
//---
   SetIndexStyle(2,DRAW_HISTOGRAM,STYLE_DOT);
   SetIndexBuffer(2,ExtSpanA_Buffer);
   SetIndexDrawBegin(2,InpKijun+ExtBegin-1);
   SetIndexShift(2,InpKijun);
   SetIndexLabel(2,NULL);
   SetIndexStyle(5,DRAW_LINE,STYLE_DOT);
   SetIndexBuffer(5,ExtSpanA2_Buffer);
   SetIndexDrawBegin(5,InpKijun+ExtBegin-1);
   SetIndexShift(5,InpKijun);
   SetIndexLabel(5,"Senkou Span A");
//---
   SetIndexStyle(3,DRAW_HISTOGRAM,STYLE_DOT);
   SetIndexBuffer(3,ExtSpanB_Buffer);
   SetIndexDrawBegin(3,InpKijun+InpSenkou-1);
   SetIndexShift(3,InpKijun);
   SetIndexLabel(3,NULL);
   SetIndexStyle(6,DRAW_LINE,STYLE_DOT);
   SetIndexBuffer(6,ExtSpanB2_Buffer);
   SetIndexDrawBegin(6,InpKijun+InpSenkou-1);
   SetIndexShift(6,InpKijun);
   SetIndexLabel(6,"Senkou Span B");
//---
   SetIndexStyle(4,DRAW_LINE);
   SetIndexBuffer(4,ExtChikouBuffer);
   SetIndexShift(4,-InpKijun);
   SetIndexLabel(4,"Chikou Span");
   indicatorfilename = __FILE__;  
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Ichimoku Kinko Hyo                                               |
//+------------------------------------------------------------------+
/*int OnCalculate(
                const int count_total,
                const int prev_count_total,
                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 start()              
  {
  //Print("","","",true,"InpTenkan",IntegerToString(InpTenkan),"InpKijun",IntegerToString(InpKijun),"InpSenkou",IntegerToString(InpSenkou),"ResultThick",DoubleToStr(ResultThick));
  //BreakPoint("","","",true,"InpTenkan",IntegerToString(InpTenkan),"InpKijun",IntegerToString(InpKijun),"InpSenkou",IntegerToString(InpSenkou),"ResultThick",DoubleToStr(ResultThick));
   int count_total=0,prev_count_total=0;
   int    i=0,k=0,pos=0,min=0,limit=2;
   double high_value,low_value;
//---
 count_total = iBars(aSymbol,ChartTimeframe);// uncounted
 prev_count_total = IndicatorCounted2(aSymbol,indicatorfilename); // Number of counted bars
 
   if(count_total<=InpTenkan || count_total<=InpKijun || count_total<=InpSenkou)
      return(0);
//--- counting from 0 to count_total
   ArraySetAsSeries(ExtTenkanBuffer,false);
   ArraySetAsSeries(ExtKijunBuffer,false);
   ArraySetAsSeries(ExtSpanA_Buffer,false);
   ArraySetAsSeries(ExtSpanB_Buffer,false);
   ArraySetAsSeries(ExtChikouBuffer,false);
   ArraySetAsSeries(ExtSpanA2_Buffer,false);
   ArraySetAsSeries(ExtSpanB2_Buffer,false);
   /*
   ArraySetAsSeries(open,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(close,false);
   */
//--- initial zero
   if(prev_count_total<1)
     {
      for(i=0; i<InpTenkan; i++)
         ExtTenkanBuffer[i]=0.0;
      for(i=0; i<InpKijun; i++)
         ExtKijunBuffer[i]=0.0;
      for(i=0; i<ExtBegin; i++)
        {
         ExtSpanA_Buffer[i]=0.0;
         ExtSpanA2_Buffer[i]=0.0;
        }
      for(i=0; i<InpSenkou; i++)
        {
         ExtSpanB_Buffer[i]=0.0;
         ExtSpanB2_Buffer[i]=0.0;
        }
     }
//--- Tenkan Sen
   pos=InpTenkan-1;
   if(prev_count_total>InpTenkan)
      pos=prev_count_total-1-limit;
   i = count_total;   
     while( (i>pos) )//for(i=pos; i<count_total; i++)//count down
     {
      i--;
      high_value=iHigh(aSymbol,ChartTimeframe,i);//high[i];
      low_value=iLow(aSymbol,ChartTimeframe,i);//low[i];
      Comment("prev_count_total="+DoubleToStr(prev_count_total),"  count_total=",DoubleToStr(count_total));
      //k=i+1-InpTenkan;
      k=i;
      min=(i+1-InpTenkan);
      while( k>min )//(k<=i)
        {
         if(high_value<iHigh(aSymbol,ChartTimeframe,k))//high[k];
            high_value=iHigh(aSymbol,ChartTimeframe,k);//high[k];
         if(low_value>iLow(aSymbol,ChartTimeframe,k))
            low_value=iLow(aSymbol,ChartTimeframe,k);
         k--;
        }
      //Print("","","",true,"i",IntegerToString(i),"prev_count_total",IntegerToString(prev_count_total),"count_total",IntegerToString(count_total));  
      ExtTenkanBuffer[i]=(high_value+low_value)/2;
     }
//--- Kijun Sen
   pos=InpKijun-1;
      if(prev_count_total>InpKijun)
      pos=prev_count_total-1-limit;
   i = count_total;   
      while( (i>pos) )//for(i=pos; i<count_total; i++)//count down
      {
       i--;
       high_value=iHigh(aSymbol,ChartTimeframe,i);
       low_value=iLow(aSymbol,ChartTimeframe,i);
       //k=i+1-InpKijun;
       k=i;
       min=(i+1-InpKijun);
          while( k>min )//(k<=i)
          {
              if(high_value<iHigh(aSymbol,ChartTimeframe,k))
               high_value=iHigh(aSymbol,ChartTimeframe,k);
              if(low_value>iLow(aSymbol,ChartTimeframe,k))
               low_value=iLow(aSymbol,ChartTimeframe,k);
           k--;
          }
        ExtKijunBuffer[i]=(high_value+low_value)/2;
       }
//--- Senkou Span A
   pos=ExtBegin-1;
      if(prev_count_total>ExtBegin)
       pos=prev_count_total-1-limit;
   i=count_total; 
      while( (i>pos) )//for(i=pos; i<count_total; i++)//count down
      {
       i--;
       ExtSpanA_Buffer[i]=(ExtKijunBuffer[i]+ExtTenkanBuffer[i])/2;
       ExtSpanA2_Buffer[i]=ExtSpanA_Buffer[i];
      }
//--- Senkou Span B
   pos=InpSenkou-1;
      if(prev_count_total>InpSenkou)
       pos=prev_count_total-1-limit;
   i=count_total;   
      while( (i>pos) )//for(i=pos; i<count_total; i++)//count down
      {
       i--;
       high_value=iHigh(aSymbol,ChartTimeframe,i);
       low_value=iLow(aSymbol,ChartTimeframe,i);
       k=i;
       min = i+1-InpSenkou;
          while( k>min )//(k<=i)
          {
              if(high_value<iHigh(aSymbol,ChartTimeframe,k))
               high_value=iHigh(aSymbol,ChartTimeframe,k);
              if(low_value>iLow(aSymbol,ChartTimeframe,k))
               low_value=iLow(aSymbol,ChartTimeframe,k);
           k--;
          }
      ExtSpanB_Buffer[i]=(high_value+low_value)/2;
      ExtSpanB2_Buffer[i]=ExtSpanB_Buffer[i];
     }
//--- Chikou Span
   pos=0;
   if(prev_count_total>1)
      pos=prev_count_total-1-limit;
      i=count_total;
    while( (i>pos) )//for(i=pos; i<count_total; i++)//count down
    { 
     i--;
      ExtChikouBuffer[i]=iClose(aSymbol,ChartTimeframe,i);
    }  
  updateIndicatorCounted2( aSymbol,indicatorfilename,(count_total-1) );
   return(count_total);
  }
//+------------------------------------------------------------------+



This is what it looks like:

Ichimoku In Strategy Tester


As you can see; testing this in the Strategy Tester will show some deformities because functions like iHigh(),iLow()...etc cant get the requested data. If you have a better approach, please show it via code.

MQL4: automated forex trading, strategy tester and custom indicators with MetaTrader
MQL4: automated forex trading, strategy tester and custom indicators with MetaTrader
  • www.mql4.com
MQL4: automated forex trading, strategy tester and custom indicators with MetaTrader
Files:
BreakPoint.mqh  10 kb
 

This is version 2:

//+------------------------------------------------------------------+
//|                                                     Ichimoku2.mq4 |
//|               Copyright 2005-2014, ??MetaQuotes Software Corp??. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
#property description "Ichimoku Kinko Hyo version 2"
#property strict
#include <BreakPoint.mqh>
#include <multipairsfunctions.mqh>

#property indicator_chart_window
#property indicator_buffers 7
#property indicator_color1 Red          // Tenkan-sen
#property indicator_color2 Blue         // Kijun-sen
#property indicator_color3 SandyBrown   // Up Kumo
#property indicator_color4 Thistle      // Down Kumo
#property indicator_color5 clrViolet//Lime         // Chikou Span
#property indicator_color6 SandyBrown   // Up Kumo bounding line
#property indicator_color7 Thistle      // Down Kumo bounding line
//--- input parameters
input string               aSymbol = NULL;
input ENUM_TIMEFRAMES      ChartTimeframe=0;
int InpTenkan=9;   // Tenkan-sen
int InpKijun=26;   // Kijun-sen
int InpSenkou=52;  // Senkou Span B
input int KumoDepthPeriod=30;//the number of bars to use to calculate kumo implied volatility
extern double Result_Tenkan=0;
extern double Result_Kijun=0;
extern double Result_Chikou=0;
extern double Result_SpanA=0;
extern double Result_SpanB=0;
extern double ResultKumoThickness=0; 
extern int ResultShift=0;//0 means the most recent indicator values. 1 means the previous indicator values to the recent.

int KumoIV=0,Shift=1,ExtBegin;  
//--- buffers
double ExtTenkanBuffer[];
double ExtKijunBuffer[];
double ExtSpanA_Buffer[];
double ExtSpanB_Buffer[];
double ExtChikouBuffer[];
double ExtSpanA2_Buffer[];
double ExtSpanB2_Buffer[];
double Current_SpanA=0,Current_SpanB=0;
string indicatorfilename;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit(void)
  {
   IndicatorDigits(Digits);
//---
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtTenkanBuffer);
   SetIndexDrawBegin(0,InpTenkan-1);
   SetIndexLabel(0,"Tenkan Sen");
//---
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,ExtKijunBuffer);
   SetIndexDrawBegin(1,InpKijun-1);
   SetIndexLabel(1,"Kijun Sen");
//---
   ExtBegin=InpKijun;
   if(ExtBegin<InpTenkan)
      ExtBegin=InpTenkan;
//---
   SetIndexStyle(2,DRAW_HISTOGRAM,STYLE_DOT);
   SetIndexBuffer(2,ExtSpanA_Buffer);
   SetIndexDrawBegin(2,InpKijun+ExtBegin-1);
   SetIndexShift(2,InpKijun);
   SetIndexLabel(2,NULL);
   SetIndexStyle(5,DRAW_LINE,STYLE_DOT);
   SetIndexBuffer(5,ExtSpanA2_Buffer);
   SetIndexDrawBegin(5,InpKijun+ExtBegin-1);
   SetIndexShift(5,InpKijun);
   SetIndexLabel(5,"Senkou Span A");
//---
   SetIndexStyle(3,DRAW_HISTOGRAM,STYLE_DOT);
   SetIndexBuffer(3,ExtSpanB_Buffer);
   SetIndexDrawBegin(3,InpKijun+InpSenkou-1);
   SetIndexShift(3,InpKijun);
   SetIndexLabel(3,NULL);
   SetIndexStyle(6,DRAW_LINE,STYLE_DOT);
   SetIndexBuffer(6,ExtSpanB2_Buffer);
   SetIndexDrawBegin(6,InpKijun+InpSenkou-1);
   SetIndexShift(6,InpKijun);
   SetIndexLabel(6,"Senkou Span B");
//---
   SetIndexStyle(4,DRAW_LINE);
   SetIndexBuffer(4,ExtChikouBuffer);
   SetIndexShift(4,-InpKijun);
   SetIndexLabel(4,"Chikou Span");
   indicatorfilename = __FILE__;  
//--- initialization done
  }
//+------------------------------------------------------------------+
//| Ichimoku Kinko Hyo                                               |
//+------------------------------------------------------------------+

  int start()              
  {
   bool fnd=false;
   ENUM_TIMEFRAMES charttimeframe=-1;
   int sz=0,i=0,countedbars=0;
   string symbol,iname; 
   datetime lastbartime=0,currentbartime=0; 
  
   int count_total=0,prev_count_total=0;
   int    k=0,pos=0,min=0,tenkan_buffer_sz=0,kijun_buffer_sz=0,chikou_buffer_sz=0,span_a_buffer_sz=0,span_b_buffer_sz=0;
   int tenkan_shift=ResultShift,kijun_shift=ResultShift,chikou_shift=ResultShift;//the shift of the wanted value. 0 is latest value.
   int span_a_shift=ResultShift;//1;//the shift candlestick inline with the wanted span a value.   
   int span_b_shift=ResultShift;//1;//the shift candlestick inline with the wanted span b value.   
   double highs[],lows[],closes[];
   double high_value,low_value;
//---
 count_total = iBars(aSymbol,ChartTimeframe);// available bars
 prev_count_total = IndicatorCounted2(aSymbol,ChartTimeframe,indicatorfilename); // Number of counted bars
   if(count_total<=InpTenkan || count_total<=InpKijun || count_total<=InpSenkou)
      return(0);
//--- counting from 0 to count_total
   ArraySetAsSeries(ExtTenkanBuffer,false);
   ArraySetAsSeries(ExtKijunBuffer,false);
   ArraySetAsSeries(ExtSpanA_Buffer,false);
   ArraySetAsSeries(ExtSpanB_Buffer,false);
   ArraySetAsSeries(ExtChikouBuffer,false);
   ArraySetAsSeries(ExtSpanA2_Buffer,false);
   ArraySetAsSeries(ExtSpanB2_Buffer,false);

//--- initial zero
   if(prev_count_total<1)
     {
      for(i=0; i<InpTenkan; i++)
         ExtTenkanBuffer[i]=0.0;
      for(i=0; i<InpKijun; i++)
         ExtKijunBuffer[i]=0.0;
      for(i=0; i<ExtBegin; i++)
        {
         ExtSpanA_Buffer[i]=0.0;
         ExtSpanA2_Buffer[i]=0.0;
        }
      for(i=0; i<InpSenkou; i++)
        {
         ExtSpanB_Buffer[i]=0.0;
         ExtSpanB2_Buffer[i]=0.0;
        }
     }

   //search for indicator name and symbol
   sz=ArrayRange(indicator_counted_bars,0);
   i=sz;
      while(i>0 && fnd==false)
      {
       i--; 
       symbol = indicator_counted_bars[i][0];//symbol   
       iname = indicator_counted_bars[i][1];//indicator's name 
       charttimeframe = (ENUM_TIMEFRAMES)StrToInteger(indicator_counted_bars[i][3]);//chart time frame  
          if(symbol == aSymbol && iname == indicatorfilename && ChartTimeframe==charttimeframe)
          {
           fnd = true;
           countedbars = (int)StringToInteger(indicator_counted_bars[i][2]);
           lastbartime = StrToTime(indicator_counted_bars[i][4]);
          }        
      } 
   currentbartime = iTime(aSymbol,ChartTimeframe,Shift);
      if(currentbartime > lastbartime)//proceed when newbar is made
      {                 
        //transfer data in correct order  
       i = count_total; 
       k = 0;
       ArrayResize(highs,count_total);
       ArrayResize(lows,count_total);
       ArrayResize(closes,count_total);
          while(i>0)
          {
           i--;
           highs[k] = iHigh(aSymbol,ChartTimeframe,i);
           lows[k] = iLow(aSymbol,ChartTimeframe,i);
           closes[k] = iClose(aSymbol,ChartTimeframe,i);
           k++;
          }           
      //--- Tenkan Sen
       pos=InpTenkan-1;
          if(prev_count_total>InpTenkan)
            pos=prev_count_total-1;
          for(i=pos; i<count_total; i++)
          {
           high_value=highs[i];
           low_value=lows[i];
           k=i+1-InpTenkan;
              while(k<=i)
              {
                  if(high_value<highs[k])
                  high_value=highs[k];
                  if(low_value>lows[k])
                  low_value=lows[k];
               k++;
              }
           ExtTenkanBuffer[i]=(high_value+low_value)/2;
          }
      //--- Kijun Sen
       pos=InpKijun-1;
          if(prev_count_total>InpKijun)
            pos=prev_count_total-1;
          for(i=pos; i<count_total; i++)
          {
           high_value=highs[i];
           low_value=lows[i];
           k=i+1-InpKijun;
              while(k<=i)
              {
                  if(high_value<highs[k])
                  high_value=highs[k];
                  if(low_value>lows[k])
                  low_value=lows[k];
               k++;
              }
           ExtKijunBuffer[i]=(high_value+low_value)/2;
          }
      //--- Senkou Span A
       pos=ExtBegin-1;
          if(prev_count_total>ExtBegin)
            pos=prev_count_total-1;
          for(i=pos; i<count_total; i++)
          {
           ExtSpanA_Buffer[i]=(ExtKijunBuffer[i]+ExtTenkanBuffer[i])/2;
           ExtSpanA2_Buffer[i]=ExtSpanA_Buffer[i];
          }
       span_a_buffer_sz = ArrayRange(ExtSpanA_Buffer,0);
          if( span_a_buffer_sz > (span_a_shift+26) )Current_SpanA = ExtSpanA_Buffer[span_a_buffer_sz-26-1-span_a_shift];//this give the SpanA value at a specific candlestick shift.     
      //--- Senkou Span B
       pos=InpSenkou-1;
          if(prev_count_total>InpSenkou)
            pos=prev_count_total-1;
          for(i=pos; i<count_total; i++)
          {
           high_value=highs[i];
           low_value=lows[i];
           k=i+1-InpSenkou;
              while(k<=i)
              {
                  if(high_value<highs[k])
                   high_value=highs[k];
                  if(low_value>lows[k])
                   low_value=lows[k];
               k++;
              }
           ExtSpanB_Buffer[i]=(high_value+low_value)/2;
           ExtSpanB2_Buffer[i]=ExtSpanB_Buffer[i];
          }
       span_b_buffer_sz = ArrayRange(ExtSpanB_Buffer,0);
          if( span_b_buffer_sz > (span_b_shift+26) )Current_SpanB = ExtSpanB_Buffer[span_b_buffer_sz-26-1-span_b_shift];//this give the SpanB value at a specific candlestick shift.        
       KumoIV = GetKumoRelativeSize(aSymbol,ChartTimeframe,lastbartime,indicatorfilename,Current_SpanA,Current_SpanB);
       
       //--- Chikou Span
       pos=0;
          if(prev_count_total>1)
            pos=prev_count_total-1;
          for(i=pos; i<count_total; i++)
            ExtChikouBuffer[i]=closes[i];
       updateIndicatorCounted2( aSymbol,ChartTimeframe,indicatorfilename,(count_total-1) );
      }//end process   

//--- buffers sizes
   tenkan_buffer_sz = ArrayRange(ExtTenkanBuffer,0);
   kijun_buffer_sz = ArrayRange(ExtKijunBuffer,0);
   chikou_buffer_sz = ArrayRange(ExtChikouBuffer,0);
      if(count_total > 52)
      {
          if(tenkan_buffer_sz > tenkan_shift)Result_Tenkan=ExtTenkanBuffer[tenkan_buffer_sz-1-tenkan_shift];//this give the tenkansen value at a specific shift.
          if(kijun_buffer_sz > kijun_shift)Result_Kijun=ExtKijunBuffer[kijun_buffer_sz-1-kijun_shift];//this give the kijunsen value at a specific shift.
          if(chikou_buffer_sz > chikou_shift)Result_Chikou=ExtChikouBuffer[chikou_buffer_sz-1-chikou_shift];//this give the chikou span value at a specific shift.
       Result_SpanA=Current_SpanA;
       Result_SpanB=Current_SpanB;
       ResultKumoThickness=KumoIV; 

       GlobalVariableSet("ichiGlobalTenkan",Result_Tenkan);
       GlobalVariableSet("ichiGlobalKijun",Result_Kijun);
       GlobalVariableSet("ichiGlobalChikou",Result_Chikou);
       GlobalVariableSet("ichiGlobalSpanA",Result_SpanA);
       GlobalVariableSet("ichiGlobalSpanB",Result_SpanB);
       GlobalVariableSet("ichiGlobalKumoThickness",ResultKumoThickness);
      } 
   return(count_total);
  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| GetKumoRelativeSize                                                |
//+------------------------------------------------------------------+
/*
 this will get Implied Volatility via Kumo's relative size. 
 implied volatility is either:
 -1  Thin(oversold).
  0  Normal.
  1  Thick(overbought).
*/
int GetKumoRelativeSize(string theSymbol, ENUM_TIMEFRAMES theChartTimeframe, datetime theLastbarTime, string theIndicatorName, double SpanA, double SpanB)
  {
   ENUM_MA_METHOD MA_MODE = MODE_SMA;//MODE_EMA;//this sets the moving average method to use for calculation of moving average
   double Overbought_threshold = 100;
   double Oversold_threshold = 20;
   
   double data_arr1[];
   double Kumodepth=0,stdv_kumo_depth=0,average_kumo_depth=0,UpperBand=0,LowerBand=0,NormalizedVolatilityIndicator=0;
   datetime lastbartime=theLastbarTime;
   datetime currentbartime=0;
    
   static string all_kumo_depths[][3];//will contain symbols' 200 kumo depth measurements.
   int ksz=ArrayRange(all_kumo_depths,0),si=0,kumo_depth_count=KumoDepthPeriod,elements_count=0,tcnt=0,kumo_description_value=0;
   int sfnd=-1;
   string Kumodepth_str;
   string tmpstr,astr;
   string str_arr[];
   string sep=",";
   ushort u_sep=0;
   
      //check if symbol already exists
       while(si<ksz && sfnd<0)
       {
        astr=all_kumo_depths[si][1];
           if(StringCompare(astr,theSymbol,false)==0)
           {
            sfnd=si;
           }
        si++;
       }
      if(sfnd>=0)kumo_description_value = StrToInteger(all_kumo_depths[sfnd][2]);//continue to use old kumo_description_value until new one is calculated.   
   //get kumo depth for new bar
   Kumodepth = MathAbs(SpanA - SpanB);
   Kumodepth_str=DoubleToString(Kumodepth);               

       //if symbol does not exists in array then increase and add it to array
       if(sfnd<0)
       {
        ArrayResize(all_kumo_depths,ksz+1);
        all_kumo_depths[ksz][0] = Kumodepth_str;
        all_kumo_depths[ksz][1] = theSymbol;         
       }
       else
       {
        tmpstr=all_kumo_depths[sfnd][0];
        //stack its kumo depth numbers
        StackDepthString(tmpstr,(kumo_depth_count+1),Kumodepth_str);//kumo_depthstr is stacked up to kumo_depth_count+1 but only kumo_depth_count will be used in calculations.
        all_kumo_depths[sfnd][0]=tmpstr;
        kumo_description_value = StrToInteger(all_kumo_depths[sfnd][2]); 
       }
    //--- Split the string to substrings
    //--- Get the separator code 
    u_sep=StringGetCharacter(sep,0);   
    elements_count=StringSplit(tmpstr,u_sep,str_arr);
//Comment("elements_count = "+IntegerToString(elements_count));
       //use data collected data only when it is sufficient
       if(elements_count>=kumo_depth_count+1)
       {
        ArrayResize(data_arr1,elements_count);
        tcnt=0;
           while(tcnt<elements_count)
           {
            //convert string array to double array 
            data_arr1[tcnt] = StrToDouble(str_arr[tcnt]);  
            //Print("num"+IntegerToString(tcnt)+": "+str_arr[tcnt]+" spanA "+DoubleToStr(SpanA)+" spanB "+DoubleToStr(SpanB)+" Kumodepth_str "+Kumodepth_str);    
            tcnt++;
           }        
            
        //calculate SMA on value
        average_kumo_depth = iMAOnArray(data_arr1,elements_count,kumo_depth_count,0,MA_MODE,Shift);//current Kumodepth value is not included in this calculation,hence Shift 1 is used.
   
        //calculate standard deviation
        stdv_kumo_depth = iStdDevOnArray(data_arr1,elements_count,kumo_depth_count,0,MA_MODE,Shift);//current Kumodepth value is not included in this calculation,hence Shift 1 is used.   
       
        UpperBand = average_kumo_depth + (2 * stdv_kumo_depth);  
        LowerBand = average_kumo_depth - (2 * stdv_kumo_depth);
           if( (UpperBand - LowerBand)!=0 )NormalizedVolatilityIndicator  = ((Kumodepth - LowerBand) / (UpperBand - LowerBand)) * 100;
           if(NormalizedVolatilityIndicator>=Overbought_threshold)//kumo is fat
           {
            kumo_description_value = 1;
           }
           else if(NormalizedVolatilityIndicator<Overbought_threshold && NormalizedVolatilityIndicator>Oversold_threshold)//kumo is normal
           {
            kumo_description_value = 0;
           }
           else if(NormalizedVolatilityIndicator<=Oversold_threshold)//kumo is thin
           {
            kumo_description_value = -1;
           }  
        all_kumo_depths[sfnd][2]=IntegerToString(kumo_description_value);//store new kumo_description_value in array   
      }     
   return(kumo_description_value);   
  }
//+------------------------------------------------------------------+
//| End of GetKumoRelativeSize                                         |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| StackDepthString                                              |
//+------------------------------------------------------------------+
/*
This pushes new string into a stack of X strings.
*/
void StackDepthString(string &the_stack_of_strings,int stack_size,string string_to_add_to_stack)
  {
   bool res=false;
   int c=1,elements_count=0;

   string sep=",";                // A separator as a character 
   ushort u_sep=0;                  // The code of the separator character 
   string str_arr[];

//split string into array of strings
//--- Get the separator code 
   u_sep=StringGetCharacter(sep,0);
//--- Split the string to substrings 
   elements_count=StringSplit(the_stack_of_strings,u_sep,str_arr);
   if(the_stack_of_strings==NULL || elements_count<1)
     {
      the_stack_of_strings=string_to_add_to_stack;
     }
   else if(elements_count>=1 && elements_count<stack_size)
     {
      the_stack_of_strings=StringConcatenate(the_stack_of_strings,",",string_to_add_to_stack);
     }
   else if(elements_count>=stack_size)
     {
      //re-assemble string
      StringReplace(the_stack_of_strings,str_arr[0]+",",NULL);
      the_stack_of_strings=StringConcatenate(the_stack_of_strings,",",string_to_add_to_stack);
     }
  }
//+------------------------------------------------------------------+
//| End of StackDepthString                                              |
//+------------------------------------------------------------------+





And this is the shell case. It is NOT required, as you can use "iCustom(...)" directly:

//+------------------------------------------------------------------+
//|      This is the wrapper(case) for Ichimoku2.mq4 indicator       |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Powered by the people."
#property link      "https://www.yahoo.com"
#property strict
#property strict
#include <BreakPoint.mqh>

//+------------------------------------------------------------------+
// iIchimoku2                                                             
//+------------------------------------------------------------------+
/*
 This returns the indicator values of the bands(tenkansen,kijunsen...).
 The Ichimoku chart is composed of five (5) separate indicator lines. These lines work together to form the
 complete "Ichimoku picture"..
 ResultKumoThickness(Kumo Implied Volatility): 0 means normal, 1 means fat(thicker than normal), -1 means thinner than normal.
 ichikShift: 0 represents the most recent indicator values or indicator values which is occurring while the newest unformed bar is forming. 1 means the previous indicator values.
*/
void iIchimoku2(string ichiSymbol, ENUM_TIMEFRAMES ichiChartTimeframe, int ichiKumoPeriod, double& Tenkansen_value, double& Kijunsen_value, double& Chikou_value, double& SpanA_value, double& SpanB_value, int& KumoIV_value, int ichikShift)
{ 
 iCustom(ichiSymbol, ichiChartTimeframe, "Ichimoku2", ichiSymbol, ichiChartTimeframe, ichiKumoPeriod, Tenkansen_value, Kijunsen_value, Chikou_value, SpanA_value, SpanB_value, KumoIV_value, ichikShift); // Shift 1 when ichikShift=1
 Tenkansen_value = GlobalVariableGet("ichiGlobalTenkan");
 Kijunsen_value = GlobalVariableGet("ichiGlobalKijun");
 Chikou_value = GlobalVariableGet("ichiGlobalChikou");
 SpanA_value = GlobalVariableGet("ichiGlobalSpanA");   
 SpanB_value = GlobalVariableGet("ichiGlobalSpanB"); 
 KumoIV_value = (int)GlobalVariableGet("ichiGlobalKumoThickness");
 //Comment("KumoIV_value=",IntegerToString(KumoIV_value),"SpanB_value",DoubleToStr(SpanB_value),"SpanA_value",DoubleToStr(SpanA_value),"Chikou_value",DoubleToStr(Chikou_value),"Kijunsen_value",DoubleToStr(Kijunsen_value),"Tenkansen_value",DoubleToStr(Tenkansen_value));  
}
//+------------------------------------------------------------------+
// End of iIchimoku2                                                             
//+------------------------------------------------------------------+


Everything is now reduced to one simplified function call. Usage:

double tenkan,kijun,chikou,spa,spb;//these are created empty but they will contain the request data at the specified shift.
int kiv;
iIchimoku2("",0,3,tenkan,kijun,chikou,spa,spb,kiv,1);//tenkan variable now contains the indicator value at the specified shift which is 1.

The variables such as kijun,chikou... also contain their respective values at the specified shift as well. Remember to put "#include <Ichimoku2_Kinko_Hyo_Indicator.mqh>" at the top of your EA before using this function.


Why?

The original mql4 ichimoku indicator worked correctly and it will continue to do so for most us. I think it was built primarily with the manual trader in mind. However, for my use it was limited; specifically, i needed an indicator that my EA could readily interpret and even more so, it needed to do this simultaneously on different pairs. At the heart of this problem was the use of " High[x]", which works on only the current pair. This was subsequently fixed by including the use of " iHigh()" which works on multiple pairs.

To a greater extent, I can say that version 2 is now multipairs capable and just as accurate as the original. Ofcourse, if someone has a better approach then modify the above so we can test it. Another situation I faced while rebuilding this was that any problem or inefficiency will be amplied when used on multipairs simultaneously. To remedy this, I modified the indicator to only run when it is necessary i.e. run only when a new bar is completed. The original version would run on every tick, which i think would consume uneccessary cpu cycles.

Since, in essence, I am upgrading the mql4 ichimoku then I thought it would be great to add in new capabilities. When one reads ichimoku literature, frequently one will encounter a reference to the Kumo as "fat", "thick" or "slim". To an experienced ichimoku practioner, it is easy to describe a kumo as "fat" or "thin" because she knows what the usual kumo thickness is for a pair. For beginners, like myself, it is very difficult to describe a kumo because we don't know what to objectively compare it to. I think a solution for this problem would be to compare it to the kumo itself over a specific period. This is the approach taken when writing the " GetKumoRelativeSize()" function. Ideally, we want to use a long period of time in the comparison to the current kumo thickness, like say 100 candlesticks. For a manual trader who is trading the daily charts, this is simply keeping your computer running MT4 on over several months. The issue I have is that I like the freedom of turning off the VPS running my EA, at least once a week. If I am trading the daily charts then the " GetKumoRelativeSize()" function will never get enough bars to analyze. At most, the function would receive just 6 bars over the course of a week, if I turn off my VPS once a week. Fortunately for me, while backtesting this indicator, I discovered that I can use as little as 3 bars for the ichiKumoPeriod and still get correct results. Backtest and see if you concur.

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:
Reason: