Структуры и array out of range

 

Доброго времени суток!

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

Для примера приведу код.

struct tester
  {
   double            bufferNone[];

   void              _init_(int poz)
     {
      SetIndexBuffer(poz,bufferNone,INDICATOR_DATA);
      ArrayResize(bufferNone,2000,0);
      ArraySetAsSeries(bufferNone,true);
      _begin_();
     }

   void              _begin_()
     {
      bufferNone[0]=5;
     }


  };


tester _tester[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   for(int i=0; i<5; i++)
     {
      _tester[i]._init_(i);
     }

  }

Получаю ошибку "array out of range" в выделенной красным строке.

Чего не так? Делаю ведь ресайз массива, а не могу задать значение ни одному из индексов массива.

 
Petr Zharuk:

Доброго времени суток!

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

Для примера приведу код.

Получаю ошибку "array out of range" в выделенной красным строке.

Чего не так? Делаю ведь ресайз массива, а не могу задать значение ни одному из индексов массива.

Если Вы массив устанавливаете как индикаторный буфер, то Resize ему уже не нужно делать - это берёт на себя подсистема терминала.

Опять-таки не понятно, это MQL5 или 4 ?

В первую очередь нужно сделать структуру с единственным буфером и добиться его правильного назначения как индикаторного буфера и обращения к нему. В OnCalculate() (Вы почему-то в скрипте пытаетесь сделать индикаторные буферы) после назначения массива буфером, проверьте его размер. Он должен быть rates_total

 
Artyom Trishkin #:

Если Вы массив устанавливаете как индикаторный буфер, то Resize ему уже не нужно делать - это берёт на себя подсистема терминала.

Опять-таки не понятно, это MQL5 или 4 ?

В первую очередь нужно сделать структуру с единственным буфером и добиться его правильного назначения как индикаторного буфера и обращения к нему. В OnCalculate() (Вы почему-то в скрипте пытаетесь сделать индикаторные буферы) после назначения массива буфером, проверьте его размер. Он должен быть rates_total

Это MQL5.

Изначально код в индикаторе. Но для моделирования ситуации и вопроса на форуме я сделал аналог в виде скрипта. Ошибка такая же.

Я хочу чтобы массив был строгого размера. И индикатор должен рисовать стрелки на последних образно 2000 барах.

Поэтому я задал размер массива в 2000. Перевел его в таймсерию. И привязал к буферу чтобы видеть его на графике. 

Тогда возьму часть кода из моего индикатора для разбора.

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |

//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 32

int bars = 2200;
int totalSymbols = 8;
struct PANEL
  {
   double            bufferBlock[];
   void              initial(int poz)
     {
      SetIndexBuffer(poz,bufferBlock,INDICATOR_DATA);
      ArrayResize(bufferBlock,2200,0);
      ArraySetAsSeries(bufferBlock,true);
      Print("poz "+(string)poz+" имеет размер "+(string)ArraySize(bufferBlock));
      bufferBlock[0]=5;
     }
  };

PANEL _panel[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---
   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[])
  {
//--- return value of prev_calculated for next call


   ArrayResize(_panel,totalSymbols,0);
   for(int i=0; i<totalSymbols; i++)
     {
      _panel[i].symbol = SymbolName(i,true);
      _panel[i].initial(i);
     }

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

Код выше выдает:

poz 0 имеет размер 101204
poz 1 имеет размер 101204
array out of range in 'test.mq5' (22,19)

То есть я обозначаю как буфер. Потом меняю размер на нужный, и все равно размер массива игнорирует мой ресайз. И при попытке изменить значение получаю ошибку.

При этом в коде ниже я закомментировал строку с присвоением буфера.

//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 32

int bars = 2200;
int totalSymbols = 2;
struct PANEL
  {
   double            bufferBlock[];
   void              initial(int poz)
     {
      //SetIndexBuffer(poz,bufferBlock,INDICATOR_DATA);
      ArrayResize(bufferBlock,2200,0);
      ArraySetAsSeries(bufferBlock,true);
      Print("poz "+(string)poz+" имеет размер "+(string)ArraySize(bufferBlock));
      
      bufferBlock[0]=5;
      
     }
  };

PANEL _panel[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---
   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[])
  {
//--- return value of prev_calculated for next call


   ArrayResize(_panel,totalSymbols,0);
   for(int i=0; i<totalSymbols; i++)
     {
      _panel[i].initial(i);
     }

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

Результат:

poz 0 имеет размер 2000
poz 1 имеет размер 2000

И ошибки присвоения значения не получаю.

То есть вроде это и решает проблему. Но цель не достигнута. Я не увижу на графике визуальное отображение из за того что массиву не присвоен буфер.

 

Видимо нашел решение. Но осталось обдумать как это сунуть в мой код.

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 8

int bars = 2200;
int totalSymbols = 2;
struct PANEL
  {
   double            bufferBlock[];
   void              initial(int poz)
     {
      ArrayResize(bufferBlock,bars,0);
      ArraySetAsSeries(bufferBlock,true);
      Print("poz "+(string)poz+" имеет размер "+(string)ArraySize(bufferBlock));
      bufferBlock[1]=5;
      Print(bufferBlock[1]);
     }
  };

PANEL _panel[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   ArrayResize(_panel,totalSymbols,0);
   
   for(int i=0;i<totalSymbols;i++)
   {
      SetIndexBuffer(i,_panel[i].bufferBlock,INDICATOR_DATA);
   }
//---
   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[])
  {
//--- return value of prev_calculated for next call



   for(int i=0; i<totalSymbols; i++)
     {
      _panel[i].initial(i);
     }

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

Ошибок не выдает.

 
Petr Zharuk #:
#property indicator_buffers 32
Petr Zharuk #:

Это MQL5.

Изначально код в индикаторе. Но для моделирования ситуации и вопроса на форуме я сделал аналог в виде скрипта. Ошибка такая же.

Я хочу чтобы массив был строгого размера. И индикатор должен рисовать стрелки на последних образно 2000 барах.

Поэтому я задал размер массива в 2000. Перевел его в таймсерию. И привязал к буферу чтобы видеть его на графике. 

Тогда возьму часть кода из моего индикатора для разбора.

Код выше выдает:


То есть я обозначаю как буфер. Потом меняю размер на нужный, и все равно размер массива игнорирует мой ресайз. И при попытке изменить значение получаю ошибку.

При этом в коде ниже я закомментировал строку с присвоением буфера.

Результат:

И ошибки присвоения значения не получаю.

То есть вроде это и решает проблему. Но цель не достигнута. Я не увижу на графике визуальное отображение из за того что массиву не присвоен буфер.

#property indicator_buffers 32

Это общее количество буферов.

А где рисуемые? Их тоже нужно указывать

 
Petr Zharuk #:

Видимо нашел решение. Но осталось обдумать как это сунуть в мой код.

Ошибок не выдает.

Для начала возможно стОит "обдумать" после прочтения справки, документации и запросы в гугл по сайту, типа этого

Имхенько

Пользовательские индикаторы в MQL5 для начинающих
Пользовательские индикаторы в MQL5 для начинающих
  • www.mql5.com
Любой новый предмет для новичка с первого взгляда кажется сложным для понимания. Нам кажется простым и ясным то, что мы уже знаем. Но мы просто не помним, что всем нам когда-то приходилось изучать с нуля, даже родной язык, на котором мы разговариваем. Так и язык MQL5, таящий в себе огромные возможности для написания торговых стратегий, можно начать изучать с базовых понятий и примеров. В этой статье на примере пользовательского индикатора SMA рассматривается взаимодействие технического индикатора с клиентским терминалом MetaTrader 5.