Problems with custom indicator array - need guidance

 

Hi,

I’m in the process of trying to replicate a custom indicator from MT4 for the MT5 that is based off the turtle trading breakout strategy.  The strategy in this example generates a trade signal at the breakout of the 20 day high for a long entry and 20 day low for a short entry. Furthermore, after taking a long position for example, it will exit the position after a 10 day low and the opposite for a short position.

Specifically, the custom indicator I’m trying to replicate is intended to do the following:

1.       Identify the trend by comparing the current bar’s close against the 20 day high/low (i.e. refer to rhigh and rlow below). If the close  > 20 day high then it is an uptrend (i.e. TrendDirection[i] = OP_BUY) therefore plot:

a.       an arrow indicating the point of change in trend, the new 20 day breakout line and also the 10 day low exit line (i.e. against ExtMapBuffer5[i], ExtMapBuffer1[i] and ExtMapBuffer3[i] respectively;

2.       The opposite would apply if the close < 20 day low then it is a downtrend. In both cases, the direction of the trend would be recorded in the TrendDirection[] array for comparison purposes for when a new bar appears;

3.       Should there be a change in the trend in the form of a 20 day breakout in the opposite direction then change the plotting of the line.

I have attached a screenshot of what it currently looks like in MT4 and also what I am getting in MT5.

MT4 Turtle Indicator Example

MT5 Turtle Indicator Example

 Also attached below is the work in progress code for the MT5.

Comparing the two screenshots it is clear that my MT5 indicator is not getting the desired results. I suspect it has something to do with how the TrendDirection[i] array is recording the information. When I run an Alert function in the loop to output the TrendDirection array I get a stack of zeroes. I have been trawling through this forum and reading up on indicator buffers and arrays but am truly stuck.

Could someone kindly guide me as to why this is the case?

Thanks in advance for your help.

PV 

//---- indicator settings
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_plots 6

#property indicator_label1 "ExtMapBuffer1"
#property indicator_label2 "ExtMapBuffer2"
#property indicator_label3 "ExtMapBuffer3"
#property indicator_label4 "ExtMapBuffer4"
#property indicator_label5 "ExtMapBuffer5"
#property indicator_label6 "ExtMapBuffer6"
#property indicator_type1 DRAW_LINE
#property indicator_type2 DRAW_LINE
#property indicator_type3 DRAW_LINE
#property indicator_type4 DRAW_LINE
#property indicator_type5 DRAW_LINE
#property indicator_type6 DRAW_LINE
#property indicator_color1 DodgerBlue
#property indicator_color2 Red
#property indicator_color3 Yellow
#property indicator_color4 White
#property indicator_color5 DodgerBlue
#property indicator_color6 Red
#property indicator_width1 3
#property indicator_width2 3
#property indicator_width3 1
#property indicator_width4 1
#property indicator_width5 1
#property indicator_width6 1
#property indicator_style1 STYLE_SOLID
#property indicator_style2 STYLE_SOLID
#property indicator_style3 STYLE_DOT
#property indicator_style4 STYLE_DOT
#property indicator_style5 STYLE_DOT
#property indicator_style6 STYLE_DOT

//---- indicator parameters
input int  TradePeriod         = 20;     // Donchian channel period for trading signals
input int  StopPeriod          = 10;     // Donchian channel period for exit signals
input bool Strict              = false;  // Apply strict entry parameters like the Turtles did
input bool DisplayAlerts       = false;  // Display Alerts

//---- indicator buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
double ExtMapBuffer5[];
double ExtMapBuffer6[];
double TrendDirection[];



//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // One more invisible buffer to store trend direction
   SetIndexBuffer(0,ExtMapBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,ExtMapBuffer2,INDICATOR_DATA);
   SetIndexBuffer(2,ExtMapBuffer3,INDICATOR_DATA);
   SetIndexBuffer(3,ExtMapBuffer4,INDICATOR_DATA);
   SetIndexBuffer(4,ExtMapBuffer5,INDICATOR_DATA);
   SetIndexBuffer(5,ExtMapBuffer6,INDICATOR_DATA);
   SetIndexBuffer(6,TrendDirection,INDICATOR_CALCULATIONS);
   
   // Drawing settings
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(1,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(2,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(3,PLOT_DRAW_TYPE,DRAW_LINE);
   PlotIndexSetInteger(4,PLOT_DRAW_BEGIN,TradePeriod);
   PlotIndexSetInteger(5,PLOT_DRAW_BEGIN,TradePeriod);
   IndicatorSetInteger(INDICATOR_DIGITS,(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS));
   
   // Name and labels
   IndicatorSetString(INDICATOR_SHORTNAME,"Turtle Channel ("+(string)TradePeriod +"-"+ (string)StopPeriod +")");
   PlotIndexSetString(0,PLOT_LABEL,"Upper line");
   PlotIndexSetString(1,PLOT_LABEL,"Lower line");
   PlotIndexSetString(2,PLOT_LABEL,"Longs Stop line");
   PlotIndexSetString(3,PLOT_LABEL,"Shorts Stop line");
   PlotIndexSetString(4,PLOT_LABEL,"Bullish trend change");
   PlotIndexSetString(5,PLOT_LABEL,"Bearish trend change");
   
   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 < TradePeriod - 1) return(0);
          
     // More vars here too
     int first;    
     if(prev_calculated==0)
     first = 0;
     else first = prev_calculated - 1;

     // Check the signal foreach bar
     for(int i = first; i < rates_total; i++)
     {           
         // Highs and lows
         double rhigh = high[ArrayMaximum(high,i,TradePeriod)];
         double rlow = low[ArrayMaximum(low,i,TradePeriod)];
         double shigh = high[ArrayMaximum(high,i,StopPeriod)];
         double slow = low[ArrayMaximum(low,i,StopPeriod)];
         
         // Candle value
         double CLOSE = close[i];
         double HIGH = high[i];
         double LOW = low[i];
     
         // Default behavior is to preserve the trend
         if(prev_calculated > 0) TrendDirection[i] = TrendDirection[i-1];
         //TrendDirection[0] = 0;
         
         // It might be recalculating bar zero
         ExtMapBuffer1[i] = EMPTY_VALUE;                          
         ExtMapBuffer2[i] = EMPTY_VALUE;                          
         ExtMapBuffer3[i] = EMPTY_VALUE;                          
         ExtMapBuffer4[i] = EMPTY_VALUE;                        
         ExtMapBuffer5[i] = EMPTY_VALUE;                          
         ExtMapBuffer6[i] = EMPTY_VALUE;                          
         
     // If it is a new bar then
     if(prev_calculated == 0) {
         
         if((CLOSE > rhigh && i > 0))
         {
         // Change to uptrend
            TrendDirection[i] = ORDER_TYPE_BUY;
            ExtMapBuffer5[i] = rlow;                              
         
         // Change to downtrend
         } else if(((CLOSE < rlow && i > 0))) {
            
            TrendDirection[i] = ORDER_TYPE_SELL;
            ExtMapBuffer6[i] = rhigh;                             
         }
         
         // Draw lines
         if(TrendDirection[i] == ORDER_TYPE_BUY)
         {
            ExtMapBuffer1[i] = rlow;                              
            ExtMapBuffer3[i] = slow;                              
            
         // Draw lines
         } else if(TrendDirection[i] == ORDER_TYPE_SELL) {
         
            ExtMapBuffer2[i] = rhigh;                             
            ExtMapBuffer4[i] = shigh;                                      }
         }
     
     if(prev_calculated > 0)
         {
         if(((CLOSE > rhigh && i > 0) || (HIGH > rhigh && Strict == true)) && TrendDirection[i-1] != ORDER_TYPE_BUY)
         {
         // Change to uptrend   
            TrendDirection[i] = ORDER_TYPE_BUY;
            ExtMapBuffer5[i] = rlow;                              
         
         // Change to downtrend
         } else if(((CLOSE < rlow && i > 0) || (LOW < rlow && Strict == true)) && TrendDirection[i-1] != ORDER_TYPE_SELL) 
         {
            
            TrendDirection[i] = ORDER_TYPE_SELL;
            ExtMapBuffer6[i] = rhigh;                             
         }
         
         // Draw lines
         if(TrendDirection[i] == ORDER_TYPE_BUY)
         {
            ExtMapBuffer1[i] = rlow;                              
            ExtMapBuffer3[i] = slow;                              
            
         // Draw lines
         } else if(TrendDirection[i] == ORDER_TYPE_SELL) {
         
            ExtMapBuffer2[i] = rhigh;                             
            ExtMapBuffer4[i] = shigh;                             
         }
         }

     }
   
      return(rates_total);
}
 
pvo2:

Hi,

I’m in the process of trying to replicate a custom indicator from MT4 for the MT5 that is based off the turtle trading breakout strategy.  The strategy in this example generates a trade signal at the breakout of the 20 day high for a long entry and 20 day low for a short entry. Furthermore, after taking a long position for example, it will exit the position after a 10 day low and the opposite for a short position.

...
Can you provide a link to the mql4 code please.
 

Hi angevoyageur,

Attached below is the MT4 indicator I am trying to replicate. It is essentially a free indicator I downloaded from pointzero-indicator.com.

When first trying to migrate the indicator from MT4 to MT5, I had only changed the syntax to the extent it was MT5 compatible but kept the logic the same. However, when I tried to compile in MT5, it kept on giving me an "Array out of range error" and pointed to the TrendDirection[i] = TrendDirection[i+1] as being the cause. It struck me as odd because I thought dynamic arrays would not experience such errors and thought it might have something to do with decrementing the loop from rates_total to 0 instead of the other way around. Changing the direction of the loop didn't fix the problem and the MT5 code you see above is how far I've progressed on the matter.

If you could help shed any light that would be much appreciated.

Thanks.

Peter 

 

//+------------------------------------------------------------------+
//| TheTurtleTradingChannel.mq4
//| Copyright © Pointzero-indicator.com
//+------------------------------------------------------------------+
#property copyright "Copyright © Pointzero-indicator.com"


//---- indicator settings
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_color1 DodgerBlue
#property indicator_color2 Red
#property indicator_color3 Yellow
#property indicator_color4 Yellow
#property indicator_color5 DodgerBlue
#property indicator_color6 Red
#property indicator_width1 3
#property indicator_width2 3
#property indicator_width3 1
#property indicator_width4 1
#property indicator_width5 1
#property indicator_width6 1
#property indicator_style3 STYLE_DOT
#property indicator_style4 STYLE_DOT
#property indicator_style5 STYLE_DOT
#property indicator_style6 STYLE_DOT

//---- indicator parameters
extern int  TradePeriod         = 20;     // Donchian channel period for trading signals
extern int  StopPeriod          = 10;     // Donchian channel period for exit signals
extern bool Strict              = false;  // Apply strict entry parameters like the Turtles did
extern bool DisplayAlerts       = false;  // You know...

//---- indicator buffers
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
double ExtMapBuffer5[];
double ExtMapBuffer6[];
double TrendDirection[];

//---- internal
static datetime TimeStamp;
static int AlertCount = 1;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
{
   // One more invisible buffer to store trend direction
   IndicatorBuffers(7);
   
   // Drawing settings
   SetIndexStyle(0,DRAW_LINE);
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE);
   SetIndexStyle(4,DRAW_ARROW); SetIndexArrow(4,159);
   SetIndexStyle(5,DRAW_ARROW); SetIndexArrow(5,159);
   IndicatorDigits(MarketInfo(Symbol(),MODE_DIGITS));
   
   // Name and labels
   IndicatorShortName("Turtle Channel ("+ TradePeriod +"-"+ StopPeriod +")");
   SetIndexLabel(0,"Upper line");
   SetIndexLabel(1,"Lower line");
   SetIndexLabel(2,"Longs Stop line");
   SetIndexLabel(3,"Shorts Stop line");
   SetIndexBuffer(4, "Bullish trend change");
   SetIndexBuffer(5, "Bearish trend change");
   
   // Buffers
   SetIndexBuffer(0,ExtMapBuffer1);
   SetIndexBuffer(1,ExtMapBuffer2);
   SetIndexBuffer(2,ExtMapBuffer3);    // Stop level for longs
   SetIndexBuffer(3,ExtMapBuffer4);    // Stop level for shorts
   SetIndexBuffer(4,ExtMapBuffer5);
   SetIndexBuffer(5,ExtMapBuffer6);
   SetIndexBuffer(6,TrendDirection);
   
   

   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
{
     // More vars here too...
     int start = 0;
     int limit;
     int counted_bars = IndicatorCounted();

     // check for possible errors
     if(counted_bars < 0) 
        return(-1);
        
     // Only check these
     limit = Bars - 1 - counted_bars;
     
     // Check the signal foreach bar
     for(int i = limit; i >= start; i--)
     {           

         // Highs and lows
         double rhigh = iHigh(Symbol(),Period(),iHighest(Symbol(), Period(), MODE_HIGH, TradePeriod,i+1));
         double rlow  = iLow(Symbol(),Period(),iLowest(Symbol(), Period(), MODE_LOW, TradePeriod, i+1));
         double shigh = iHigh(Symbol(),Period(),iHighest(Symbol(), Period(), MODE_HIGH, StopPeriod,i+1));
         double slow  = iLow(Symbol(),Period(),iLowest(Symbol(), Period(), MODE_LOW, StopPeriod, i+1));
         
         // Candle value
         double CLOSE = iClose(Symbol(),0, i);
         double HIGH = iHigh(Symbol(),0, i);
         double LOW = iLow(Symbol(),0, i);
     
         
         // Default behavior is to preserve the trend
         TrendDirection[i] = TrendDirection[i+1];
         
         // It might be recalculating bar zero
         ExtMapBuffer1[i] = EMPTY_VALUE;
         ExtMapBuffer2[i] = EMPTY_VALUE;
         ExtMapBuffer3[i] = EMPTY_VALUE;
         ExtMapBuffer4[i] = EMPTY_VALUE;
         ExtMapBuffer5[i] = EMPTY_VALUE;
         ExtMapBuffer6[i] = EMPTY_VALUE;
         
         // Change to uptrend
         if((CLOSE > rhigh && i > 0))
         {
            TrendDirection[i] = OP_BUY;
            ExtMapBuffer5[i] = rlow;
         
         // Change to downtrend
         } else if((CLOSE < rlow && i > 0)) {
            
            TrendDirection[i] = OP_SELL;
            ExtMapBuffer6[i] = rhigh;
         }
         
         // Draw lines
         if(TrendDirection[i] == OP_BUY)
         {
            ExtMapBuffer1[i] = rlow;
            ExtMapBuffer3[i] = slow;
            
         // Draw lines
         } else if(TrendDirection[i] == OP_SELL) {
         
            ExtMapBuffer2[i] = rhigh;
            ExtMapBuffer4[i] = shigh;
         }
     }
     
     // Alert
     if(TimeStamp != Time[0] && DisplayAlerts == true)
     {
         if(TrendDirection[1] == OP_SELL && TrendDirection[2] == OP_BUY && AlertCount == 0)
         {
            Alert("[Turtle Trading "+ TradePeriod +"-"+ StopPeriod +"]["+ Symbol() +"] SELL");
         } else if (TrendDirection[1] == OP_BUY && TrendDirection[2] == OP_SELL && AlertCount == 0) {
            Alert("[Turtle Trading "+ TradePeriod +"-"+ StopPeriod +"]["+ Symbol() +"] BUY");
         }
         TimeStamp = Time[0];
         AlertCount = 0;
     }
    
   // Bye Bye
  
   return(0);
   
}
Documentation on MQL5: MQL5 programs / Runtime Errors
Documentation on MQL5: MQL5 programs / Runtime Errors
  • www.mql5.com
MQL5 programs / Runtime Errors - Documentation on MQL5
 
pvo2:

Hi angevoyageur,

Attached below is the MT4 indicator I am trying to replicate. It is essentially a free indicator I downloaded from pointzero-indicator.com.

When first trying to migrate the indicator from MT4 to MT5, I had only changed the syntax to the extent it was MT5 compatible but kept the logic the same. However, when I tried to compile in MT5, it kept on giving me an "Array out of range error" and pointed to the TrendDirection[i] = TrendDirection[i+1] as being the cause. It struck me as odd because I thought dynamic arrays would not experience such errors and thought it might have something to do with decrementing the loop from rates_total to 0 instead of the other way around. Changing the direction of the loop didn't fix the problem and the MT5 code you see above is how far I've progressed on the matter.

If you could help shed any light that would be much appreciated.

Thanks.

Peter 

 

I will check that. As a remark, when you post complete code of an indicator (or EA/script), it's more useful to use the Attach file link, so we only have to download it.
 
angevoyageur:
I will check that. As a remark, when you post complete code of an indicator (or EA/script), it's more useful to use the Attach file link, so we only have to download it.

Ok no problem, thanks for the heads up.

PV 

 

The more obvious way to convert from mql4 if you are not accustomed with mql5 is by using ArraySetAsSeries() to have the indexing of arrays working like in mt4.

   ArraySetAsSeries(ExtMapBuffer1,true);
   ...
   ...

You also have to take into account TradePeriod & StopPeriod to calculate "first" and then avoid out of range error.

   if(prev_calculated==0)
     {
      first=rates_total-1-MathMax(TradePeriod,StopPeriod);
      TrendDirection[first+1]=0;
     }
   else
      first=rates_total-1-prev_calculated;

Finally you make a little on error low calculation, you have to use ArrayMinimum instead of ArrayMaximum :

      double rlow = low[ArrayMinimum(low,i+1,TradePeriod)];

See working full code attached.

 
angevoyageur:

The more obvious way to convert from mql4 if you are not accustomed with mql5 is by using ArraySetAsSeries() to have the indexing of arrays working like in mt4.

You also have to take into account TradePeriod & StopPeriod to calculate "first" and then avoid out of range error.

Finally you make a little on low calculation, you have to use ArrayMinimum instead of ArrayMaximum :

See working full code attached.

Hi Alain,

 Wow you make it look very easy.  I did initially put in ArraySetAsSeries but maybe because I had parts of the code grabbing the array elements in one direction and other parts of the code grabbing elements in the opposite direction that it never worked. Definitely a thing to store in the knowledge bank.

Once again, thanks for your help with this.

Peter 

 
pvo2:

Hi Alain,

 Wow you make it look very easy.  I did initially put in ArraySetAsSeries but maybe because I had parts of the code grabbing the array elements in one direction and other parts of the code grabbing elements in the opposite direction that it never worked. Definitely a thing to store in the knowledge bank.

Once again, thanks for your help with this.

Peter 

You are welcome. I attach also here the same indicator but with default indexing of mql5. So you can compare both version.
Files:
 
angevoyageur:
You are welcome. I attach also here the same indicator but with default indexing of mql5. So you can compare both versions.

Hi Alain,

Thanks again. Its especially helpful seeing the two versions of indicator arrays - now I definitely understand how they work!

Cheers.

PV 

 

hello. i have a similar question, cannot understand what is going wrong with robot - it does not load data from indicator so doesnt work.

here is indicator(attached full code, left here most important for convenience:)

#property indicator_buffers 2
extern int InpQual=5;
extern int InpLen=5;
extern int InpCountbars=1000;
double Up[];
double Dn[];
int OnInit(){
   SetIndexBuffer(0, Up, INDICATOR_DATA);
   SetIndexBuffer(1, Dn, INDICATOR_DATA);
}
int OnCalculate(....){
   if (rates_total - prev_calculated == 0) return(rates_total);//no need to calculate current bar
   int limit;
   if (prev_calculated < 1){
      ArrayInitialize(Up, EMPTY_VALUE);
      ArrayInitialize(Dn, EMPTY_VALUE);
      ArraySetAsSeries(Up, 0);
      ArraySetAsSeries(Dn, 0);
      limit = InpCountbars-5; //limit = MathMin(Countbars - 5, Bars(_Symbol,_Period));
   } else      limit = prev_calculated;
   for (int i = limit; i < rates_total && !IsStopped(); i++){
           //simple arithmetical calculations
   return(rates_total);}

 and also here is robot, looked how macd sample.mq5 is written. previously i wrote in mq4 but experience with mq5 is new for me. indicator works ok

 

int OnInit()  {
   if(!ResultExpert.Init())      return(INIT_FAILED);
   return(INIT_SUCCEEDED);
  }
bool CExpert::Init(void)  {
// *** symbol name and other common information
   if(!InitIndicators())      return(false);
   return(true);  
  }
bool CExpert::InitIndicators(void)  {
   if(m_handle_lelExt==INVALID_HANDLE)
      if((m_handle_lelExt=iCustom(_Symbol,0,ind,  ind_qual,ind_len,ind_countbars))==INVALID_HANDLE){
         printf("Error creating Leledc_ExhaustionBar3_upd_mq5 - 0 indicator");
         return false;
      }
   return(true);
  }
void OnTick()  {
   static int perSec = PeriodSeconds(PERIOD_CURRENT);
   static datetime last_bar=0; // last bar datetime
   if (TimeCurrent()/perSec*perSec > last_bar){
      ResultExpert.Processing();
      last_bar = TimeCurrent()/perSec*perSec;
   }
}
bool CExpert::Processing(void)
  {
   if(BarsCalculated(m_handle_lelExt)<2)      return(false);
   if(CopyBuffer(m_handle_lelExt,0,0,2,m_buff_lelExt0)  !=2 ||
      CopyBuffer(m_handle_lelExt,1,0,2,m_buff_lelExt1)  !=2)      return(false);
   ArraySetAsSeries(m_buff_lelExt0,0);
   ArraySetAsSeries(m_buff_lelExt1,0);
   m_lelExt0 = m_buff_lelExt0[1];
   m_lelExt1 = m_buff_lelExt1[1];
   Print("new bar:",TimeCurrent()," ",DoubleToString(m_lelExt0,5),"/",DoubleToString(m_lelExt1,5));
   /// further code, but by now buffer is loaded with error, as sometimes indicator on chart has values, but robot fails to load it
   return(true);
}

 run in tester, obtained info (time current at start of bar and 0.0000000/0.0000000000 for both values) which is not correct, so no need in further calculations. 

please help with loading indicator in mt5. thank you!

edit: attached picture from tester: both 9:00 and 17:00 candles have values of indicator, as can be seen, but tester failed to get that values. 

 
almost solved, problem with indicator's buffers seems works fine now. 
Reason: