Приведите тестовый пример, который не копирует запрошенные последние бары. Это будет баг либо в терминале, либо в MQL5.
Я не в состоянии пока в силу недостаточного опыта на MQL5.
Тем не менее, я считаю, что отсутствие кода для воспроизведения возможных проблем не отменяет необходимость реализации всего описанного в цитате ниже
(я не критикую ваш код, я просто акцентирую внимание на том, что, по моему мнению, при реализации надежного варианта нужно будет много всего предусмотреть и обработать)
Если копировать только новые бары, то нужно много дополнительных обработок, я думаю.
При ошибке копирования нужно очищать весь ранее скопированный массив. Если добавлено больше одного бара - лучше тоже скопировать все заново. Потому, что лично я не могу быть уверен, что новые бары добавились именно в нужный конец массива (а не подгрузилась история, например).
Плюс все равно нужен хотя бы холостой запрос с каждым тиком что бы поддерживать график в актуальном состоянии. По идее, вызов Bars() для этого графика может обеспечить холостой запрос, но это не точно и нужно проверять (и как раз поможет узнать, добавились ли новые бары).
А если между вызовом Bars и копированием самих котировок придет тик, который сформирует новый бар (привет, паранойя)? Получается, при добавлении бара нужно копировать на 1 бар больше, что бы убедится потом, что все правильно добавили.
Довольно громоздкая хреновина получится с учетом всего этого.
Разница между 1 и 2 скажет сколько баров нужно дописать в массив.
Где тут пять страниц кода?
Артём, в обоих частях есть засады :-) может прийти больше 1-го новых баров (например связь затыкалась), могут прийти некорректные данные, может прийти докачка/исправление истории. Если включая 0-й бар то незабывать копировать 2(!) бара (последний перезаписывать и новый добавлять)
не 5-ть конечно, но довольно кропотливо..Правда не разу не испытывал потребности держать полную копию Rates в отдельном массиве. В базы и эксель синхронизировал, поэтому уверенно - там есть подводные камни
Maxim Kuznetsov #: не 5-ть конечно, но довольно кропотливо
5 много экранов это промышленное решение.
То есть, менеджер котировок, который в OnInit принимает массив нужных таймфреймов, создает экземпляры классов котировок для всех заданных таймфреймов и раздает всем нуждающимся константные указатели на экземпляры необходимых им графиков.
В OnTick этот менеджер сам обновляет все графики (читай классы котировок) и если что пошло не так, то возводит флаг ошибки.
Нуждающиеся чекают этот флаг ошибки и если ошибки нет, то просто спокойно используют котировки с помощью указателей, которые они получили в OnInit.
Я чуть позже может прикреплю здесь пример реализации на mql4, где прямой доступ к графикам и нет необходимости ничего копировать. Я как раз его сейчас ковыряю вношу в него изменения сейчас.
Основной прикол, что даже учитывая прямой доступ в четверке, все равно громоздко получается. А в пятерке пойди еще скопируй правильно
Вот такой эксперт запустить в тестере в режиме по открытию баров (потому что просили именно котировки, в онлайне нужно будет добавить общую проверку на формирование нового бара - здесь для нас это делает тестер), дважды: один раз параметр Batch равный true, второй раз - false.
Вот какие замеры получаем за 2023 год:
Это только по поводу быстродействия.
Насчет засечки последнего скопированного бара - нетрудно это реализовать и не займет ни времени, ни ресурсов (только одну переменную с datetime последнего бара сохранять и отправлять в CopyRates).
Чтобы не менять постоянного направления индексации, лучше подобный тест сделать через класс, где есть геттеры с нужным направлением индексации. Получается чуть быстрее. И более удобно.
class HistoryRates {
private:
MqlRates r[];
datetime last_time;
int begin_from;
public:
int size;
HistoryRates(int start_history = 1) {
size = 0;
begin_from = start_history;
};
~HistoryRates() {};
void NewTick() {
if (size <=0) { // первая закачка
size = CopyRates(_Symbol,_Period,0,begin_from,r);
if (size>0) last_time = r[size-1].time;
} else {
MqlRates r0[1];
int i = CopyRates(_Symbol,_Period,0,1,r0);
if (i==1) if (r0[0].time!=last_time) { // новый бар
r[ArrayResize(r,++size,size<10000?size*2:10000)-1] = r0[0];
last_time =r0[0].time;
} else r[size-1] = r0[0]; // новый тик без нового бара
}
};
void NewTick2() { // более продвинутая, но чуть медленная реализация, не претендующая на конечное использование, т.к. необходимо первоначальную закачку данных реализовывать через таймер.if (size <=0) { // первая закачка
size = CopyRates(_Symbol,_Period,0,begin_from,r);
if (size>0) last_time = r[size-1].time;
} else {
MqlRates r0[];
int i = CopyRates(_Symbol,_Period,last_time,TimeCurrent(),r0);
if (i>0) if (r0[0].time!=last_time)
Print("Дырка в истории. Необходима программная реализация данной ситуации");
if (i==1) r[size-1] = r0[0]; // новый тик без нового бараelseif (i==2) {
r[ArrayResize(r,++size,10000)-1] = r0[1]; // новый бар
last_time =r0[1].time;
} elseif (i>2) { // новые бары
size = ArrayResize(r,size+i, 2*(size+i));
ArrayCopy(r,r0,size-i-1,0);
last_time =r0[i-1].time;
}
}
};
MqlRates GetBarAsSeries(int i) { // Геттер по индексу, когда самый новый бар нулевойif (i>=0 && i<size) return r[size-1-i];
else {
Print("Index error...");
return r[size-1];
}
}
MqlRates GetBarAsNotSeries(int i) { // Геттер по индексу, когда самый старый бар нулевойif (i>=0 && i<size) return r[i];
else {
Print("Index error...");
return r[size-1];
}
}
};
результат через класс:
2024.02.0518:15:58.115 Core 01 EURUSD,H1: history cached from2022.01.0300:002024.02.0518:15:58.115 Core 01 EURUSD,H1 (MetaQuotes-Demo): generating based on real ticks
2024.02.0518:15:58.115 Core 01 EURUSD,H1: testing of Experts\TestActualHistory.ex5 from2023.01.0100:00 to 2024.01.0100:00 started with inputs:
2024.02.0518:15:58.115 Core 01 Batch=false2024.02.0518:15:58.115 Core 01 EURUSD : real ticks begin from2023.01.0200:00:002024.02.0518:15:58.115 Core 01 final balance 10000.00 USD
2024.02.0518:15:58.115 Core 012023.12.2923:58:43 Rates: 62292024.02.0518:15:58.115 Core 012023.12.2923:58:43 Rates fromclass HistoryRates: 124342024.02.0518:15:58.115 Core 01 EURUSD,H1: 21297131 ticks, 6207 bars generated. Test passed in0:00:01.355.
результат через смену индексаций:
2024.02.0518:08:58.959 Core 01 EURUSD,H1: history cached from2022.01.0300:002024.02.0518:08:58.959 Core 01 EURUSD,H1 (MetaQuotes-Demo): generating based on real ticks
2024.02.0518:08:58.959 Core 01 EURUSD,H1: testing of Experts\TestActualHistory.ex5 from2023.01.0100:00 to 2024.01.0100:00 started with inputs:
2024.02.0518:08:58.959 Core 01 Batch=false2024.02.0518:08:58.959 Core 01 EURUSD : real ticks begin from2023.01.0200:00:002024.02.0518:08:58.959 Core 01 final balance 10000.00 USD
2024.02.0518:08:58.959 Core 012023.12.2923:58:43 Rates: 213033592024.02.0518:08:58.959 Core 012023.12.2923:58:43 Rates fromclass HistoryRates: 02024.02.0518:08:58.959 Core 01 EURUSD,H1: 21297131 ticks, 6207 bars generated. Environment synchronized in0:00:00.018. Test passed in0:00:01.930.
хотя нет, скорость одинаковая, т.к. для правильного тестирования на реальных тиках нужно было сделать такую штуку:
Для авторизации и пользования сайтом MQL5.com необходимо разрешить использование файлов Сookie.
Пожалуйста, включите в вашем браузере данную настройку, иначе вы не сможете авторизоваться.
Вы вошли в аккаунт. Двухфакторная аутентификация отключена. Настройте её заново и отсканируйте новый QR-код или продолжите с отключённой двухфакторной аутентификацией.
Оно то все хорошо и правда, но это сферическое копирование в вакууме.
Реализация боевого/надежного варианта добавит ~5 экранов кода и это не сделаешь на коленке.
Опять-же, даже результат выполнения Bars() нужно обрабатывать.
Я не сомневаюсь, что это самое быстрое решение с точки зрения производительности. Но разработать надежный вариант не так уж и легко.
Приведите тестовый пример, который не копирует запрошенные последние бары. Это будет баг либо в терминале, либо в MQL5.
Оно то все хорошо и правда, но это сферическое копирование в вакууме.
Реализация боевого/надежного варианта добавит ~5 экранов кода и это не сделаешь на коленке.
Опять-же, даже результат выполнения Bars() нужно обрабатывать.
Я не сомневаюсь, что это самое быстрое решение с точки зрения производительности. Но разработать надежный вариант не так уж и легко.
У вас есть
У Вас есть
Где тут пять страниц кода?
Приведите тестовый пример, который не копирует запрошенные последние бары. Это будет баг либо в терминале, либо в MQL5.
Я не в состоянии пока в силу недостаточного опыта на MQL5.
Тем не менее, я считаю, что отсутствие кода для воспроизведения возможных проблем не отменяет необходимость реализации всего описанного в цитате ниже
(я не критикую ваш код, я просто акцентирую внимание на том, что, по моему мнению, при реализации надежного варианта нужно будет много всего предусмотреть и обработать)
Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий
Обновление массива Rates с каждым новым баров. Или как добавить в массив только последний бар.
Vladislav Boyko, 2024.01.22 15:57
Если копировать только новые бары, то нужно много дополнительных обработок, я думаю.
При ошибке копирования нужно очищать весь ранее скопированный массив. Если добавлено больше одного бара - лучше тоже скопировать все заново. Потому, что лично я не могу быть уверен, что новые бары добавились именно в нужный конец массива (а не подгрузилась история, например).
Плюс все равно нужен хотя бы холостой запрос с каждым тиком что бы поддерживать график в актуальном состоянии. По идее, вызов Bars() для этого графика может обеспечить холостой запрос, но это не точно и нужно проверять (и как раз поможет узнать, добавились ли новые бары).
А если между вызовом Bars и копированием самих котировок придет тик, который сформирует новый бар (привет, паранойя)? Получается, при добавлении бара нужно копировать на 1 бар больше, что бы убедится потом, что все правильно добавили.
Довольно громоздкая хреновина получится с учетом всего этого.
У вас есть
У Вас есть
Где тут пять страниц кода?
Я, пожалуй, ретируюсь из этого обсуждения потому, что на данный момент не могу в коде показать то, что имею ввиду
Я так и предлагал - запрашивать только новые бары, добавлять в общий массив.
А ваш пример с ошибкой, поэтому вызов просто не работает (не потребляет ни времени, ни памяти):
Вместо этого должно быть:
Спасибо. Вот уж лоханулся, по полной. Но и вы не сразу это заметили. Хоть что-то в оправдание…:)))
У вас есть
У Вас есть
Где тут пять страниц кода?
Артём, в обоих частях есть засады :-) может прийти больше 1-го новых баров (например связь затыкалась), могут прийти некорректные данные, может прийти докачка/исправление истории. Если включая 0-й бар то незабывать копировать 2(!) бара (последний перезаписывать и новый добавлять)
не 5-ть конечно, но довольно кропотливо..Правда не разу не испытывал потребности держать полную копию Rates в отдельном массиве. В базы и эксель синхронизировал, поэтому уверенно - там есть подводные камни
не 5-ть конечно, но довольно кропотливо
5 много экранов это промышленное решение.
То есть, менеджер котировок, который в OnInit принимает массив нужных таймфреймов, создает экземпляры классов котировок для всех заданных таймфреймов и раздает всем нуждающимся константные указатели на экземпляры необходимых им графиков.
В OnTick этот менеджер сам обновляет все графики (читай классы котировок) и если что пошло не так, то возводит флаг ошибки.
Нуждающиеся чекают этот флаг ошибки и если ошибки нет, то просто спокойно используют котировки с помощью указателей, которые они получили в OnInit.
Я чуть позже может прикреплю здесь пример реализации на mql4, где прямой доступ к графикам и нет необходимости ничего копировать. Я как раз его сейчас ковыряю вношу в него изменения сейчас.
Основной прикол, что даже учитывая прямой доступ в четверке, все равно громоздко получается. А в пятерке пойди еще скопируй правильноCopyRates
// по ходу чо та тут шибко заморочились над поиском ответа на простейший вопрос ;)))))
решение в пару строк всего по сути
добавляйте в конец массива один бар, и пользуйтесь
(ArrayResize)
Вот такой эксперт запустить в тестере в режиме по открытию баров (потому что просили именно котировки, в онлайне нужно будет добавить общую проверку на формирование нового бара - здесь для нас это делает тестер), дважды: один раз параметр Batch равный true, второй раз - false.
Вот какие замеры получаем за 2023 год:
Это только по поводу быстродействия.
Насчет засечки последнего скопированного бара - нетрудно это реализовать и не займет ни времени, ни ресурсов (только одну переменную с datetime последнего бара сохранять и отправлять в CopyRates).
Чтобы не менять постоянного направления индексации, лучше подобный тест сделать через класс, где есть геттеры с нужным направлением индексации. Получается чуть быстрее. И более удобно.
результат через класс:
результат через смену индексаций:
хотя нет, скорость одинаковая, т.к. для правильного тестирования на реальных тиках нужно было сделать такую штуку: