Обновление массива Rates с каждым новым баров. Или как добавить в массив только последний бар. - страница 3

 

Если вы такой … как по русски правильно сказать, чтобы не обидеть… Сделайте свой вариант сравнительного теста и покажите результат где добавление в существующий массив типа MqlRates по одному элементу будет быстрей чем выполнение CopyRates всей истории. ИМЕННО столько раз, сколько раз будет добавляться новый бар.

 
Vladislav Boyko #:

Тот комментарий касается только реализации исследования.

У меня лично нет готового алгоритма для подобного копирования только новых баров. Да и вообще, я на mql4 пишу, там доступ к котировкам других графиков осуществляется максимально легко.

Я бы наверное тоже на mql5 просто заново копировал бы штук 1000 баров с каждым тиком, что бы избежать головной боли с синхронизацией при "добавлении новых баров в большой массив". Для большинства советников 1000 последних баров будет вполне достаточно.

А в индикаторах копировать котировки вообще бы не стал. Для текущего тф они есть в параметрах OnCalculate, а мультитаймфрейм индикаторы - штука не благодарная, я бы за это не брался вообще.

 
Vladislav Boyko #:

…Да и вообще, я на mql4 пишу, …

Тогда зачем вы тут?

 
Alexey Viktorov #:

Тогда зачем вы тут?

Та что же вы агрессивный такой?😄

У меня нет желания сраться, я писал конструктивно и по существу.

Здесь я потому, что mql5 меня тоже интересует. Более того, мои посты были полностью по mql5, я ведь мог и умолчать, что я пока на четверке.

 

На самом деле, не так и больно память выделять, относительно остальных вычислений.

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[])
  {
   ulong start = GetMicrosecondCount();
   int i = 0;
   MqlRates p[], r[];
   int n = ArrayResize(p, Bars(_Symbol, PERIOD_CURRENT), 10000);
   ulong temp = GetMicrosecondCount();
   Print("Resizing took ", temp - start);
   start = temp;
   do
    {
     ArraySetAsSeries(p, true);
     CopyRates(_Symbol, PERIOD_CURRENT, i, 1, r);
     p[i] = r[0];
     ArraySetAsSeries(p, false);
     i++;
    }
   while(i < rates_total && !IsStopped());
   Print("Второй замер ", rates_total, " ", GetMicrosecondCount()-start);
   return(rates_total);
  }
Resizing took 54
Второй замер 100000 35755
 
Alexey Viktorov #:


Не сильно изменилось.


Что касается выделенного красным: ТС хочет иметь всю историю для пересчёта на каждом баре. По этому ему нужен не только последний бар, а вся история. Или как минимум не один десяток баров. Вот и получается, либо на каждом баре копировать всю историю, либо копировать один бар и дописывать его в другой массив.

Я так и предлагал - запрашивать только новые бары, добавлять в общий массив.

А ваш пример с ошибкой, поэтому вызов просто не работает (не потребляет ни времени, ни памяти):

CopyRates(_Symbol, PERIOD_CURRENT, rates_total, 0, rates);

Вместо этого должно быть:

CopyRates(_Symbol, PERIOD_CURRENT, 0, rates_total, rates);
 
Stanislav Korotky #:

Я так и предлагал - запрашивать только новые бары, добавлять в общий массив.

А ваш пример с ошибкой, поэтому вызов просто не работает (не потребляет ни времени, ни памяти):

Вместо этого должно быть:

Если копировать только новые бары, то нужно много дополнительных обработок, я думаю.

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

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

А если между вызовом Bars и копированием самих котировок придет тик, который сформирует новый бар (привет, паранойя)? Получается, при добавлении бара нужно копировать на 1 бар больше, что бы убедится потом, что все правильно добавили.

Довольно громоздкая хреновина получится с учетом всего этого.

 

Вот такой эксперт запустить в тестере в режиме по открытию баров (потому что просили именно котировки, в онлайне нужно будет добавить общую проверку на формирование нового бара - здесь для нас это делает тестер), дважды: один раз параметр Batch равный true, второй раз - false.

#define PUSH(A,V) (A[ArrayResize(A, ArrayRange(A, 0) + 1, ArrayRange(A, 0) * 2) - 1] = V)

input bool Batch = true;

int size = 0;

void OnTick()
{
  static bool once = false;
  static MqlRates rates[];
  ResetLastError();
  if(Batch || !once)
  {
    CopyRates(_Symbol, _Period, 0, Bars(_Symbol, _Period), rates);
    ArraySetAsSeries(rates, true);
    once = true;
  }
  else
  {
    static MqlRates r[1];
    CopyRates(_Symbol, _Period, 0, 1, r);
    ArraySetAsSeries(rates, false);
    PUSH(rates, r[0]);
    ArraySetAsSeries(rates, true);
  }
  size = ArraySize(rates);
  // rates[0] - latest bar
  // ... actual processing
}

void OnDeinit(const int)
{
  PrintFormat("Rates: %d", size);
}

Вот какие замеры получаем за 2023 год:

EURUSD,H1: history cached from 2022.01.02 22:00
EURUSD,H1 (Just2Trade-MT5): OHLC bar states generating. OnTick executed on the bar begin only
EURUSD,H1: testing of Experts\Rates.ex5 from 2023.01.01 00:00 to 2024.01.01 00:00 started with inputs:
  Batch=true
final balance 10000.00 USD
2023.12.29 21:59:59   Rates: 12443
EURUSD,H1: 24350 ticks, 6218 bars generated. Environment synchronized in 0:00:00.021. Test passed in 0:00:01.360.
...
EURUSD,H1 (Just2Trade-MT5): OHLC bar states generating. OnTick executed on the bar begin only
EURUSD,H1: testing of Experts\Rates.ex5 from 2023.01.01 00:00 to 2024.01.01 00:00 started with inputs:
  Batch=false
final balance 10000.00 USD
2023.12.29 21:59:59   Rates: 12443
EURUSD,H1: 24350 ticks, 6218 bars generated. Environment synchronized in 0:00:00.019. Test passed in 0:00:00.007.

Это только по поводу быстродействия.

Насчет засечки последнего скопированного бара - нетрудно это реализовать и не займет ни времени, ни ресурсов (только одну переменную с datetime последнего бара сохранять и отправлять в CopyRates).

 
функция добавки в массив, это вроде актуально при вычленении из цикла нужных данных, а подгружать из графика... на новом баре, я показывал, как 1 из 3 терминалов пропускает иногда бары (т.е. копирует на newbar иногда данные прошлого, и надо еще и сравнивать)
 
Stanislav Korotky #:

Вот такой эксперт запустить в тестере в режиме по открытию баров, дважды: один раз параметр Batch равный true, второй раз - false.

Вот какие замеры получаем:

Это только по поводу быстродействия. Насчет засечки последнего скопированного бара - нетрудно это реализовать и не займет ни времени, ни ресурсов (только одну переменную с datetime последнего бара).

Оно то все хорошо и правда, но это сферическое копирование в вакууме.

Stanislav Korotky #:
нетрудно это реализовать и не займет ни времени, ни ресурсов

Реализация боевого/надежного варианта добавит ~5 экранов кода и это не сделаешь на коленке.

Опять-же, даже результат выполнения Bars() нужно обрабатывать.

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

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