Запрос истории баров на mql4

 

Здравствуйте, столкнулся с такой проблемой:

Есть советник, который рассчитывает iHigh/iLow по M15. Если он установлен на чарт М15 или же в терминале просто открыт чарт М15, то всё корректно. Если же устанавливаем на любой другой чарт и в терминале нет открытого М15, то расчет происходит некорректно. При чем в тестере проблем не возникает - только при работе в реале. Уже сломал голову что делать :( Я так понимаю нужно как-то запросить историю баров через переменную Bars для M15?

 

Для наглядности кусок кода с которым возникают проблемы (лишнее  поубирал):

int ChannelDataPeriod = 21;

void Channel() {
  
   double   high,
            low;
   
   RefreshRates();
   
   while(ChannelDataPeriod>=0) {
      
      high  = iHigh(NULL,PERIOD_M15,ChannelDataPeriod); 
      low   = iLow(NULL,PERIOD_M15,ChannelDataPeriod); 
   }
}
 
topsecret2102:

Для наглядности кусок кода с которым возникают проблемы (лишнее  поубирал):

Проверяйте, что возвращают функции iHigh и iLow (ссылки на документацию по MQL5, но то же самое справедливо и для MQL4). До тех пор, пока возвращается ошибка, происходит подгрузка данных.

 
Ihor Herasko:

Проверяйте, что возвращают функции iHigh и iLow (ссылки на документацию по MQL5, но то же самое справедливо и для MQL4). До тех пор, пока возвращается ошибка, происходит подгрузка данных.

Спасибо, если всё происходит в цикле while, я правильно понимаю, что нужно сделать так чтобы циклы продолжали работу, пока ошибка не будет исправлена:

int ExamplePeriod = 21;

void Example() {

   while(ExamplePeriod>=0) {
   
      ResetLastError();
      
      high  = iHigh(NULL,PERIOD_M15,ExamplePeriod);
         if(GetLastError()!=0) continue; ///////// Повторяем цикл если ошибка              
      low   = iLow(NULL,PERIOD_M15,ExamplePeriod);
         if(GetLastError()!=0) continue; ///////// Повторяем цикл если ошибка      

      k     = ExamplePeriod-1+ChannelPeriod;
      
      while(k>=ExamplePeriod) {
      
         price=iHigh(NULL,PERIOD_M15,k);
            if(GetLastError()!=0) continue; ///////// Повторяем цикл если ошибка      

         if(high<price) high=price;
         price=iLow(NULL,PERIOD_M15,k);
            if(GetLastError()!=0) continue; ///////// Повторяем цикл если ошибка      

         if(low>price)  low=price;
         
         k--;
      } 
      
      UpBuffer[ExamplePeriod] = high;
      DnBuffer[ExamplePeriod] = low;
      MdBuffer[ExamplePeriod] = (high+low)/2;        
     
   ExamplePeriod--;
   }

}
 
topsecret2102:

Спасибо, если всё происходит в цикле while, я правильно понимаю, что нужно сделать так чтобы циклы продолжали работу, пока ошибка не будет исправлена:

Нет, нужно отдать управление терминалу. Загрузка данных происходит неопределенное время. Поэтому ожидать окончание загрузки нужно либо по приходу нового тика (по запуску OnTick()), либо в таймере (OnTimer()). Я обычно не заморачиваюсь с таймером, но для некоторых задач может потребоваться именно он. К примеру, если рынок закрыт, то следующий OnTick советник получит только с началом сессии.

Также, чтобы не проверять то, что вернула каждая из функций-таймсерий всегда и везде, можно использовать вызов функции IsTFDataReady() в начале OnTick().

 
Ihor Herasko:

Нет, нужно отдать управление терминалу. Загрузка данных происходит неопределенное время. Поэтому ожидать окончание загрузки нужно либо по приходу нового тика (по запуску OnTick()), либо в таймере (OnTimer()). Я обычно не заморачиваюсь с таймером, но для некоторых задач может потребоваться именно он. К примеру, если рынок закрыт, то следующий OnTick советник получит только с началом сессии.

Также, чтобы не проверять то, что вернула каждая из функций-таймсерий всегда и везде, можно использовать вызов функции IsTFDataReady() в начале OnTick().

Вышеописанная функция вызывается только при открытии сделок, а сами сделки открываются не на тиках, а на новых барах.

Тогда получается как-то так?

bool IsTFDataReady()
{
   iTime(NULL, PERIOD_M15, 1);
   return GetLastError() == ERR_NO_ERROR;
}

void  OnTick() {
   
   if(IsTFDataReady() == true)          
   if(NewBar==true) Example();  
}


int ExamplePeriod = 21;

void Example() {

   while(ExamplePeriod>=0) {

      high  = iHigh(NULL,PERIOD_M15,ExamplePeriod);          
      low   = iLow(NULL,PERIOD_M15,ExamplePeriod);
      k     = ExamplePeriod-1+ChannelPeriod;
      
      while(k>=ExamplePeriod) {
      
         price=iHigh(NULL,PERIOD_M15,k);   
         if(high<price) high=price;
         price=iLow(NULL,PERIOD_M15,k);
         if(low>price)  low=price;
         
         k--;
      } 
      
      UpBuffer[ExamplePeriod] = high;
      DnBuffer[ExamplePeriod] = low;
      MdBuffer[ExamplePeriod] = (high+low)/2;        
     
   ExamplePeriod--;
   }

}
 
Ihor Herasko:

Нет, нужно отдать управление терминалу. Загрузка данных происходит неопределенное время. Поэтому ожидать окончание загрузки нужно либо по приходу нового тика (по запуску OnTick()), либо в таймере (OnTimer()). Я обычно не заморачиваюсь с таймером, но для некоторых задач может потребоваться именно он. К примеру, если рынок закрыт, то следующий OnTick советник получит только с началом сессии.

Также, чтобы не проверять то, что вернула каждая из функций-таймсерий всегда и везде, можно использовать вызов функции IsTFDataReady() в начале OnTick().

Или же так:

bool IsTFDataReady()
{
   iTime(NULL, PERIOD_M15, 1);
   return GetLastError() == ERR_NO_ERROR;
}

int ExamplePeriod = 21;

void Example() {

   int check=-1;
   while(check < 1) check = IsTFDataReady();
        
   while(ExamplePeriod>=0) {

      high  = iHigh(NULL,PERIOD_M15,ExamplePeriod);          
      low   = iLow(NULL,PERIOD_M15,ExamplePeriod);
      k     = ExamplePeriod-1+ChannelPeriod;
      
      while(k>=ExamplePeriod) {
      
         price=iHigh(NULL,PERIOD_M15,k);   
         if(high<price) high=price;
         price=iLow(NULL,PERIOD_M15,k);
         if(low>price)  low=price;
         
         k--;
      } 
      
      UpBuffer[ExamplePeriod] = high;
      DnBuffer[ExamplePeriod] = low;
      MdBuffer[ExamplePeriod] = (high+low)/2;        
     
   ExamplePeriod--;
   }

}


Второй вариант:

bool IsTFDataReady(int shift)
{
   iTime(NULL, PERIOD_M15, shift);
   return GetLastError() == ERR_NO_ERROR;
}

int ExamplePeriod = 21;

void Example() {

   int check=-1;
   while(check < 1) check = IsTFDataReady(ExamplePeriod);
        
   while(ExamplePeriod>=0) {

      high  = iHigh(NULL,PERIOD_M15,ExamplePeriod);          
      low   = iLow(NULL,PERIOD_M15,ExamplePeriod);
      k     = ExamplePeriod-1+ChannelPeriod;
      
      while(k>=ExamplePeriod) {
      
         price=iHigh(NULL,PERIOD_M15,k);   
         if(high<price) high=price;
         price=iLow(NULL,PERIOD_M15,k);
         if(low>price)  low=price;
         
         k--;
      } 
      
      UpBuffer[ExamplePeriod] = high;
      DnBuffer[ExamplePeriod] = low;
      MdBuffer[ExamplePeriod] = (high+low)/2;        
     
   ExamplePeriod--;
   }

}


Третий вариант:

bool IsTFDataReady(int shift)
{
   iTime(NULL, PERIOD_M15, shift);
   return GetLastError() == ERR_NO_ERROR;
}

int ExamplePeriod = 21;

void Example() {

   int check=-1;
   while(check < 1) 
        for(int z=0; z<=ExamplePeriod; z++) {
           if(IsTFDataReady(z)==0) break; 
           check = IsTFDataReady(z);
        }
        
   while(ExamplePeriod>=0) {

      high  = iHigh(NULL,PERIOD_M15,ExamplePeriod);          
      low   = iLow(NULL,PERIOD_M15,ExamplePeriod);
      k     = ExamplePeriod-1+ChannelPeriod;
      
      while(k>=ExamplePeriod) {
      
         price=iHigh(NULL,PERIOD_M15,k);   
         if(high<price) high=price;
         price=iLow(NULL,PERIOD_M15,k);
         if(low>price)  low=price;
         
         k--;
      } 
      
      UpBuffer[ExamplePeriod] = high;
      DnBuffer[ExamplePeriod] = low;
      MdBuffer[ExamplePeriod] = (high+low)/2;        
     
   ExamplePeriod--;
   }

}
 
topsecret2102:

Вышеописанная функция вызывается только при открытии сделок, а сами сделки открываются не на тиках, а на новых барах.

Тогда получается как-то так?

На мой взгляд, первый вариант наиболее надежный.

 
Ihor Herasko:

На мой взгляд, первый вариант наиболее надежный.

Спасибо, я пока остановился на этом варианте:

bool IsTFDataReady(int shift)
{
   iTime(NULL, ExamplePeriod, shift);
   return GetLastError() == ERR_NO_ERROR;
}
----------------------------------------------
   for(int z=0; z<=ExamplePeriod; z++) {
      int check=-1;
      while(check < 1) check = IsTFDataReady(PERIOD_M15,z);
   }

----------------------------------------------
цикл расчета

Пару дней потестирую его, а там будет видно :) Все равно исходя из первого варианта мы получаем только предыдущий бар, а мне нужно получить несколько баров...