Загадочный биржевой индикатор

 

Ниже приведен сильно упрощенный (ООП полностью отсутствует) индикатор, который показывает проторгованный оборот на основании тиковой биржевой истории

// Индикатор в виде гистограммы показывает проторгованный оборот BUY и SELL

#property indicator_separate_window

#property indicator_buffers 2
#property indicator_plots 2

#property indicator_label1  "TurnOver_BUY"
#property indicator_type1 DRAW_HISTOGRAM
#property indicator_style1 STYLE_SOLID
#property indicator_color1 clrYellow

#property indicator_label2  "TurnOver_SELL"
#property indicator_type2 DRAW_HISTOGRAM
#property indicator_style2 STYLE_SOLID
#property indicator_color2 clrRed

long LastTime = 0;
int Count = 0;

double Buffer0[];
double Buffer1[];

int GetFreshTicks( MqlTick &Ticks[], const uint flags = COPY_TICKS_TRADE, const uint count = 100000 )
{
  int Res = 0;

  MqlTick NewTicks[];
  const int NewAmount = CopyTicks(Symbol(), NewTicks, flags, LastTime, count);

  if ((NewAmount > 0) && (Count < NewAmount))
  {
    Res = ArrayCopy(Ticks, NewTicks, 0, Count);

    // Взяли крайнее время из текущей истории
    LastTime = Ticks[Res - 1].time_msc;
    Count = 1;

    // Находим (Count) в текущей истории количество тиков со временем LastTime
    for (int i = Res - 2; i >= 0; i--)
    {
      if (Ticks[i].time_msc < LastTime)
        break;

      Count++;
    }
  }

  return(Res);
}

// Ширина гистограммы
void SetScale()
{
  const int Width = 9 / (1 << (5 - (int)ChartGetInteger(0, CHART_SCALE)));

  if (Width != PlotIndexGetInteger(0, PLOT_LINE_WIDTH))
  {
    PlotIndexSetInteger(0, PLOT_LINE_WIDTH, Width);
    PlotIndexSetInteger(1, PLOT_LINE_WIDTH, Width);

    ChartRedraw();
  }
}

void OnInit()
{
  SetIndexBuffer(0, Buffer0);
  SetIndexBuffer(1, Buffer1);

  IndicatorSetInteger(INDICATOR_DIGITS, Digits());
}

void OnChartEvent( const int id, const long &lparam, const double &dparam, const string &sparam )
{
  if (id == CHARTEVENT_CHART_CHANGE)
    SetScale();
}

int OnCalculate( const int rates_total,
                 const int prev_calculated,
                 const datetime &time[],
                 const double &open[],
                 const double &high[],
                 const double &low[],
                 const double &close[],
                 const long &tick_volume[],
                 const long &volume[],
                 const int &spread[] )
{
  if (prev_calculated == 0)
  {
    // возьмем тики с начала утренней сессии
    LastTime = (TimeCurrent() - (TimeCurrent() % (24 * 3600))) * 1000;

    Count = 0;
  }

  // Зануляем новые бары
  if (rates_total > prev_calculated)
  {
    ArrayFill(Buffer0, prev_calculated, rates_total - prev_calculated, 0);
    ArrayFill(Buffer1, prev_calculated, rates_total - prev_calculated, 0);
  }

  MqlTick Ticks[];

  // Взяли свеженькие тики
  const int Amount = GetFreshTicks(Ticks);

  if (Amount > 0)
  {
    int Pos;

    const datetime LastTime2 = Ticks[0].time - (Ticks[0].time % PeriodSeconds());

    // Находим бар (Pos), включающий первый свежий тик
    for (Pos = rates_total - 1; Pos >= 0; Pos--)
      if (time[Pos] == LastTime2)
        break;

    if (Pos >= 0)
    {
      int i = 0;

      // Заполняем бары своими тиками
      while ((Pos < rates_total) && (i < Amount))
      {
        const datetime NextTime = time[Pos] + PeriodSeconds();

        while (i < Amount)
        {
          const MqlTick Tick = Ticks[i];

          if (Tick.time >= NextTime)
            break;

          if ((bool)(Tick.flags & TICK_FLAG_BUY))
            Buffer0[Pos] += (double)Tick.volume;
          else if ((bool)(Tick.flags & TICK_FLAG_SELL))
            Buffer1[Pos] -= (double)Tick.volume;

          i++;
        }

        Pos++;
      }
    }
  }

  return(rates_total);
}

Вот такая картинка должна быть

 


Загадочность этого индикатора заключается в области, помеченной зеленым на скрине . В этом месте либо ничего не показывается, либо показываются значения, но с мерцанием на каждом тике.

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

Файлы:
TurnOver.mq5  4 kb
 

а чего тут выяснять - читайте документацию...

если OnCalculate возвращает 0 результат, то индикаторные буферы не отображаются в окне данных, иначе отображаются. Если то так то сяк, то мерцают :-)

 
Maxim Kuznetsov:

а чего тут выяснять - читайте документацию...

если OnCalculate возвращает 0 результат, то индикаторные буферы не отображаются в окне данных, иначе отображаются. Если то так то сяк, то мерцают :-)

Ну если не заметно, повторю
return(rates_total);
 
fxsaber:

Ниже приведен сильно упрощенный (ООП полностью отсутствует) индикатор, который показывает проторгованный оборот на основании тиковой биржевой истории

Вот такая картинка должна быть

 


Загадочность этого индикатора заключается в области, помеченной зеленым на скрине . В этом месте либо ничего не показывается, либо показываются значения, но с мерцанием на каждом тике.

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

Определённая зависимость от количества копируемых тиков. Всё-таки копирование 100000 элементов структуры - это затратная операция. При первом запуске - ещё ладно, ну а вот в процессе работы копировать по нескольку раз в секунду 100000 элементов - это много.
 
Karputov Vladimir:
Определённая зависимость от количества копируемых тиков. Всё-таки копирование 100000 элементов структуры - это затратная операция. При первом запуске - ещё ладно, ну а вот в процессе работы копировать по нескольку раз в секунду 100000 элементов - это много.

Не идет так такого количества копирования на каждом тике. Чаще всего - 1 тик. Редко - несколько десятков. 100 000 - это запас.

Логирование с момента запуска (снизу-вверх)

2016.09.27 18:19:01.675 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:19:01.608 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:19:01.538 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:19:01.473 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:19:01.404 TurnOver (Si-12.16,M1)  CopyTicks_elements = 2, FreshTicks = 1
2016.09.27 18:19:00.403 TurnOver (Si-12.16,M1)  CopyTicks_elements = 2, FreshTicks = 1
2016.09.27 18:19:00.090 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:59.916 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.815 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.748 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.688 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.621 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.553 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.478 TurnOver (Si-12.16,M1)  CopyTicks_elements = 2, FreshTicks = 1
2016.09.27 18:18:58.136 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:58.070 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:57.997 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:57.937 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:57.867 TurnOver (Si-12.16,M1)  CopyTicks_elements = 1, FreshTicks = 0
2016.09.27 18:18:57.805 TurnOver (Si-12.16,M1)  CopyTicks_elements = 52555, FreshTicks = 52550
2016.09.27 18:18:57.734 TurnOver (Si-12.16,M1)  CopyTicks_elements = 100000, FreshTicks = 99995
2016.09.27 18:18:57.661 TurnOver (Si-12.16,M1)  CopyTicks_elements = 100000, FreshTicks = 99998
2016.09.27 18:18:57.598 TurnOver (Si-12.16,M1)  CopyTicks_elements = 100000, FreshTicks = 99999
2016.09.27 18:18:57.530 TurnOver (Si-12.16,M1)  CopyTicks_elements = 100000, FreshTicks = 100000
 
fxsaber:
Ну если не заметно, повторю

не, незаметно... приведён "сильно упрощенный" вариант и кто его знает что в нём упрощенно :-)

посмотри что возвращает OnCalculate при каждом вызове

PS/ вернуть 0 - единственный известный мне документированный способ скрыть буферы из окна данных.

 
Maxim Kuznetsov:

не, незаметно... приведён "сильно упрощенный" вариант и кто его знает что в нём упрощенно :-)

посмотри что возвращает OnCalculate при каждом вызове

PS/ вернуть 0 - единственный известный мне документированный способ скрыть буферы из окна данных.

Давайте без флуда в этой ветке.
 
fxsaber:
Давайте без флуда в этой ветке.

где флуд?

советы по элементарной отладке - проверь сначала якобы очевидное..

самая простая и ясная гипотеза : периодически rates_total(возвращаемое значение из OnCalculate) на выходе получается 0...вполне несложно скинуть в лог его зхачение на входе и на выходе..

 
Maxim Kuznetsov:

где флуд?

советы по элементарной отладке - проверь сначала якобы очевидное..

самая простая и ясная гипотеза : периодически rates_total(возвращаемое значение из OnCalculate) на выходе получается 0...вполне несложно скинуть в лог его зхачение на входе и на выходе..

Это было проверено в первую очередь. И еще десяток других проверок
fxsaber:

Потратил много часов на выяснение причин - тщетно.

Индикатор - реальная техническая загадка. Он очень короткий, чтобы потратить минимум времени на его понимание. Только запустив можно, действительно, увидеть, что ведет он себя не так, как должен (запрограммирован). Предполагаю, что дело в CopyTicks. Но это только на уровне догадок.
 
Как вариант - уйти от CopyTicks и заполнять индикаторный буфер из генератора случайных чисел. Думаю моргание пропадёт.
 
Karputov Vladimir:
Как вариант - уйти от CopyTicks и заполнять индикаторный буфер из генератора случайных чисел. Думаю моргание пропадёт.
Пробовал - моргание исчезало. Но в причинах не разобрался. Не хочется думать, что это очередной баг.
Причина обращения: