iCustom multiple instances on strategy test - casting issue?

 

Hi all,

So not looking for any free code, only a second set of eyes on the inputs for an indicator and EA :-)


Usual issue, indicator works absolutely fine when applied to a chart, however when i attempt to use via iCustom in an EA I have multiple instances being applied on my back testing using the strategy tester - this is turn causes the strategy test to fall over and not complete.

I had a similar issue before and it was due to a string and int inputs crossover incorrectly, however i dont see that issue here.

Below are the indicator input variables:

#property indicator_separate_window
#property indicator_buffers 6
#property indicator_level1 30
#property indicator_level2 70
#property indicator_minimum 0
#property indicator_maximum 100
#define arrowsDisplacement 0.0003

input string                RSI_settings                     = "----------------------------------------------------------------------";
input int                   RSI_period                       = 14;
input ENUM_APPLIED_PRICE    RSI_applied_price                = 0; 
input string                Indicator_settings               = "----------------------------------------------------------------------";
input bool                  DrawIndicatorTrendLines          = true;
input bool                  DrawPriceTrendLines              = true;
input bool                  DisplayAlert                     = true;
input bool                  DisplayClassicalDivergences      = true;
input bool                  DisplayHiddenDivergences         = false;
input color                 LongColour                       = clrLimeGreen;
input color                 ShortColour                      = clrDeepPink;
input uchar                 LongArrowCode                    = 233;
input uchar                 ShortArrowCode                   = 234;
input int                   ArrowSize                        = 1;
input color                 RSIColour                        = clrGoldenrod;
input ENUM_LINE_STYLE       RSIStyle                         = 0;
input int                   RSIWidth                         = 1;
input int                   rsiupper                         = 50;
input int                   rsilower                         = 40;

Below is the same being defined in my EA:

sinput string a1="============ Indicator settings ============";//============ Indicator settings ============
input int                   RSI_period                       = 21;
input ENUM_APPLIED_PRICE    RSI_applied_price                = 0;
input bool                  DrawIndicatorTrendLines          = true;
input bool                  DrawPriceTrendLines              = true;
input bool                  DisplayAlert                     = true;
input bool                  DisplayClassicalDivergences      = true;
input bool                  DisplayHiddenDivergences         = false;
input int                   rsiupper                         = 50;
input int                   rsilower                         = 40;

and here is the iCustom function....

int fill_levels()
  {
   cur_buy=iCustom(Symbol(),0,"RSI_Divergence2",RSI_period,RSI_applied_price,DrawIndicatorTrendLines,DrawPriceTrendLines,DisplayAlert,DisplayClassicalDivergences,DisplayHiddenDivergences,rsilower,rsiupper,3,1);   
   cur_sell=iCustom(Symbol(),0,"RSI_Divergence2",RSI_period,RSI_applied_price,DrawIndicatorTrendLines,DrawPriceTrendLines,DisplayAlert,DisplayClassicalDivergences,DisplayHiddenDivergences,rsilower,rsiupper,3,1); 
     {
         if(cur_buy == 1)return 1;
         if(cur_sell==3)return 0;
     }
   return -1;
  }

any ideas why this is generating multiple instances on a backtest?

 
Indicator
iCustom
/////////////iCustom
input string                RSI_settings
input int                   RSI_period
input ENUM_APPLIED_PRICE    RSI_applied_price
input string                Indicator_settings
input bool                  DrawIndicatorTrendLines
input bool                  DrawPriceTrendLines
input bool                  DisplayAlert
input bool                  DisplayClassicalDivergences
input bool                  DisplayHiddenDivergences
input color                 LongColour
input color                 ShortColour
input uchar                 LongArrowCode
input uchar                 ShortArrowCode
input int                   ArrowSize
input color                 RSIColour
input ENUM_LINE_STYLE       RSIStyle
input int                   RSIWidth
input int                   rsiupper
input int                   rsilower
 cur_buy=iCustom(Symbol(),0,"RSI_Divergence2",
// Missing argument, a string
RSI_period,
RSI_applied_price,
// Missing argument, a string
DrawIndicatorTrendLines,
DrawPriceTrendLines,
DisplayAlert,
DisplayClassicalDivergences,
DisplayHiddenDivergences,
// Missing argument, 
// Missing argument, 
// Missing argument, 
// Missing argument, 
// Missing argument, 
// Missing argument, 
// Missing argument, 
// Missing argument, 
rsilower,
rsiupper,
3,1); 

You should encapsulate your iCustom calls to make your code self-documenting.
          Detailed explanation of iCustom - MQL4 programming forum
 
William Roeder:
Indicator
iCustom

You should encapsulate your iCustom calls to make your code self-documenting.
          Detailed explanation of iCustom - MQL4 programming forum

thank you William - this is now working correctly, for some reason i thought i could omit some of the inputs thinking they would default.

Another question if you don't mind, regarding the same indicator, i'm trying to pick up when an arrow is populated with a value thinking that it will be filled with EMPTY_VALUE when not generated but unfortunately i'm having no luck - what would be your opinion here? when no arrow is generated the data window is showing nothing.

indicator code:

input string                RSI_settings                     = "----------------------------------------------------------------------";
input int                   RSI_period                       = 14;
input ENUM_APPLIED_PRICE    RSI_applied_price                = 0; 
input string                Indicator_settings               = "----------------------------------------------------------------------";
input bool                  DrawIndicatorTrendLines          = true;
input bool                  DrawPriceTrendLines              = true;
input bool                  DisplayAlert                     = true;
input bool                  DisplayClassicalDivergences      = true;
input bool                  DisplayHiddenDivergences         = false;
input color                 LongColour                       = clrLimeGreen;
input color                 ShortColour                      = clrDeepPink;
input uchar                 LongArrowCode                    = 233;
input uchar                 ShortArrowCode                   = 234;
input int                   ArrowSize                        = 1;
input color                 RSIColour                        = clrGoldenrod;
input ENUM_LINE_STYLE       RSIStyle                         = 0;
input int                   RSIWidth                         = 1;
input int                   rsiupper                         = 50;
input int                   rsilower                         = 40;
//---- buffers
double bullishDivergence[];
double bearishDivergence[];
double rsi[];
double divergencesType[];
double divergencesRSIDiff[];
double divergencesPriceDiff[];
//----
static datetime lastAlertTime;
static string   indicatorName;
string RSILine,PriceLine;



void OnInit()
  {
   int t1;

//---- indicators
   SetIndexStyle(0,DRAW_ARROW,EMPTY,ArrowSize,LongColour);
   SetIndexStyle(1,DRAW_ARROW,EMPTY,ArrowSize,ShortColour);
   SetIndexStyle(2,DRAW_LINE,RSIStyle,RSIWidth,RSIColour);
   
   t1=3;
   while(t1<=5)
     {
      SetIndexStyle(t1,DRAW_NONE);
      t1++;
     }

//----
   SetIndexBuffer(0, bullishDivergence);
   SetIndexBuffer(1, bearishDivergence);
   SetIndexBuffer(2, rsi);
   SetIndexBuffer(3, divergencesType);
   SetIndexBuffer(4, divergencesRSIDiff);
   SetIndexBuffer(5, divergencesPriceDiff);  
   
//----
   SetIndexArrow(0,LongArrowCode);
   SetIndexArrow(1,ShortArrowCode);
   
   
//----
   indicatorName=StringConcatenate("RSI Divergence (",RSI_period,", ",RSI_applied_price,")");
   SetIndexDrawBegin(3,RSI_period);
   IndicatorDigits(Digits() + 2);
   IndicatorShortName(indicatorName);
   RSILine="RSIDiv RSI ";
   PriceLine="RSIDiv Price ";
  }
void OnDeinit(const int reason) {if(!IsTesting()) {RemoveObjects("RSIDiv ");}}

int start()
  {
   int countedBars = IndicatorCounted();
   if(countedBars < 0)
      countedBars = 0;
   CalculateIndicator(countedBars);
   return(0);
  }







void CalculateIndicator(int countedBars)

  {

   for(int i = Bars - countedBars; i >= 0; i--)

     {

      CalculateRSI(i);

      CatchBullishDivergence(i + 2);

      CatchBearishDivergence(i + 2);

     }

  }







void CalculateRSI(int x1)

  {

   rsi[x1] = iRSI(Symbol(),PERIOD_CURRENT,RSI_period,RSI_applied_price,x1);

  }







void CatchBullishDivergence(int shift)

  {
   int t4;

   datetime h1,h2;

   string s7;



   if(IsIndicatorTrough(shift) == false)

      return;



   int currentTrough = shift;

   int lastTrough = GetIndicatorLastTrough(shift);



//--CLASSIC DIVERGENCE--//


   if(DisplayClassicalDivergences)

     {

      if(rsi[currentTrough] > rsi[lastTrough] && Low[currentTrough] < Low[lastTrough] && rsi[currentTrough] <= rsilower)

        {

         bullishDivergence[currentTrough] = rsi[currentTrough];// - arrowsDisplacement;        

         divergencesType[currentTrough] = 1; //"Classic Bullish";

         divergencesRSIDiff[currentTrough] = MathAbs(rsi[currentTrough] - rsi[lastTrough]);

         divergencesPriceDiff[currentTrough] = MathAbs(Low[currentTrough] - Low[lastTrough]);



         if(DrawPriceTrendLines)
           {
            h1=Time[currentTrough];
            h2=Time[lastTrough];
            s7=StringConcatenate(PriceLine,h1," ",h2);
            t4=0;

            DrawTrendLine(s7,t4,h1,Low[currentTrough],h2,Low[lastTrough],LongColour,STYLE_SOLID,1);
           }



         if(DrawIndicatorTrendLines)
           {
            h1=Time[currentTrough];
            h2=Time[lastTrough];
            s7=StringConcatenate(RSILine,h1," ",h2);
            t4=ChartWindowFind(0,indicatorName);

            DrawTrendLine(s7,t4,h1,rsi[currentTrough],h2,rsi[lastTrough],LongColour,STYLE_SOLID,1);
           }





         if(DisplayAlert)

            DisplayAlert("Classical RSI bullish divergence on: ", currentTrough);

        }

     }

in my EA i'm using the following:

int fill_levels()
  {
   cur_buy=iCustom(Symbol(),0,"RSI_Divergence2",RSI_settings,RSI_period,RSI_applied_price,Indicator_settings,DrawIndicatorTrendLines,DrawPriceTrendLines,DisplayAlert,DisplayClassicalDivergences,DisplayHiddenDivergences,LongColour,ShortColour,LongArrowCode,ShortArrowCode,ArrowSize,RSIColour,RSIStyle,RSIWidth,rsilower,rsiupper,0,1);   
   cur_sell=iCustom(Symbol(),0,"RSI_Divergence2",RSI_settings,RSI_period,RSI_applied_price,Indicator_settings,DrawIndicatorTrendLines,DrawPriceTrendLines,DisplayAlert,DisplayClassicalDivergences,DisplayHiddenDivergences,LongColour,ShortColour,LongArrowCode,ShortArrowCode,ArrowSize,RSIColour,RSIStyle,RSIWidth,rsilower,rsiupper,1,1); 
     {
         if(cur_buy !=EMPTY_VALUE)return 1;
         if(cur_sell !=EMPTY_VALUE)return 0;
     }
   return -1;
  }
 

This might fix it:

   for(int i = Bars - countedBars; i >= 0; i--)
     {
      bullishDivergence[i]=EMPTY_VALUE;
      bearishDivergence[i]=EMPTY_VALUE;
      CalculateRSI(i);
      CatchBullishDivergence(i + 2);
      CatchBearishDivergence(i + 2);
     }
 
lippmaje:

This might fix it:

thank you for the suggestion, unfortunately this didnt seem to work :-(

 
SJCFX:

thank you for the suggestion, unfortunately this didnt seem to work :-(

Notice that it is computed for i + 2 ? And this is assigned to shift, which in turn is assigned to currentTrough.

  CatchBullishDivergence(i + 2);

void CatchBullishDivergence(int shift)

  int currentTrough = shift;

bullishDivergence[currentTrough] = ...

Maybe you will always get empty values for shift=1 in your iCustom call. Just a guess. Try with shift=2.

   cur_buy=iCustom(...,rsiupper,0,2);   
 
lippmaje:

Notice that it is computed for i + 2 ? And this is assigned to shift, which is in turn assigned to currentTrough.

Maybe you will always get empty values for shift=1 in your iCustom call. Just a guess. Try with shift=2.

great spot, that is exactly the issue. thank you very much!

 
SJCFX:

great spot, that is exactly the issue. thank you very much!

ok!

On a second view, I think this i + 2 could be replaced with i + 1. This will make it less laggy.

I'd also suggest to introduce a bar computation limit. This will speed up the backtest:

...
input int                   rsilower                         = 40;
input int                   InpMaxBars                       = 500; // max bars to compute

// replace the deprecated start()
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=rates_total-prev_calculated;
   if(InpMaxBars && limit>=InpMaxBars)
      limit=InpMaxBars-1;
   if(limit>rates_total-1)
      limit=rates_total-1;
   CalculateIndicator(limit);
   return rates_total;
  }

void CalculateIndicator(int limit)
  {
   for(int i=limit; i>=0; i--)
     {
      bullishDivergence[i]=EMPTY_VALUE;
      bearishDivergence[i]=EMPTY_VALUE;
      CalculateRSI(i);
      CatchBullishDivergence(i + 1);
      CatchBearishDivergence(i + 1);
     }
  }
Reason: