Выбивает советник при пустом стакане, почему?

 
Добрый день, друзья. Решил проанализировать стакан с выводом данных в советнике. Но столкнулся с парадоксальным явлением...
При клиринге или еще какой остановке обновления стакана, в советнике воспринимается не тот размер данных, что есть на самом деле.
Как результат выскакивает ошибка не соразмерности массива данных и как следствие выбивание советника.
Вот такая ошибка

Stakan (CLEJ8,M1) array out of range in 'Stakan.mq5' (59,48)

Привожу простейший код, который определяет текущую цену и анализирует объемы заявок стакана
void OnBookEvent(const string &symbol)
  {
//---
   MqlBookInfo priceBook[]; 
   bool getBook=MarketBookGet(symbol,priceBook); 
   if(getBook) 
   { 
     int k=0;
     int size=ArraySize(priceBook);
     ENUM_BOOK_TYPE type1=BOOK_TYPE_BUY,type2=BOOK_TYPE_SELL;
     int i=0;
     for(i=0;i<size;i++) 
     { 
       if(i==0)
       {
         type1=priceBook[i].type;
         if(type1==BOOK_TYPE_SELL) type2=BOOK_TYPE_BUY;
       }
       if(priceBook[i].type==type1 && priceBook[i+1].type==type2)
       {
         k=i;
         break;
       }
     }
     long sellvolume=0,buyvolume=0;
     for(i=k;i>=0;i--) sellvolume+=priceBook[i].volume;
     for(i=k+1;i<size;i++) buyvolume+=priceBook[i].volume;
     Print((string)sellvolume+" Sell "+(string)buyvolume+" Buy");
   } 
  }
//+------------------------------------------------------------------+
Все вроде как правильно, но ошибка...
Подскажите, каким образом это можно устранить.
 

Имхо, стоит логику пересмотреть. Так понимаю, что собираете инфу по объёмам на продажу и покупку? 

Вот эта индексация вызывает скорее всего краш:

   for(i=0;i<size;i++) 
     { 
       if(i==0)
       {
         type1=priceBook[i].type;
         if(type1==BOOK_TYPE_SELL) type2=BOOK_TYPE_BUY;
       }
       if(priceBook[i].type==type1 && priceBook[i+1].type==type2)
       {
         k=i;
         break;
       }
     }

На последнем проходе (где i меньше size на единицу) берёте следующий элемент [i+1], которого нет в природе. А раз массив priceBook[] динамический, то и ошибка возникает при выполнении программы

 
Dennis Kirichenko:

Имхо, стоит логику пересмотреть. Так понимаю, что собираете инфу по объёмам на продажу и покупку? 

Вот эта индексация вызывает скорее всего краш:

На последнем проходе (где i меньше size на единицу) берёте следующий элемент [i+1], которого нет в природе. А раз массив priceBook[] динамический, то и ошибка возникает при выполнении программы

Спасибо за ответ, но к сожалению думаю что не так...
Вся суть в том, что это условие проверяется только до середины стакана и как только оно выполняется, то перебор стакана заканчивается по break и запоминается значение i.

 
Dennis Kirichenko:

Имхо, стоит логику пересмотреть. Так понимаю, что собираете инфу по объёмам на продажу и покупку? 

Вот эта индексация вызывает скорее всего краш:

На последнем проходе (где i меньше size на единицу) берёте следующий элемент [i+1], которого нет в природе. А раз массив priceBook[] динамический, то и ошибка возникает при выполнении программы

Но на всякий случай и это учел

void OnBookEvent(const string &symbol)
  {
//---
   MqlBookInfo priceBook[]; 
   bool getBook=MarketBookGet(symbol,priceBook); 
   if(getBook) 
   { 
     int k=0;
     int size=ArraySize(priceBook);
     ENUM_BOOK_TYPE type1=BOOK_TYPE_BUY,type2=BOOK_TYPE_SELL;
     int i=0;
     for(i=0;i<size;i++) 
     { 
       if(i==0)
       {
         type1=priceBook[i].type;
         if(type1==BOOK_TYPE_SELL) type2=BOOK_TYPE_BUY;
       }
       else if(priceBook[i-1].type==type1 && priceBook[i].type==type2)
       {
         k=i-1;
         break;
       }
     }
     long sellvolume=0,buyvolume=0;
     for(i=k;i>k-9;i--) sellvolume+=priceBook[i].volume;
     for(i=k+1;i<k+1+9;i++) buyvolume+=priceBook[i].volume;
     Print((string)sellvolume+" Sell "+(string)buyvolume+" Buy");
   } 
  }
//+------------------------------------------------------------------+
 

Геннадий, Вам сама программа пишет, где есть ошибка:

array out of range in 'Stakan.mq5' (59,48)

Что у Вас в коде на строке #59?

И потом, имхо, Вы с циклами намудрили. Можно всё намного проще посчитать, в одном цикле. Зачем искать переход с части BOOK_TYPE_BUY на часть BOOK_TYPE_SELL, чтобы потом снова на каждой части запускать свой цикл???  Двойная работа.

 

Проверил Ваш код, как раз сегодня выходной. Получил пустой стакан.

У Вас ошибка тут:

      for(i=k;i>=0;i--) sellvolume+=priceBook[i].volume;

size =0 для массива priceBook[] , и всё равно пытаетесь получить доступ к элементу этого массива. 

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

Как-то так:

      if(size>0)
        {
         long sellvolume=0,buyvolume=0;
         for(i=k;i>=0;i--) sellvolume+=priceBook[i].volume;
         for(i=k+1;i<size;i++) buyvolume+=priceBook[i].volume;
         Print((string)sellvolume+" Sell "+(string)buyvolume+" Buy");
        }
 
Dennis Kirichenko:

Геннадий, Вам сама программа пишет, где есть ошибка:

Что у Вас в коде на строке #59?

И потом, имхо, Вы с циклами намудрили. Можно всё намного проще посчитать, в одном цикле. Зачем искать переход с части BOOK_TYPE_BUY на часть BOOK_TYPE_SELL, чтобы потом снова на каждой части запускать свой цикл???  Двойная работа.

Спасибо за ответ, но что именно намудрил то...как думал так и сделал....есть возможность сделать проще, подскажите, буду при очень благодарен...
Просто ранее ни когда не работал со стаканом, а тут немного приспичило, да и самому интересно получить правильные данные.

Уже вроде как там ошибки нет и пока все работает стабильно, но пока не могу проверить на клиринге.
Код вышел таким

void OnBookEvent(const string &symbol)
  {
//---
   MqlBookInfo priceBook[]; 
   bool getBook=MarketBookGet(symbol,priceBook); 
   if(getBook) 
   { 
     int k=0;
     int size=ArraySize(priceBook);
     ENUM_BOOK_TYPE type1=BOOK_TYPE_BUY,type2=BOOK_TYPE_SELL;
     int i=0;
     for(i=0;i<size;i++) 
     { 
       if(i==0)
       {
         type1=priceBook[i].type;
         if(type1==BOOK_TYPE_SELL) type2=BOOK_TYPE_BUY;
       }
       else if(priceBook[i-1].type==type1 && priceBook[i].type==type2)
       {
         k=i-1;
         break;
       }
     }
     if(k<size-7)
     {
       long sellvolume=0,buyvolume=0;
       string txt="Buy ";
       if(type1==BOOK_TYPE_SELL) txt="Sell ";
       for(i=k;i>k-7 && i>=0;i--)
       {
         if(type1==BOOK_TYPE_BUY) buyvolume+=priceBook[i].volume;
         else sellvolume+=priceBook[i].volume;
       }
       if(type1==BOOK_TYPE_BUY) txt+=(string)buyvolume+" Sell ";
       else txt+=(string)sellvolume+" Buy ";
       for(i=k+1;i<k+8 && i<size;i++)
       {
         if(type2==BOOK_TYPE_BUY) buyvolume+=priceBook[i].volume;
         else sellvolume+=priceBook[i].volume;
       }
       if(type2==BOOK_TYPE_BUY) txt+=(string)buyvolume;
       else txt+=(string)sellvolume;
       Print(txt);
     }
     else Print("BookEvent Empty");
   } 
  }
//+------------------------------------------------------------------+
 
Gennady Mazur:

Спасибо за ответ, но что именно намудрил то...как думал так и сделал....есть возможность сделать проще, подскажите, буду при очень благодарен...

Я Вас спрашивал раньше, ещё раз спрошу. Какая цель Вашего кода, что хотите подсчитать? Вроде ОчевиднО, НО на всякий пожарный...

 
Dennis Kirichenko:

Я Вас спрашивал раньше, ещё раз спрошу. Какая цель Вашего кода, что хотите подсчитать? Вроде ОчевиднО, НО на всякий пожарный...

Мне надо найти переход между Бай и Селл
а затем в разных пропорциях отдельно посчитать заявки с разных сторон
например:
сумму первых 2 Бай и 2 Селл
сумму первых 4 Бай и 4 Селл
сумму первых 7 Бай и 7 Селл
Сейчас я добиваюсь чтобы стакан считывался четко без сбоев, в любой ситуации.
Далее еще хочу получить данные ленты.

 
Dennis Kirichenko:

Я Вас спрашивал раньше, ещё раз спрошу. Какая цель Вашего кода, что хотите подсчитать? Вроде ОчевиднО, НО на всякий пожарный...

В принципе, самое главное, это определить где переход между Бай и Селл...
Конечно, если принять за аксиому что стакан всегда симметричный,
то к можно найти делением размера на 2, но я что то не очень в этом уверен, что так можно и пройдет хорошо.

 
Решил проверить вышесказанное, да, код упростился значительно и цикл всего 1.
Посмотрю как будет работать.
void OnBookEvent(const string &symbol)
  {
//---
   MqlBookInfo priceBook[]; 
   bool getBook=MarketBookGet(symbol,priceBook); 
   if(getBook) 
   { 
     int size=ArraySize(priceBook);
     ENUM_BOOK_TYPE type=BOOK_TYPE_SELL;
     if(size>0) type=priceBook[0].type;
     else return;
     int b=((int)size/2);
     int s=b-1;
     if(b<size-7)
     {
       long sellvolume=0,buyvolume=0;
       for(int i=0;i<7;i++)
       {
         if(type==BOOK_TYPE_SELL)
         {
           sellvolume+=priceBook[s-i].volume;
           buyvolume+=priceBook[b+i].volume;
         }
         else if(type==BOOK_TYPE_BUY)
         {
           buyvolume+=priceBook[s-i].volume;
           sellvolume+=priceBook[b+i].volume;
         }
       }
       string txt="";
       if(type==BOOK_TYPE_SELL) txt="Sell "+(string)sellvolume+" Buy "+(string)buyvolume;
       else if(type==BOOK_TYPE_BUY) txt="Buy "+(string)buyvolume+" Sell "+(string)sellvolume;
       Print(txt);
     }
     else Print("BookEvent Empty");
   }
  }
//+------------------------------------------------------------------+
Причина обращения: