Вопросы от начинающих MQL5 MT5 MetaTrader 5 - страница 1331

 
Artyom Trishkin:

Из входных параметров нужно извлечь все подстроки, из них составить наименования символов и соответствующих им таймфреймов.

Далее из этих списков создать объекты-новые бары и указатель на каждый создаваемый объект "Новый бар" поместить в CArrayObj, который объявлен на глобальном уровне.

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

Таймер сделать по своим потребностям - миллисекундный, секундный, минутный - в общем, стой частотой, которую считаете достаточной для реакции на новый бар на нетекущем символе.

Примерно так и делал, но по ArrObj.At(0) не вызываются функции-члены класса...

 
Koldun Zloy:

Смотрите внимательнее. Вы делали не так.

Уже заметил)
Значит, выход - объявлять глобально пустые объекты....
А если заранее неизвестно, сколько их будет ? Просто объявить "с запасом"  ?  :)
P.S. Во встроенной справке не нашел такой способ объявления объектов 

CObj* var1 = NULL;
[Удален]  
Mikhail Tkachev:

Уже заметил)
Значит, выход - объявлять глобально пустые объекты....
А если заранее неизвестно, сколько их будет ? Просто объявить "с запасом"  ?  :)

Положите в CArrayObj.

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

Для того чтобы к ним обращаться просто сделайте преобразование типа.

CIsNewBar* newBar = (CIsNewBar*)ArrayObj.At(0);
newBar.method( parameter );
 
Koldun Zloy:

Положите в CArrayObj.

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

Для того чтобы к ним обращаться просто сделайте преобразование типа.

Спасибо за ответ, вовсе вы не злой)
Теперь все стало ясно)
UPD
Вот такая конструкция тоже работает

CIsNewBar* newBar = ArrayObj.At(0);
newBar.method( parameter )
 
Mikhail Tkachev:

Спасибо за ответ, вовсе вы не злой)
Теперь все стало ясно)
UPD
Вот такая конструкция тоже работает

Обратите внимание на то, что возвращает метод At(). Если вернёт NULL, то вылетите по критической ошибке. Прежде, чем обращаться по указателю к объекту, проверьте его на не NULL

 
Mikhail Tkachev:

Уже заметил)
Значит, выход - объявлять глобально пустые объекты....
А если заранее неизвестно, сколько их будет ? Просто объявить "с запасом"  ?  :)
P.S. Во встроенной справке не нашел такой способ объявления объектов 

Когда-то Артём писал мне этот класс. Я в подробностях объяснить как работает не могу. Но Артём увидев вспомнит и сможет объяснить. В общем вот сам класс

#include <Arrays\ArrayObj.mqh>
/********************************************************************\
|   Класс Новый бар                                                  |
\********************************************************************/
class CNewBar : public CObject
  {
private:
  string            m_symbol;
  ENUM_TIMEFRAMES   m_timeframe;
  datetime          m_time;
  datetime          Time(void);                                       //  Возвращает время нулевого бара
  string            Symbol(void)         { return this.m_symbol;    }
public:
  ENUM_TIMEFRAMES   Timeframe(void)      { return this.m_timeframe; }
  datetime          GetTime(void)        { return this.m_time;      } //  Возвращает время последнего обращения
  bool              IsNewBar(void);                                   //  Основная функция класса

                    CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe);
                   ~CNewBar(void){;}
  };
//+------------------------------------------------------------------+
//|    Конструктор                                                   |
//+------------------------------------------------------------------+
CNewBar::CNewBar(const string symbol,const ENUM_TIMEFRAMES timeframe) : m_time(0)
  {
   this.m_symbol = symbol;
   this.m_timeframe = (timeframe == PERIOD_CURRENT ? Period() : timeframe);
  }
//+------------------------------------------------------------------+
//| CNewBar Time Возвращает время нулевого бара                      |
//+------------------------------------------------------------------+
datetime CNewBar::Time(void)
  {
   datetime array[1], ret;
   ret = CopyTime(this.m_symbol, this.m_timeframe, 0, 1, array) == 1 ? array[0] : 0;
   return(array[0]);
  }
//+------------------------------------------------------------------+
//| CNewBar IsNewBar Основная функция класса                         |
//+------------------------------------------------------------------+
bool CNewBar::IsNewBar(void)
  {
   datetime tm = this.Time();
   if(tm == 0)
      return false;
   if(tm != this.m_time)
     {
      this.m_time = tm;
      return true;
     }
   return false;
  }

И вот цикл создания указателей в OnInit()

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

и в OnTimer()

void OnTimer()
{
 int total = list_new_bar.Total();
 for(int i = 0; i < ArraySize(Rates); i++)
  {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
    continue;
   bool new_bar = nb.IsNewBar();
   if(new_bar)
    {// и дальше………

ArraySize(Rates) это размер массива структур в котором перечислены символы с которыми надо работать.

 
Alexey Viktorov:

Когда-то Артём писал мне этот класс. Я в подробностях объяснить как работает не могу. Но Артём увидев вспомнит и сможет объяснить. В общем вот сам класс

И вот цикл создания указателей в OnInit()

и в OnTimer()

ArraySize(Rates) это размер массива структур в котором перечислены символы с которыми надо работать.

Здесь:

for(int i = 0; i < ArraySize(Rates); i++)

я бы делал до total - просто по причине, что ты с массива Rates читаешь символы (верно?), создаёшь экземпляры класса нового бара и добавляешь их в список.

При любой ошибке добавления, размер списка указателей на экземпляры класса нового бара не будет совпадать с размером массива Rates.

В общем, как-то так наверное:

void OnTimer()
  {
   int total = list_new_bar.Total();
   for(int i = 0; i < total; i++)
   {
   CNewBar* nb = list_new_bar.At(i);
   if(nb == NULL)
      continue;
   if(nb.IsNewBar())
     {// и дальше………

А вот тут нужно тоже проверять на успешность добавления в список:

   for(int i = 0; i < ArraySize(Rates); i++)
     {
       CNewBar* nb = new CNewBar(Rates[i].m_Symbols, timefram);
       if(nb != NULL)
         {
          list_new_bar.Add(nb);
          Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
         }
     }

как-то так:

   for(int i = 0; i < ArraySize(Rates); i++)
     {
      CNewBar *nb = new CNewBar(Rates[i].m_Symbols, timefram);
      if(nb==NULL)
         continue;
      if(!list_new_bar.Add(nb))
        {
         delete nb;
         continue;
        }
      Print(nb.IsNewBar(), " ***** ", Rates[i].m_Symbols, " ***** ", nb.Time());
     }
во избежание утечки памяти при ошибке добавления указателя на новый объект в список
 
Artyom Trishkin:

Здесь:

я бы делал до total - просто по причине, что ты с массива Rates читаешь символы (верно?), создаёшь экземпляры класса нового бара и добавляешь их в список.

При любой ошибке добавления, размер списка указателей на экземпляры класса нового бара не будет совпадать с размером массива Rates.

В общем, как-то так наверное:

А вот тут нужно тоже проверять на успешность добавления в список:

как-то так:

во избежание утечки памяти при ошибке добавления указателя на новый объект в список

Спасибо. Я понял, исправлю на так…:)))

Ненавижу оператор continue; и стараюсь им не пользоваться. Исключительно в безвыходных случаях.

      if(nb==NULL)
         continue;

чем отличается от

      if(nb!=NULL)
       {
       }
Другое дело если при ошибке удалить несостоявшийся указатель… Но и тут можно обойтись без ненавистного мне continue; просто удалив Print(). Он был нужен во время отладки и попытки понять происходящее, а если во время работы произойдёт какая-то ошибка, я по любому не пойму что не так… Мне проще переустановить ОС, чем разобраться в логах.


Раз уж пошёл разговор об этом, расскажи пожалуйста, только не влезая в дебри, чем отличается указатель от переменной класса и что предпочтительней. В подробностях, в таких которые понять сложно я могу в тырнете почитать. Мне достаточно, так сказать, поверхностного понимания…

 
Artyom Trishkin:

Обратите внимание на то, что возвращает метод At(). Если вернёт NULL, то вылетите по критической ошибке. Прежде, чем обращаться по указателю к объекту, проверьте его на не NULL

Артем, спасибо за ценное замечание)

 
Alexey Viktorov:

Спасибо. Я понял, исправлю на так…:)))

Ненавижу оператор continue; и стараюсь им не пользоваться. Исключительно в безвыходных случаях.

чем отличается от


Итерацию цикла не закончит и новую не начнет, а перейдет к следующему Иф. Логика поменяется.