Проверка нового бара для нескольких тайм-фреймов

 
Возможно у кого есть простые идеи.
Надо проверять на открытие нового бара, но ... надо чтобы это была отдельная функция или метод класса и чтобы ее можно было применить несколько раз подряд для разных периодов.
Сейчас использую такое.
bool isNewPeriod(const string symbol, const int bars = 1, const ENUM_TIMEFRAMES period = PERIOD_CURRENT)
{
            datetime open = getLastServerTime();
            static datetime _openTime = open;
            int range = int(open) - int(_openTime);

            if (range >= PeriodSeconds(period) * bars)
            {
                return bool(_openTime = open);
            }
            
            return false;
}
Проблема здесь в том, что при двойном вызове, вызов с младшим периодом всегда будет передвигать последнюю известную дату вперед, поэтому повторный вызов никогда не вернет true.
// Single call for M1

isNewPeriod(Symbol(), 1, PERIOD_M1);  //  works

// Single call for D1

isNewPeriod(Symbol(), 1, PERIOD_D1);  //  works

// Multiple calls for M1, H1, D1

isNewPeriod(Symbol(), 1, PERIOD_M1);  //  works
isNewPeriod(Symbol(), 1, PERIOD_H1);  //  always false
isNewPeriod(Symbol(), 1, PERIOD_D1);  //  always false
 
Andy Sanders:
Возможно у кого есть простые идеи.
Надо проверять на открытие нового бара, но ... надо чтобы это была отдельная функция или метод класса и чтобы ее можно было применить несколько раз подряд для разных периодов.
Сейчас использую такое.
Проблема здесь в том, что при двойном вызове, вызов с младшим периодом всегда будет передвигать последнюю известную дату вперед, поэтому повторный вызов никогда не вернет true.

Вот посмотрите

Обработчик события "новый бар"
Обработчик события "новый бар"
  • 2010.10.04
  • Konstantin Gruzdev
  • www.mql5.com
Язык программирования MQL5 позволяет решать задачи на совершенно новом уровне. Даже те задачи, которые уже вроде имеют решения, благодаря объектно-ориентированному программированию могут подняться на качественно новый уровень. В данной статье специально взят простой пример проверки появления нового бара на графике, который был преобразован в достаточно мощный и универсальный инструмент. Какой? Читайте в статье.
 
Andy Sanders:
Возможно у кого есть простые идеи.
Надо проверять на открытие нового бара, но ... надо чтобы это была отдельная функция или метод класса и чтобы ее можно было применить несколько раз подряд для разных периодов.
Сейчас использую такое.
Проблема здесь в том, что при двойном вызове, вызов с младшим периодом всегда будет передвигать последнюю известную дату вперед, поэтому повторный вызов никогда не вернет true.

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

class CNewBar
{
protected:
  MqlRates newBarRates[];
public:
 bool newBar();
 bool newBar(ENUM_TIMEFRAMES timeframe, datetime & tOld);
};/********************************************************************/

bool CNewBar::newBar()
{
 static datetime timeLastBar;
  if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, newBarRates) < 0)
   return(false);
  bool ret = timeLastBar != newBarRates[0].time;
   if(ret)
    timeLastBar = newBarRates[0].time;
   return(ret);
}/********************************************************************/

bool CNewBar::newBar(ENUM_TIMEFRAMES timeframe, datetime & tOld)
{
  if(CopyRates(_Symbol, timeframe, 0, 1, newBarRates) < 0)
   return(false);
    datetime tNew = newBarRates[0].time;
   bool ret = tOld != tNew;
   if(ret)
    tOld = tNew;
   return(ret);
}/********************************************************************/
 

bool IsNewBar(int Number, string symbol, int timeframe)
{
    //---+
    datetime Time2_;
    int Size = Number + 1;
    static datetime Time2[];  
    if(ArrayRange(Time2, 0) < Size)
    if(ArrayResize(Time2, Size) < Size)
    {
        if(TerminalInfoString(TERMINAL_LANGUAGE) == "Russian") Print("IsNewBar(): Не удалось изменить размеры буфера Time2[]!!!");
        else Print("IsNewBar(): Unable to change the size of the buffer Time2[]!!!");
        PlaySound("alert.wav");   
        return(false);
    }
    //----
    Time2_ = iTime(symbol, timeframe, 2);
    if(Time2_ == 0) return(false);    
    if(Time2_ != Time2[Number])
    {
        Time2[Number] = Time2_;
        return(true);
    }
    //----
    return(false);        
    //---+
}


 
Andy Sanders:
Возможно у кого есть простые идеи.
Надо проверять на открытие нового бара, но ... надо чтобы это была отдельная функция или метод класса и чтобы ее можно было применить несколько раз подряд для разных периодов.
Сейчас использую такое.
Проблема здесь в том, что при двойном вызове, вызов с младшим периодом всегда будет передвигать последнюю известную дату вперед, поэтому повторный вызов никогда не вернет true.

за сохраните вы результат функции и используйте его сколько вам надо раз в коде, чего мудрить то?

 
Mikhail Sergeev:

да, тоже так подумал, пришлось запоминать массив последних баров, самое универсальное и неказистое, для МТ5 так

datetime _openTime[];  //  class property

bool isNewPeriod(const string symbol, const int bars = 1, const int index = 0, const ENUM_TIMEFRAMES period = PERIOD_CURRENT)
{
    datetime open = (datetime) SeriesInfoInteger(symbol, period, SERIES_LASTBAR_DATE);

    if (ArraySize(_openTime) < index + 1)
    {
        ArrayResize(_openTime, index + 1);
    }

    int range = int(open) - int(_openTime[index]);

    if (range >= PeriodSeconds(period) * bars)
    {
        _openTime[index] = open;
        return true;
    }
   
    return false;
}

bool isM1 = isNewPeriod(Symbol(), 1, 0, PERIOD_M1);
bool isM5 = isNewPeriod(Symbol(), 1, 1, PERIOD_M5);
        
if (isM1) Print("### M1");
if (isM5) Print("### M5");

P. S. По остальным предложениям : вариант с передачей дат в качестве параметра не подходит, автор статьи в первом комменте сам же это и признает в конце, т.к. метод может быть вызван по таймеру или при мультивалютных тиках (индикатор Spy - Груздева), в таком случае взять Open Time нам неоткуда, а каждый раз копировать CopyTime() в основном коде глупо и делает метод isNewBar() бесполезным, потому что каждый новый бар вычисляется, опять же, в основном коде, а не в методе :)
 
Andy Sanders:

да, тоже так подумал, пришлось запоминать массив последних баров, самое универсальное и неказистое, для МТ5 так

P. S. По остальным предложениям : вариант с передачей дат в качестве параметра не подходит, автор статьи в первом комменте сам же это и признает в конце, т.к. метод может быть вызван по таймеру или при мультивалютных тиках (индикатор Spy - Груздева), в таком случае взять Open Time нам неоткуда, а каждый раз копировать CopyTime() в основном коде глупо и делает метод isNewBar() бесполезным, потому что каждый новый бар вычисляется, опять же, в основном коде, а не в методе :)

попробуйте такой вариант.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CNevBar
  {
private:
   datetime          curbar;
   datetime          lastbar;
public:
                     CNevBar();
                    ~CNevBar();
   bool              bar(string symbol,ENUM_TIMEFRAMES period);
  };
//+------------------------------------------------------------------+
void CNevBar::CNevBar()
  {

  }
//+------------------------------------------------------------------+
void CNevBar::~CNevBar(void)
  {

  }
//+------------------------------------------------------------------+
bool CNevBar:: bar(string symbol,ENUM_TIMEFRAMES period)
  {
   curbar=(datetime) SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE);
   if(lastbar==0)lastbar=(datetime)SeriesInfoInteger(symbol,period,SERIES_LASTBAR_DATE);
   if(lastbar!=curbar)
     {
      lastbar=curbar;
      return(true);
     }
   return(false);
  }

int test=0;
CNevBar newbar;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---

   test=5;
   Print(__FUNCTION__,": test = ",test);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   if(newbar.bar(_Symbol,PERIOD_CURRENT))
     {
      test=10;
      Print(__FUNCTION__,": test = ",test);
      OnInit();
     }
  }
//+------------------------------------------------------------------+
....
Причина обращения: