Пропуски баров на графике

 

Рисую показания тренда по нескольким инструментам (мультивалютный индикатор) и получаю на графике пропуски баров. Выглядит это так:


Кто-нибудь сталкивался с такими несуразностями? Может есть идеи и предложения по устранению?
Жёлтую линию рисует индикаторный буфер в который в начале цикла расчёта индикатора вносится значение:

Buf_OUT[li_Bar] = 0.0;

А затем, в процессе расчёта, это значение изменяется. Стоило ожидать наличие жёлтой линии на всех барах. Ан НЕТ!!!

 
пользуй функцию типа iBarShift( беря значение ближайшего бара к текущему....
 
Aleksander:
пользуй функцию типа iBarShift( беря значение ближайшего бара к текущему....
Если бы всё было так просто!...
Вот цикл расчётов:
    for (li_Bar = Limit - 1; li_Bar >= 0; li_Bar--)
    {
        ld_Trend = 0.0; Buf_UPHigh[li_Bar] = 0.0; Buf_UP[li_Bar] = 0.0; Buf_OUT[li_Bar] = 0.0;
        ld_delta_Trend = 0.0; Buf_DWLow[li_Bar] = 0.0; Buf_DW[li_Bar] = 0.0;
        Time_Bar = Time[li_Bar];
        for (li_SMB = 0; li_SMB < cnt_SMB[2]; li_SMB++)
        {
            //---- Суммируем показания индикатора по LONG-корзине
            if (cnt_SMB[0] > 0 && li_SMB < cnt_SMB[0])
            {
                li_Bar_ind = iBarShift (Sym_LONG[li_SMB], Period(), Time_Bar);
                ld_SuperTrend = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind);
                ld_SuperTrend_1 = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind + 1);
                ld_SuperTrend_2 = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind + 2);
                ld_Trend += IIFd ((ld_SuperTrend > ld_SuperTrend_1 && ld_SuperTrend_1 >= ld_SuperTrend_2), 1,
                IIFd ((ld_SuperTrend == ld_SuperTrend_1), 0, -1));
            }
            //---- Суммируем показания индикатора по SHORT-корзине
            if (cnt_SMB[1] > 0 && li_SMB < cnt_SMB[1])
            {
                li_Bar_ind = iBarShift (Sym_SHORT[li_SMB], Period(), Time_Bar);
                ld_SuperTrend = iCustom (Sym_SHORT[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind);
                ld_SuperTrend_1 = iCustom (Sym_SHORT[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind + 1);
                ld_SuperTrend_2 = iCustom (Sym_SHORT[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar_ind + 2);
                ld_Trend += IIFd ((ld_SuperTrend < ld_SuperTrend_1 && ld_SuperTrend_1 <= ld_SuperTrend_2), 1,
                IIFd ((ld_SuperTrend == ld_SuperTrend_1), 0, -1));
            }
        }
        Buf_OUT[li_Bar] = ld_Trend;
        if (ld_Trend >= 0)
        {
            if (ld_Trend > (cnt_SMB[0] + cnt_SMB[1]) / 2)
            {Buf_UPHigh[li_Bar] = ld_Trend;}
            else
            {Buf_UP[li_Bar] = ld_Trend;}
        }
        else
        {
            if (MathAbs (ld_Trend) > (cnt_SMB[0] + cnt_SMB[1]) / 2)
            {Buf_DWLow[li_Bar] = ld_Trend;}
            else
            {Buf_DW[li_Bar] = ld_Trend;}
        }
    }
Это был следующий ход моей мысли после возникновения данной несуразицы. А сначала я использовал номер бара текущего графика для расчёта показаний на других инструментах.
 
Дай весь код, а то будем гадать...
 
alsu:
Дай весь код, а то будем гадать...
Результат отрабатывает именно этот код, а много кода - чужого кода, отбивает желание вообще его (чужой код) смотреть.
 
Aleksander:
пользуй функцию типа iBarShift( беря значение ближайшего бара к текущему....


Для мультивалютников это обычное дело. Я тоже так делаю. Это позволяет построить индикатор, при отсутствии баров, на основе "последней известной цены". Отсутствие баров бывает по нескольким поводам:

1. история на сервере ДЦ существует, но она еще не закачана;

2. история на сервере ДЦ отсутствует:

2.1 дыра в истории;

2.2 отсутствие баров вследствие низкой ликвидности (характерно для М1, М5, иногда М15).

п. 1 лечится пересчетом окна индикатора приемлемых размеров (со временем история докачивается);

п. 2.2 может быть разрешен на основе "последней известной цены";

п. 2.1 не лечится (диагностируется только при отсутствии подряд "существенного" числа баров )

В общем, основная идея - пересчет окна индикатора приемлемых размеров (со временем история докачивается)

 

Мне для мультивалютного анализа очень надо было решить эту проблему на все возможные случаи.

Привожу решение, которое использовал. Снабдил комментариями, если что-то непонятно, спрашивайте. Работает на 100% и даже в режиме визуального тестирования.

// Возвращает цену символа по заданному времени
double GetPrice( string Symb, int time )
{
  double Price;

  Price = iClose(Symb, Period(), iBarShift(Symb, Period(), time));

  return(Price);
}

// Возвращает следующее за CurrTime время, для которого есть цена.
// В массиве Symbols названия нужных символов.
// AmountSymbols - их количество.
int GetNextTime( int CurrTime )
{
  static int Pos[MAX_AMOUNTSYMBOLS];
  int i, MinTime, Tmp = -1;

  // Pos[i] содержит следующий номер бара, со временем больше CurrTime
  for (i = 0; i < AmountSymbols; i++)
  {
    Pos[i] = iBarShift(Symbols[i], Period(), CurrTime) - 1;

    if (Pos[i] >= 0)
      Tmp = i;
  }

  // Если все Pos[i] оказались отрицательными, выходим. Т.к. мы дошли до крайних записей в исторической базе.
  if (Tmp < 0)
    return(Time[0]);

  MinTime = iTime(Symbols[Tmp], Period(), Pos[Tmp]);

  i = Tmp - 1;

  // Среди всех Pos[i] ищем наименьшее время.
  while (i >= 0)
  {
    if (Pos[i] >= 0)
    {
      Tmp = iTime(Symbols[i], Period(), Pos[i]);

      if (Tmp < MinTime)
        MinTime = Tmp;
    }

    i--;
  }

  // Найденное наименьшее время и есть ближайшее известное время за CurrTime в исторической базе.
  return(MinTime);
}

// Заполняем матрицу так, чтобы в каждой строке были синхронизированные цены со времени StartTime до Time[0].
void GetBaseMatrix()
{
  int i, CurrTime = StartTime;

  MatrixRows = 0;

  while (CurrTime < Time[0])
  {
    // Заполняем строку матрицы ценами, соответствующими времени CurrTime
    for (i = 0; i < AmountSymbols; i++)
      BaseMatrix[i][MatrixRows] = 1000 * MathLog(GetPrice(Symbols[i], CurrTime));

    // Запомнили значение времени для соответствующей строки матрицы.
    Times[MatrixRows] = CurrTime;

    MatrixRows++;

    // Получили следующее время из исторической базы
    CurrTime = GetNextTime(CurrTime);
  }

  return;
}
 
Mislaid:


Для мультивалютников это обычное дело. Я тоже так делаю. Это позволяет построить индикатор, при отсутствии баров, на основе "последней известной цены". Отсутствие баров бывает по нескольким поводам:

1. история на сервере ДЦ существует, но она еще не закачана;

2. история на сервере ДЦ отсутствует:

2.1 дыра в истории;

2.2 отсутствие баров вследствие низкой ликвидности (характерно для М1, М5, иногда М15).

п. 1 лечится пересчетом окна индикатора приемлемых размеров (со временем история докачивается);

п. 2.2 может быть разрешен на основе "последней известной цены";

п. 2.1 не лечится (диагностируется только при отсутствии подряд "существенного" числа баров )

В общем, основная идея - пересчет окна индикатора приемлемых размеров (со временем история докачивается)

Я для читабельности убрал из кода проверку на отсутствие истории:

            //---- Суммируем показания индикатора по LONG-корзине
            if (cnt_SMB[0] > 0 && li_SMB < cnt_SMB[0])
            {
                li_Bar_ind = iBarShift (Sym_LONG[li_SMB], Period(), Time_Bar);
                ld_SuperTrend = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar);
                ld_SuperTrend_1 = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar + 1);
                ld_SuperTrend_2 = iCustom (Sym_LONG[li_SMB], Period(), "VininI_Supertrend", iCCI_Period, iATR_Period, 0, li_Bar + 2);
                ld_Trend += IIFd ((ld_SuperTrend > ld_SuperTrend_1 && ld_SuperTrend_1 >= ld_SuperTrend_2), 1,
                IIFd ((ld_SuperTrend == ld_SuperTrend_1), 0, -1));
                ld_delta_Trend += (ld_SuperTrend - ld_SuperTrend_2) / gd_PointLB[li_SMB];
                if (Time_Bar != iTime (Sym_LONG[li_SMB], Period(), li_Bar_ind) && li_Bar < 1000)
                {Print ("Не совпадение баров: Bar[", li_Bar, " - ", TS_DM (Time_Bar), "] != Bar[", li_Bar_ind, " - ", TS_DM (iTime (Sym_LONG[li_SMB], Period(), li_Bar_ind)), "] - ", Sym_LONG[li_SMB], " !!!");}
            }

на 1000 последних баров на дырки в истории жаловаться не приходится (на этом TF). У меня стоит инструмент, который в реальном времени подкачивает историю по всему "Обзору рынка". Если бара нет - то значение будет "не адекватным" с точки зрения правильности получаемой на выходе информации. НО результат в виде (в данном случае) жёлтой линии на графике ДОЛЖЕН БЫТЬ, а он ОТСУТСТВУЕТ!!!
Ещё есть идеи?

 

у тебя не реализовано свойство

exact - Возвращаемое значение если бар не найден. FALSE - iBarShift возвращает ближайший.



int iBarShift( string symbol, int timeframe, datetime time, bool exact=false)
Поиск бара по времени. Функция возвращает смещение бара, которому принадлежит указанное время. Если для указанного времени бар отсутствует ("дыра" в истории), то функция возвращает, в зависимости от параметра exact, -1 или смещение ближайшего бара.
Параметры:
symbol - Символьное имя инструмента. NULL означает текущий символ.
timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.
time - Значение времени для поиска.
exact - Возвращаемое значение если бар не найден. FALSE - iBarShift возвращает ближайший. TRUE - iBarShift возвращает -1.
Пример:
 
TarasBY:

Я для читабельности убрал из кода проверку на отсутствие истории:

на 1000 последних баров на дырки в истории жаловаться не приходится (на этом TF). У меня стоит инструмент, который в реальном времени подкачивает историю по всему "Обзору рынка". Если бара нет - то значение будет "не адекватным" с точки зрения правильности получаемой на выходе информации. НО результат в виде (в данном случае) жёлтой линии на графике ДОЛЖЕН БЫТЬ, а он ОТСУТСТВУЕТ!!!
Ещё есть идеи?


Идея - переписать индикатор VininI_Supertrend, он то, точно, не расчитан на отсутствие баров в истории. Наличие символа в обзоре рынка влияет на закачку истории по символу, если только открыт график по инструменту, или вы ее запрашиваете через одну из функций:

iClose, iHigh, iLow, iOpen

Я пользуюсь в мультивалютниках только индикаторами в окнах фиксированного размера, поэтому на текущем таймфрейме достаточно корректно работает такая функция

//+------------------------------------------------------------------+
//| Функция LastKnownPrice() возвращает последнюю известную цену     |
//| по инструменту SymbolName на момент времени cTime                |
//| Вызываемые процедуры: нет                                        |
//| Вызывается из                                                    |
//+------------------------------------------------------------------+
double  LastKnownPrice( string SymbolName, datetime cTime)
{
   int   shift;
   
   shift = iBarShift( SymbolName, 0, cTime, false);
   if (iTime(SymbolName, 0, shift) > cTime) shift++;
   return( iClose(SymbolName, 0, shift) );
}
//+-- LastKnownPrice() END ------------------------------------------+

 
Aleksander:

у тебя не реализовано свойство

exact - Возвращаемое значение если бар не найден. FALSE - iBarShift возвращает ближайший.



int iBarShift( string symbol, int timeframe, datetime time, bool exact=false)
Поиск бара по времени. Функция возвращает смещение бара, которому принадлежит указанное время. Если для указанного времени бар отсутствует ("дыра" в истории), то функция возвращает, в зависимости от параметра exact, -1 или смещение ближайшего бара.
Параметры:
symbol - Символьное имя инструмента. NULL означает текущий символ.
timeframe - Период. Может быть одним из периодов графика. 0 означает период текущего графика.
time - Значение времени для поиска.
exact - Возвращаемое значение если бар не найден. FALSE - iBarShift возвращает ближайший. TRUE - iBarShift возвращает -1.
Пример:

Ты вот на эту проверку обратил внимание:

if (Time_Bar != iTime (Sym_LONG[li_SMB], Period(), li_Bar_ind) && li_Bar < 1000)
                {Print ("Не совпадение баров: Bar[", li_Bar, " - ", TS_DM (Time_Bar), "] != Bar[", li_Bar_ind, " - ", TS_DM (iTime (Sym_LONG[li_SMB], Period(), li_Bar_ind)), "] - ", Sym_LONG[li_SMB], " !!!");}
            

В логе записи несоответствия отстутствуют.
Давай возьмём вариант, когда номер бара берётся с графика чарта. Мне (пока - на данный момент) не существенно правильно у меня производится конечный расчёт или нет. Расёт (пусть даже не правильный) присутствует не на всех барах! ПОЧЕМУ???

Причина обращения: