Я тоже сломал себе голову с этой синхронизацией. Проблем намного больше, чем кажется.
Более или менее рабочая версия — запуск таймера в ините, проверка и подгрузка истории в таймере (но только через какое-то время после запуска, иначе гарантированно в клинч войдет!), и перерисовка всех буферов при этой самой подгрузке и при prev_calculated == 0.
Сам вызов ОнКалкулейт сделать не сложно:
void OnTimer() { //--- Не пытаемся подгрузить историю сразу после запуска, чтобы не подвесить терминал static datetime launch_time = 0; if ( launch_time <= 0 ) launch_time = TimeLocal(); if ( TimeLocal() - launch_time < 10 ) return; //--- Получаем самую раннюю дату среди всех инструемнтов datetime prevStartTime = newStartTime; newStartTime = RefreshStartTime(); if ( newStartTime < prevStartTime ) { Print( "Deeper history have been loaded (", prevStartTime, " -> ", newStartTime, ")..." ); double p[]; OnCalculate( LastRatesTotal, 0, 0, p ); } } int OnCalculate (const int rates_total, const int prev_calculated, const int begin, const double& price[] ) { LastRatesTotal = rates_total; if ( LastRatesTotal > TerminalInfoInteger( TERMINAL_MAXBARS ) ) LastRatesTotal = TerminalInfoInteger( TERMINAL_MAXBARS );
Еще с недавнего времени rates_total может оказаться больше кол-ва баров на графике. Разработчики на форуме на это не ответили (в СД не писал).
И, несмотря на все эти хитрости, при старте терминала бывают случаи, когда индикаторы не могут рассчитаться (грузят ядро процессора, но ничего не отображают). Проявляется, когда запущено несколько копий, каждая из которых использует историю одного или нескольких совпадающих инструментов.
Sergey Savinkin:
Индикатор запускается и пытается получить данные с большего таймфрейма того же символа. Я пока не поднимаю тему получения хэндлов индикаторов. Нужно хотя бы получить историю функциями Bars, iBarsShift и т.д.
Как только rates_total положительный, сразу старшие ТФ доступны для работы через соответствующий пересчет текущих.
Я тоже сломал себе голову с этой синхронизацией. Проблем намного больше, чем кажется.
Более или менее рабочая версия — запуск таймера в ините, проверка и подгрузка истории в таймере (но только через какое-то время после запуска, иначе гарантированно в клинч войдет!), и перерисовка всех буферов при этой самой подгрузке и при prev_calculated == 0.
Сам вызов ОнКалкулейт сделать не сложно:
Еще с недавнего времени rates_total может оказаться больше кол-ва баров на графике. Разработчики на форуме на это не ответили (в СД не писал).
И, несмотря на все эти хитрости, при старте терминала бывают случаи, когда индикаторы не могут рассчитаться (грузят ядро процессора, но ничего не отображают). Проявляется, когда запущено несколько копий, каждая из которых использует историю одного или нескольких совпадающих инструментов.
Спасибо, но не понятно, какие параметры передавать в OnCalculate. Вы передаете пустой массив p[]. Чем он заполнится в процедуре? Могу сам проверить, но спросить быстрее. ))) И если вызывается вторая форма OnCalculate с бОльшим количеством параметров, их также можно пустыми массивами передать?
попытался добавить макс. комментов в коде, работает как часы, использую для синхронизации нескольких инструментов, если индикатор запущен в выходные дни
пока не видел мультивалютных / мультитаймфреймных индикаторов от MQ, поэтому скорей всего с их стороны это проблемой не считается
int iStart = 1; double Buffer1[]; double Buffer2[]; void OnInit() { if (MQLInfoInteger(MQL_TESTER) == 0) // tester loads all data properly, do not call timer in testing mode { EventSetMillisecondTimer(1000); } } void OnTimer() { if (sync() > 0) // timer will be called only for weekends and holidays { EventKillTimer(); } } int OnCalculate(const int bars, const int counted, const int start, const double &price[]) { if (iStart == 0) // execute this code once, when indicator is loaded { iStart = 1; ZeroMemory(Buffer1); ZeroMemory(Buffer2); return bars; } if (bars != counted) // if new bar has come, but we're still waiting for syncing, keep indicator updated with previous value { Buffer1[0] = Buffer1[1]; Buffer2[0] = Buffer2[1]; } if (sync() > 0) { // draw indicator's data } return bars; } int sync() { int M1 = CopyRates(Symbol(), PERIOD_M1, ...); int D1 = CopyRates(Symbol(), PERIOD_D1, ...); int D1External = CopyRates("AMZN", PERIOD_D1, ...); if (...) // if M1 < 1 or D1 < 0, stop and wait for the next tick { return 0; // failed, wait for next tick } return 1; // synchronized successfully, draw indicator data }
3. сразу за этим вызовом будет вызов sync() из таймера, и он будет вызываться до тех пор, пока данные не подгрузятся
- голосов: 9
- 2016.11.28
- XXX
- www.mql5.com
Спасибо, но не понятно, какие параметры передавать в OnCalculate. Вы передаете пустой массив p[]. Чем он заполнится в процедуре? Могу сам проверить, но спросить быстрее. ))) И если вызывается вторая форма OnCalculate с бОльшим количеством параметров, их также можно пустыми массивами передать?
Да, у меня вариант, в котором встроенные массивы не используются.
Если они нужны, то нужно хранить и поддерживать в актуальном состоянии свои копии таких массивов.
1. рискну предположить, что либо не вызывается ChartRedraw() и не видно изменений
2. либо по одному из синхронизируемых инструментов запрашивается больше баров, чем есть в истории, например, в РобоФХ индекс S&P < 500 баров, а в FXChoice > 1000
есть код, который синхронизирует по наименьшему количеству баров из всех выбранных инструментов
struct SSets { string name; MqlTick ticks[]; MqlRates rates[]; }; int getSyncQuotes( SSets &series[], const int position = 0, const int count = 0, ENUM_TIMEFRAMES period = PERIOD_CURRENT) { int indexes[]; int items = 10000; // can be replaced with TERMINAL_MAXBARS - 1 int size = ArraySize(series); SSets sources[]; ArrayResize(sources, size); ArrayResize(indexes, size); ZeroMemory(indexes); for (int k = 0; k < size; k++) { indexes[k] = 0; items = MathMin(items, CopyRates(series[k].name, period, position, count, sources[k].rates)); // if EURUSD = 1K bars, and GBPUSD = 2K bars, cut them both to 1K if (items < 1) { Print( "Synchronization : " + series[k].name + ", " + "Position : " + IntegerToString(position) + ", " + "Depth : " + IntegerToString(count)); return 0; } } for (int k = 0; k < size; k++) { ArraySetAsSeries(series[k].rates, true); ArraySetAsSeries(sources[k].rates, true); ArrayResize(series[k].rates, items); ArrayResize(sources[k].rates, items); } for (int n = 0; n < items; n++) { datetime pointTime = 0; for (int k = 0; k < size; k++) { pointTime = MathMax(pointTime, sources[k].rates[n].time); } for (int k = 0; k < size; k++) { MqlRates currentRate = sources[k].rates[indexes[k]]; if (currentRate.time >= pointTime) { indexes[k]++; } series[k].rates[n] = currentRate; series[k].rates[n].time = pointTime; } } return items; }
попытался добавить макс. комментов в коде, работает как часы, использую для синхронизации нескольких инструментов, если индикатор запущен в выходные дни
Спасибо за код, попробую у себя.
Если не затруднит, ответьте еще на вопрос: проверяли ли поведение при загрузке терминала с несколькими запущенными индикаторами, которые используют одни и те же чужие тайм-серии для расчетов?
1. рискну предположить, что либо не вызывается ChartRedraw() и не видно изменений
2. либо по одному из синхронизируемых инструментов запрашивается больше баров, чем есть в истории, например, в РобоФХ индекс S&P < 500 баров, а в FXChoice > 1000
есть код, который синхронизирует по наименьшему количеству баров из всех выбранных инструментов
У меня аналогичный код, только вместо CopyRates я использую iBars (а в более ранних версиях - SeriesInfoInteger( SERIES_FIRSTDATE )).
Не спасало.
Проблема еще в том, что ошибка возникает не стабильно.
Я пробовал обнаружить причины ее возникновения, но не смог (удалял кэши тайм-серий, просто ждал произвольное время перед загрузкой терминала, запускал индикаторы на М1 или наоборот - на старших ТФ).
Проблема еще в том, что ошибка возникает не стабильно.
Я пробовал обнаружить причины ее возникновения, но не смог (удалял кэши тайм-серий, просто ждал произвольное время перед загрузкой терминала, запускал индикаторы на М1 или наоборот - на старших ТФ).
только что запустил приаттаченный Movings.ex5
1. добавил две копии индикатора на чарт AUDUSD - рынок основного чарта открыт
- EURUSD,GBPUSD,EURGBP - рынок открыт
- BA,AMZN,TSLA,NFLX - рынок акций закрыт
2. второй чарт TSLA с одной копией индикатора - рынок основного чарта закрыт
- SPY,UVXY - рынок акций закрыт
при открытиии / закрытиии терминала все подгружется корректно
при накидывании новых копий индикатора с любыми комбинациями на уже открытые чарты - корректно
при попытке сменить символ первого чарта на другой, которого нет в обзоре рынка, через Enter, индикаторы выдали ошибку выхода за границы массива ... где-то не проверяю на ArraySize(IndBuffer)
вобщем, можно допилить больше проверок, но лень :)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Проблема синхронизации в ИНДИКАТОРЕ данных с других таймфреймов на МТ5 обсуждалась давно и много. Я изучил документацию, прочитал все, что смог найти на форуме, но ответа на свой вопрос не нашел.
Заранее спасибо.