MQL4. Написание индикатора.

 

Здравствуйте! Я написала индикатор основанный на трех МА. Но индикатор не виден на графике и в тестере такая ошибка: 3MA EURUSD,H1: array out of range in '3MA.mq4' (109,20). Помогите разобраться. Ко представлен ниже:

#property indicator_chart_window
#property indicator_buffers 5
#property indicator_color1  Yellow
#property indicator_color2  Red
#property indicator_color3  Pink
#property indicator_color4  Yellow
#property indicator_color5  Red
//+----------------------------------------------------------------------------+
extern int Period_Ma1       = 6;
extern int Period_Ma2       = 18;
extern int Period_Ma3       = 36;
extern int ma_method1       = 0;   //method MA 0-3
extern int ma_method2       = 0;   //method MA 0-3
extern int ma_method3       = 0;   //method MA 0-3
extern int price1           = 3;   //applied price 0-6
extern int price2           = 3;   //applied price 0-6
extern int price3           = 3;   //applied price 0-6
extern int shift            = 0;
extern int arrow_code_up    = 218;
extern int arrow_code_down  = 217;
extern int width            = 3;
//--- indicator buffers
double ExtMapBuffer0[];
double ExtMapBuffer1[];
double ExtMapBuffer2[];
double ExtMapBuffer3[];
double ExtMapBuffer4[];
datetime LastTime=0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicator line
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMapBuffer0);

   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,ExtMapBuffer1);

   SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(2,ExtMapBuffer2);

   SetIndexStyle(3,DRAW_ARROW,EMPTY,width);
   SetIndexArrow(3,arrow_code_up);
   SetIndexBuffer(3,ExtMapBuffer3);
   SetIndexEmptyValue(3,0.0);

   SetIndexStyle(4,DRAW_ARROW,EMPTY,width);
   SetIndexArrow(4,arrow_code_down);
   SetIndexBuffer(4,ExtMapBuffer4);
   SetIndexEmptyValue(4,0.0);

   IndicatorShortName("3MA");

   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   int limit;
   int counted_bars=IndicatorCounted();

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
   limit=Bars-counted_bars;
   for(int i=limit; i>=0; i--)
     {
      double MA_1_0= iMA(NULL,0,Period_Ma1,0,ma_method1,price1,i+shift);
      double MA_1_1= iMA(NULL,0,Period_Ma1,0,ma_method1,price1,i+shift+1);
      double MA_2_0= iMA(NULL,0,Period_Ma2,0,ma_method2,price2,i+shift);
      double MA_2_1= iMA(NULL,0,Period_Ma2,0,ma_method2,price2,i+shift+1);
      double MA_3_0= iMA(NULL,0,Period_Ma3,0,ma_method3,price3,i+shift);
      double MA_3_1= iMA(NULL,0,Period_Ma3,0,ma_method3,price3,i+shift+1);
      ExtMapBuffer0[i]=MA_1_0;
      ExtMapBuffer1[i]=MA_2_0;
      ExtMapBuffer2[i]=MA_3_0;

      if(MA_1_1>MA_1_0 && MA_1_1>MA_2_1 && MA_1_0<MA_2_0 && MA_2_1>MA_3_1 && MA_2_0<MA_3_0 && Time[i]!=LastTime)
        {
         ExtMapBuffer3[i]=High[i]+5*Point;
         LastTime=Time[i];
        }

      if(MA_1_1<MA_1_0 && MA_1_1<MA_2_1 && MA_1_0>MA_2_0 && MA_2_1<MA_3_1 && MA_2_0>MA_3_0 && Time[i]!=LastTime)
        {
         ExtMapBuffer4[i]=Low[i]-5*Point;
         LastTime=Time[i];
        }
     }

   return(0);
  }
//+------------------------------------------------------------------+

 


 
for(int i=limit-1; i>=0; i--)

но если ещё идёт -- "+shift+1" -- то надо отнимать не 1:

for(int i=limit-1-(shift+1); i>=0; i--)
 
Andrey F. Zelinsky:

но если ещё идёт -- "+shift+1" -- то надо отнимать не 1:

Только может оказаться что limit-shift<0

Цикл выполнится один раз на исторических данных и больше работать не будет.

Плохой совет 

 
Anna_89:

Здравствуйте! Я написала индикатор основанный на трех МА. Но индикатор не виден на графике и в тестере такая ошибка: 3MA EURUSD,H1: array out of range in '3MA.mq4' (109,20). Помогите разобраться. Ко представлен ниже:

 


Мой совет не лучше. Но проще было индикатор написать чем объяснять

//+------------------------------------------------------------------+
//|                                                          3MA.mq4 |
//|                                            Copyright 2015, Vinin |
//|                                             http://vinin.ucoz.ru |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vinin"
#property link      "http://vinin.ucoz.ru"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots   5
//--- plot MA1
#property indicator_label1  "MA1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot MA2
#property indicator_label2  "MA2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot MA3
#property indicator_label3  "MA3"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Arrow1
#property indicator_label4  "Arrow1"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrRed
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot Arrow2
#property indicator_label5  "Arrow2"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrRed
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- input parameters
input int      Period_MA1=6;
input ENUM_MA_METHOD Method_MA1=MODE_SMA;
input ENUM_APPLIED_PRICE Price_MA1=PRICE_CLOSE;

input int      Period_MA2=18;
input ENUM_MA_METHOD Method_MA2=MODE_SMA;
input ENUM_APPLIED_PRICE Price_MA2=PRICE_CLOSE;

input int      Period_MA3=36;
input ENUM_MA_METHOD Method_MA3=MODE_SMA;
input ENUM_APPLIED_PRICE Price_MA3=PRICE_CLOSE;

input int      Shift;
//--- indicator buffers
double         MA1Buffer[];
double         MA2Buffer[];
double         MA3Buffer[];
double         Arrow1Buffer[];
double         Arrow2Buffer[];

int Period_Max=0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,MA1Buffer);
   SetIndexBuffer(1,MA2Buffer);
   SetIndexBuffer(2,MA3Buffer);
   SetIndexBuffer(3,Arrow1Buffer);
   SetIndexBuffer(4,Arrow2Buffer);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   SetIndexArrow(3,159);
   SetIndexArrow(3,159);
   
   if (Period_MA1>Period_Max) Period_Max=Period_MA1;
   if (Period_MA2>Period_Max) Period_Max=Period_MA2;
   if (Period_MA3>Period_Max) Period_Max=Period_MA3;
   Period_Max+=Shift;
   
//---
   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[])
  {
//---
   int limit=rates_total-prev_calculated;
   if (limit>1) 
   {
      limit=rates_total-Period_Max-1;
   }
   
   for (int i=limit;i>=0;i--)
   {
      double MA_1_0= iMA(NULL,0,Period_MA1,0,Method_MA1,Price_MA1,i+Shift);
      double MA_1_1= iMA(NULL,0,Period_MA1,0,Method_MA1,Price_MA1,i+Shift+1);
      
      double MA_2_0= iMA(NULL,0,Period_MA2,0,Method_MA2,Price_MA2,i+Shift);
      double MA_2_1= iMA(NULL,0,Period_MA2,0,Method_MA2,Price_MA2,i+Shift+1);
      
      double MA_3_0= iMA(NULL,0,Period_MA3,0,Method_MA3,Price_MA3,i+Shift);
      double MA_3_1= iMA(NULL,0,Period_MA3,0,Method_MA3,Price_MA3,i+Shift+1);
      
      MA1Buffer[i]=MA_1_0;
      MA2Buffer[i]=MA_2_0;
      MA3Buffer[i]=MA_3_0;
      Arrow1Buffer[i]=0;
      Arrow2Buffer[i]=0;


      if(MA_1_1>MA_1_0 && MA_1_1>MA_2_1 && MA_1_0<MA_2_0 && MA_2_1>MA_3_1 && MA_2_0<MA_3_0)
        {
         Arrow1Buffer[i]=High[i]+5*Point;
        }

      if(MA_1_1<MA_1_0 && MA_1_1<MA_2_1 && MA_1_0>MA_2_0 && MA_2_1<MA_3_1 && MA_2_0>MA_3_0)
        {
         Arrow2Buffer[i]=Low[i]-5*Point;
        }
   
   }
   
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 

Здесь налицо архитектурная ошибка: допустимые значения итератора цикла рассчитываются одним способом, а в теле цикла с рассчитанным значением производятся дополнительные действия, допустимость которых нигде не проверяется.

Наиболее простой путь исправления - проверять допустимость индекса бара в самом теле цикла:

 for(int i=limit; i>=0; i--)
     {
      int curBarIndex = i + shift;
      int prevBarIndex = curBarIndex + 1;
      if (curBarIndex < 0 || prevBarIndex < 0 || prevBarIndex >= Bars)
          continue;

      double MA_1_0= iMA(NULL,0,Period_Ma1,0,ma_method1,price1,curBarIndex);
      double MA_1_1= iMA(NULL,0,Period_Ma1,0,ma_method1,price1,prevBarIndex );
      double MA_2_0= iMA(NULL,0,Period_Ma2,0,ma_method2,price2,curBarIndex);
      double MA_2_1= iMA(NULL,0,Period_Ma2,0,ma_method2,price2,prevBarIndex );
      double MA_3_0= iMA(NULL,0,Period_Ma3,0,ma_method3,price3,curBarIndex);
      double MA_3_1= iMA(NULL,0,Period_Ma3,0,ma_method3,price3,prevBarIndex );

Хотя лучше всего делать такие проверки еще до входа в цикл. 

P. S. А может для shift имелось в виду смещение самой МА, т. е. таким вот образом?

double MA_1_0= iMA(NULL,0,Period_Ma1,shift,ma_method1,price1,i);
 
Victor Nikolaev:

Только может оказаться что limit-shift<0

Цикл выполнится один раз на исторических данных и больше работать не будет.

Плохой совет 

так у тебя такой же совет как и у меня.

у тебя:

   if (limit>1) 
   {
      limit=rates_total-Period_Max-1;
   }
   for (int i=limit;i>=0;i--)

до этого:

Period_Max+=Shift;
 
Andrey F. Zelinsky:

так у тебя такой же совет как и у меня.

у тебя:

до этого:

Э нет. У  меня проверка до цикла идет и отрицательного значения не может быть. Только в том случае, если недостаточно баров на графике
Причина обращения: