Ошибки, баги, вопросы - страница 3662

 
Georgiy Merts #:

Да, всё верно.

Обращаю внимание разработчиков, ошибка.

При запуске индикатора при работающем MT5 - все проходит штатно, и без ошибок.

Если оставить индикатор на графике, и перезапустить МТ5, то в момент вызова функции Init() индикатора - таймсерии ещё не готовы:

  • Запрос функции SymbolIsSynchronized() выдаёт false. 
  • Запрос функции SeriesInfoInteger(strSymbolFullName,etTimeframe,SERIES_BARS_COUNT,lResult) выдаёт false, при этом GetLastError() возвращает 4401 (ERR_HISTORY_NOT_FOUND). 

Лично я пока обошёл проблему повторной инициализацией при первом вызове OnCalculate(). Если во время OnInit() не получилось инициализироваться, то я ещё раз проделываю все нужные действия в первом вызове OnCalculate - в этом случае и символ синхронизирован, и количество баров выдаётся верно.

проверка баров всегда и была в OnCalculate

на достаточность для расчета и т.д.

 
lynxntech #:

проверка баров всегда и была в OnCalculate

на достаточность для расчета и т.д.

Хм... А если их количество уже нужно в OnInit() ?

Необходимо выполнить инициализационные действия, в зависимости от того, достаточно ли имеется баров. Более того, некоторые подготовительные действия могут потребоваться со значениями цен баров. А у нас, выходит, баров-то ещё и нет... 

Если запускать индикатор на работающем МТ5 - всё проходит нормально. Проблемы возникают только если терминал перезапускается. Если при OnInit() символ может быть ещё не синхронизирован, и бары могут быть ещё недоступны - какой смысл в инициализации вобще? 

 
Georgiy Merts #:

Хм... А если их количество уже нужно в OnInit() ?

Необходимо выполнить инициализационные действия, в зависимости от того, достаточно ли имеется баров. Более того, некоторые подготовительные действия могут потребоваться со значениями цен баров. А у нас, выходит, баров-то ещё и нет... 

Если запускать индикатор на работающем МТ5 - всё проходит нормально. Проблемы возникают только если терминал перезапускается. Если при OnInit() символ может быть ещё не синхронизирован, и бары могут быть ещё недоступны - какой смысл в инициализации вобще? 

В mt5, если мне не изменяет память, так было всегда.
А смысл инициализации - подготовить буферы и, возможно, значения каких-либо переменных.
 

в чем разница у этих функций?

не могу понять для чего первая понадобилась

SeriesInfoInteger(strSymbolName,etTimeframe,SERIES_BARS_COUNT,lResult)

int  Bars( 
   string           symbol_name,     // имя символа 
   ENUM_TIMEFRAMES  timeframe        // периоду 
   );

на достаточность баров обычно Bars 

если нужно проверить расчет другого индикатора(хендла), то 

int  BarsCalculated(
   int       indicator_handle,     // handle индикатора
   );



Примечание

Функция полезна в тех случаях, когда необходимо получить данные индикатора сразу после его создания (получения хэндла индикатора).

пробелы не убираются
 
Sergey Gridnev #:
В mt5, если мне не изменяет память, так было всегда.
А смысл инициализации - подготовить буферы и, возможно, значения каких-либо переменных.

Вот-вот, и для подготовки, скажем, мне нужны дополнительные буфферы, и если число баров недостаточно - то смысла отображать вобще нет. Я запрашиваю в инициализации бары, а мне выдаётся, что их нет... Соответственно, и инициализироваться нечем. 

Пока обошёл эту проблему, инициализируясь на первом пришедшем тике. Но, по-моему, это неправильно, тем более, что в МТ4 - было всё в порядке в этом плане, в функции Init() все данные подготовлены. 

 
lynxntech #:
если нужно проверить расчет другого индикатора(хендла), то 

А если нужны бары по другому символу? 

Лично я устаревшей Bars() без параметров вобще не пользуюсь, поскольку непонятно внутри кода, к каким барам она относится. 

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

 
Georgiy Merts #:

А если нужны бары по другому символу? 

Лично я устаревшей Bars() без параметров вобще не пользуюсь, поскольку непонятно внутри кода, к каким барам она относится. 

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

у Bars и есть выбор символа и TF

в штатных индикаторах всегда в OnCalculated идет проверка, только вместо Bars, rates_total

 if(rates_total<3)
      return(0);
Bars(_Symbol,_Period); 
 
Georgiy Merts #:

Вот-вот, и для подготовки, скажем, мне нужны дополнительные буфферы, и если число баров недостаточно - то смысла отображать вобще нет. Я запрашиваю в инициализации бары, а мне выдаётся, что их нет... Соответственно, и инициализироваться нечем. 

Пока обошёл эту проблему, инициализируясь на первом пришедшем тике. Но, по-моему, это неправильно, тем более, что в МТ4 - было всё в порядке в этом плане, в функции Init() все данные подготовлены. 

Если это работает, значит это правильно. Было бы не правильно, оно бы не работало. Логично?

Вот взял первый попавшийся индикатор, перенёс OnInit()  в OnCalculate().

Работает. Значит всё норм)))

#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   3
//--- plot ATR
#property indicator_label1  "ATR"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDarkViolet
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot MAOnATR
#property indicator_label2  "MAOnATR"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGold
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot MAOnATR2
#property indicator_label3  "MAOnATR2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

#include <MovingAverages.mqh>
//--- input parameters
input int                  Inp_ATR_ma_period             = 21;             // ATR: averaging period
input int                  Inp_MA_ma_period              = 55;             // MA1: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method              = MODE_SMMA;      // MA1: smoothing type
input int                  Inp_MA_ma_period2             = 14;             // MA2: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method2             = MODE_SMA;       // MA2: smoothing type
//--- indicator buffers
double ATRBuffer[];
double MAOnATRBuffer[];
double MAOnATRBuffer2[], Buffer1[];
int handle_iATR = 0;                         // variable for storing the handle of the iATR indicator
bool start = true;
//+------------------------------------------------------------------+
int OnInit()
  {
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
  {
   if(start)
     {
      SetIndexBuffer(0, ATRBuffer, INDICATOR_DATA);
      SetIndexBuffer(1, MAOnATRBuffer, INDICATOR_DATA);
      SetIndexBuffer(2, MAOnATRBuffer2, INDICATOR_DATA);

      PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
      PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
      PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, 0.0);
      IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
      PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, Inp_ATR_ma_period);

      string short_name = StringFormat("MAOnATR(%d; %d; %d)", Inp_ATR_ma_period, Inp_MA_ma_period, Inp_MA_ma_period2);
      IndicatorSetString(INDICATOR_SHORTNAME, short_name);

      handle_iATR = iATR(_Symbol, PERIOD_CURRENT, Inp_ATR_ma_period);
      if(handle_iATR == INVALID_HANDLE)
        {
         Print(StringFormat("Failed to create handle of the iATR indicator for the symbol %s/%s, error code %d",
                            Symbol(), EnumToString(Period()), GetLastError()));
         return(INIT_FAILED);
        }
      start = false;
     }
     
   int to_copy, bar = 1;
   if(prev_calculated > rates_total || prev_calculated <= 0)
     {
      ArrayInitialize(ATRBuffer, 0);
      ArrayInitialize(MAOnATRBuffer, 0);
      ArrayInitialize(MAOnATRBuffer2, 0);
      to_copy = rates_total;
     }
   else
      to_copy = rates_total - prev_calculated + 1;

   if(BarsCalculated(handle_iATR) < rates_total)
      return(0);

   if(CopyBuffer(handle_iATR, 0, 0, to_copy, ATRBuffer) < 0)
     {
      Print(StringFormat("Failed to copy, error code %d", GetLastError()));
      return(0);
     }

   IsMaCalc(Inp_MA_ma_method, rates_total, prev_calculated, Inp_ATR_ma_period - 1,  Inp_MA_ma_period, ATRBuffer, MAOnATRBuffer);
   IsMaCalc(Inp_MA_ma_method2, rates_total, prev_calculated, Inp_ATR_ma_period - 1,  Inp_MA_ma_period2, ATRBuffer, MAOnATRBuffer2);

   return(rates_total);
  }
//+------------------------------------------------------------------+
void IsMaCalc(const int ma_method, const int rates_total, const int prev_calculated, const int begin, const int period, const double& price[], double& buffer[])
  {
   switch(ma_method)
     {
      case  MODE_EMA :
         ExponentialMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer);
         break;
      case MODE_SMMA :
         SmoothedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer);
         break;
      case MODE_LWMA :
         LinearWeightedMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer);
         break;
      default :
         SimpleMAOnBuffer(rates_total, prev_calculated, begin, period, price, buffer);
     }
  }
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(handle_iATR != INVALID_HANDLE)
      IndicatorRelease(handle_iATR);
  }
//+------------------------------------------------------------------+
 

вырезка из DeepSeek

// Способ 1 - простой
int bars1 = Bars(_Symbol, _Period);

// Способ 2 - через SeriesInfoInteger (эквивалент)
long bars2;
if(SeriesInfoInteger(_Symbol, _Period, SERIES_BARS_COUNT, bars2))
{
    // bars2 будет содержать то же значение, что и bars1
}
Вывод: Для обычных задач используйте Bars(_Symbol, _Period) - это более современный и удобный способ. SeriesInfoInteger() оставьте для специфических случаев.

это должно быть в OnCalculated

Bars можно на rates_total для текущего символа и тф заменить

 
Aleksandr Slavskii #:

Если это работает, значит это правильно. Было бы не правильно, оно бы не работало. Логично?

НЕТ.

Когда заложен нос - люди дышат ртом, и это у них вполне себе получается. Однако, рот человека, всё-таки, не предназначен для дыхания, и дышать им в обычных условиях неправильно. 

Также и тут - начальные проверки и инициализация должны проводиться в Init(). Если при этом таймсерии могут быть недоступны - это должно быть, как минимум, чётко указанно в описании события Init для индикаторов. В справке ничего этого нет сказано. В описании порядка доступа к таймсериям - указано, что бары могут быть несформированы, и для этого надо использовать скрипт с функцией Sleep(), которая не должна вызываться в индикаторах. 

Наконец важно и то, что если индикатор запускается на графике - то всё проходит нормально, и количество баров благополучно выдаётся в функции Init(). Если же терминал перезапущен - то в функции Init() количество баров нулевое. На мой взгляд, тут надо либо привести к общему поведению, когда в функции Init() таймсерии доступны (или недоступны), ну, либо, хотя бы указать в справке - что поведение не определено, и запрашивать число баров в этой функции нельзя. 

Вывод: Для обычных задач используйте Bars(_Symbol, _Period) - это более современный и удобный способ. SeriesInfoInteger() оставьте для специфических случаев.

DeepSeek, конечно, авторитет... Особенно, учитывая, что функция Bars() появилась РАНЬШЕ, чем функция SeriesInfoInteger() (если не ошибаюсь, ещё в МТ3).

lynxntech #:
у Bars и есть выбор символа и TF

Ну, так я ведь и сказал - "без параметров". 

В обычных случаях разницы нет, однако, когда надо в одном месте получать разные данные, и в том числе количество баров - предпочтительнее SeriesInfoInteger(), а не отдельные функции, среди которых будет и Bars()