Форум » Консультации по программированию » MQL4 Zig-Zag не делается мультитаймфреймным » Ответить

MQL4 Zig-Zag не делается мультитаймфреймным

hoz: Я позаимствовал у Игоря Зиг-зага из статьи, которая называлась как-то так... "Идеальный зиг-заг". Привёл в читабельный вид. И хотел было сделать ещё некоторые вещи с ним, как заметил, что у меня не получается сделать этот зиг-заг МТФ. Версия Зиг-зага, которая коректно отображает экстремумы называется ZigZagHighLow.mq4. Версия МТФ Зиг-зага называется ZZ.mq4, Коды прилагаю в сообщению. У второго индикатора имеются вводные параметры: Символ и Таймфрейм. Кроме как замены 3 функции я больше ничего не менял. По сути, должно было, как я понимаю, получить то, что мне нужно. Но не получилось.. В индикаторе ZZ.mq4 используется библиотека-прокладка GetTimeSeriesData.mq4. Она удобно для получения данных из таймсерий. В индикаторе ZZ.mq4 я заменил лишь данные таймсерий т.е. High[index] и High[index + 1], Low[index], Low[index + 1] и Bars, на соответственно методы сегодня написанной библиотеки, которую я проверил уже: getBarHighPrice(index, i_tf, i_instrument), getBarLowPrice(index, i_tf, i_instrument) и getTotalHistoryBars(i_tf, i_instrument). Так вот Зиг-заг рисуется какой-то левый. У меня такое ощущение, что он экстремумы рисует со сдвигом. Но почему вопрос. Ведь я получил количество баров с оответствующего таймфрейма, а так же цены максимальные и минимальные беру тоже с того же таймфрейма. Что не так? Ссылка на имеющийся код

Ответов - 22, стр: 1 2 All

hoz: Я понял, что суть касяка кроется в том, что я произвожу анализ на другом ТФ, а рисовать пытают на индексах другого ТФ, а не открытого графика. Но полностью как-то не улаживается в голове всё. Вот 2 функции я уже поправил: //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Сравнение последнего максимума с новым максимумом | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ void checkHigh(int index) { // найдём индекс бара с непустым значением (экстремумом) int lastNEVIndex = getLastNoEmptyValueIndex(index); if (lastNEVIndex == getTotalHistoryBars(i_tf)) { // ZZBuf[index] = getBarHighPrice(index, i_tf); datetime barOpenTime = getBarOpenTime(index, i_tf); // Время открытия бара на заданном в инпутпараметрах ТФ int barShift = getBarShift(barOpenTime, 0); // Смещение бара на открытом ТФ ZZBuf[barShift] = getBarHighPrice(barShift, 0); return; } if (getBarHighPrice(index, i_tf) > ZZBuf[lastNEVIndex]) { ZZBuf[lastNEVIndex] = EMPTY_VALUE; // ZZBuf[index] = getBarHighPrice(index, i_tf); datetime barOpenTime = getBarOpenTime(index, i_tf); // Время открытия бара на заданном в инпутпараметрах ТФ int barShift = getBarShift(barOpenTime, 0); // Смещение бара на открытом ТФ ZZBuf[barShift] = getBarHighPrice(barShift, 0); } } //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Сравнение последнего минимума с новым минимумом | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ void checkLow(int index) { // найдём индекс бара с непустым значением (экстремумом) int lastNEVIndex = getLastNoEmptyValueIndex(index); if (lastNEVIndex == getTotalHistoryBars(i_tf)) { // ZZBuf[index] = getBarLowPrice(index, i_tf); datetime barOpenTime = getBarOpenTime(index, i_tf); // Время открытия бара на заданном в инпутпараметрах ТФ int barShift = getBarShift(barOpenTime, 0); // Смещение бара на открытом ТФ ZZBuf[barShift] = getBarLowPrice(barShift, 0); return; } if (getBarLowPrice(index, i_tf) < ZZBuf[lastNEVIndex]) { ZZBuf[lastNEVIndex] = EMPTY_VALUE; // ZZBuf[index] = getBarLowPrice(index, i_tf); datetime barOpenTime = getBarOpenTime(index, i_tf); // Время открытия бара на заданном в инпутпараметрах ТФ int barShift = getBarShift(barOpenTime, 0); // Смещение бара на открытом ТФ ZZBuf[barShift] = getBarLowPrice(barShift, 0); } }

Scriptong: Написание MTF-индикаторов - это довольно непростое дело. В обычной жизни можно сравнить с пространственным мышлением. Ведь мозг человека больше привык мыслить двумерно. Тех, кто умеет мыслить трехмерно, не так уж и много (стереометрия мало, кому дается). Поэтому, если программирование еще только осваиваете, то не беритесь за такую сложную задачу. Если же готовы к трудностям, то велкам. Самая главная задача при написании MTF-индикаторов - понять, что нумерация баров на текущем ТФ и на "другом" ТФ - разная. В приведенном коде в этом направлении нет ни одного шага. Нумерации всех баров - от текущего ТФ. Для перевода индексов баров одного ТФ в другой обычно используют функцию iBarShift (тоже нет в коде). Ну и не забывайте, что индикаторные буферы относятся к текущему ТФ. А потому для отображения данных другого ТФ придется сильно попотеть.

hoz: Scriptong пишет: Для перевода индексов баров одного ТФ в другой обычно используют функцию iBarShift (тоже нет в коде) Уже не начинаю. Опыт есть. Просто я залез дальше и вот в таких сложных делах опыта не много. Чутка подвис. Думаю ещё. Индикатор Ваш, поэтому вы как никто другой понимаете как он устроен. В прилагаемом коде должно быть. Я это уже всё учёл. Я же прикрепил ссылку на бибилотеку, там это всё учтено. Вот выложу сюда на свякий случай, чутка переписанный более оптимально: //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Возвращает индекс бара на открытом графика соответствующий времени открытия бара на ТФ i_tf | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ int getLocalBarShift(int index) { datetime barOpenTime = getBarOpenTime(index, i_tf); // Время открытия бара на заданном в инпутпараметрах ТФ return getBarShift(barOpenTime, 0); // Смещение бара на открытом ТФ } Функции getBarOpenTime и getBarShift берутся из библиотеки. Вот их код: // 1.2 Возвращает индекс бара относящегося к определённому времени. ======================================================================= int getBarShift(datetime time, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT, bool exact = false) export { return iBarShift(NULL, timeframe, time, exact); } // 1.7 Возвращает значение времени открытия бара, находящегося на shift баров от текущего бара в историю. ================================= datetime getBarOpenTime(int shift, ENUM_TIMEFRAMES timeframe = PERIOD_CURRENT) export { return iTime(NULL, timeframe, shift); } Поиск последнего максимума получился такой: //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ //| Сравнение последнего максимума с новым максимумом | //+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ void checkHigh(int index) { // найдём индекс бара с непустым значением (экстремумом) int lastNEVIndex = getLastNoEmptyValueIndex(index); int barShift = getLocalBarShift(index); // Смещение бара на открытом ТФ if (lastNEVIndex == getTotalHistoryBars(i_tf)) { // ZZBuf[index] = getBarHighPrice(index, i_tf); ZZBuf[barShift] = getBarHighPrice(index, i_tf); return; } if (getBarHighPrice(index, i_tf) > ZZBuf[lastNEVIndex]) { ZZBuf[lastNEVIndex] = EMPTY_VALUE; // ZZBuf[index] = getBarHighPrice(index, i_tf); ZZBuf[barShift] = getBarHighPrice(index, i_tf); } } Вот код весь, кстати


Scriptong: hoz пишет: Просто я залез дальше и вот в таких сложных делах опыта не много. Чутка подвис. Думаю ещё. Индикатор Ваш, поэтому вы как никто другой понимаете как он устроен. В прилагаемом коде должно быть. Я это уже всё учёл. Я же прикрепил ссылку на бибилотеку, там это всё учтено. Вот выложу сюда на свякий случай, чутка переписанный более оптимально: То, что использована функция iBarShift, еще ничего не дает. Ведь дело не только в ней, а в самом устройстве кода. MTF-индикатор отличается от обычного индикатора намного больше, чем самолет от кареты. Нельзя делать MTF-индикатор на основе обычного индикатора. Получится уродливая конструкция, зачастую неработающая. Для MTF-индикатора нужно строить новую архитектуру. В приведенном коде бросаются в глаза следующие ошибки: Нельзя использовать функцию GetRecalcIndex в том виде, в котором она есть. Ведь снова считаем бары текущего ТФ, а нужно - заданного. В функцию ZigZag передается индекс бара текущего ТФ, а нужно - заданного. Я бы решил эту задачу вот так.

hoz: Я понимаю, что вопрос видимо примитивный и мне за него уже где-то даже стыдно, но, тем не менее. Прямо в методе OnCalculate пишу: static bool b = false; if (!b) { for (int i = 0; i < 150; i++) { Print("g_ZZBuf[ i ] = ", g_ZZBuf[ i ]); b = true; } } Индикатор то рисует зиг-заг верно, а вот принтует у меня таким образом всегда 2147483647. Как такое вообще выходит? Ведь я вижу, что у нас там присваивается этому буферу значени цены на заданном баре, а не 2147483647, коорое означает EMPTY_VALUE

Scriptong: hoz пишет: Прямо в методе OnCalculate пишу: Без полного кода я вряд ли смогу угадать причину. Ведь сразу встает вопрос о том, в каком именно месте OnCalculate все это выводится? P. S. При написании кода на этом форума, чтобы не пропадал в коде индекс i, копируйте последовательность символов [, i, ] с пробелом внутри. Иначе форум воспринимает это за BB-код и не отображает символы.

hoz: Scriptong пишет: Без полного кода я вряд ли смогу угадать причину. Ведь сразу встает вопрос о том, в каком именно месте OnCalculate все это выводится? Полный Вот весь исходный код. Кстати, я там под себя чутка переназвал и добавил буфер времени. Вроде как правильно. Вот его планирую прикрутить и дальше пилить индюк. Много ещё чего нужно сделать. Это ещё только начало. Как допилю обязательно Вам покажу, есс-но как увиижу, что есть подвижки в плане мат. ожидания. Scriptong пишет: P. S. При написании кода на этом форума, чтобы не пропадал в коде индекс i, копируйте последовательность символов [, i, ] с пробелом внутри. Иначе форум воспринимает это за BB-код и не отображает символы. Это я понял уже. Учту.

Scriptong: hoz пишет: Полный Вот весь исходный код. В этом коде видно, что значения индикаторного буфера распечатываются до момента расчета. Поэтому там пусто (EMPTY_VALUE). Такое значение устанавливается в индикаторных буфера МТ4 по умолчанию.

hoz: Scriptong пишет: В этом коде видно, что значения индикаторного буфера распечатываются до момента расчета. Поэтому там пусто (EMPTY_VALUE). Такое значение устанавливается в индикаторных буфера МТ4 по умолчанию. Действительно, простая задача, а я продолбался (( Я, кстати, добавил там буфер времени, но время не показывается. Какая-то причина в этом есть? Вот последний актуальный код. Ещё я заметил, что у вас не используется метод ArraySetAsSeries. Он замеляет выполнение кода? Я к тому, что удобнее, в принципе, при работе с массивами таймсерий работать как с таймсериями. Не критично, но всё-таки. Вот и возник такой вопрос.. И ещё один момент. Метод GetExtremumOnCurrentTF странный. Он же ищет индекс экстремума от текущего до предыдущего бара. Вот мне интересно зачем это вообще нужно? Ведь в прошлой версии зиг-зага, который работал на одном ТФ был метод getLastNoEmptyValueIndex, который искал последний экстремум. Он более очевиден.

Scriptong: hoz пишет: Я, кстати, добавил там буфер времени, но время не показывается. Какая-то причина в этом есть? Причин сразу четыре: В индикаторе разрешено отображение только одного буфера (#property indicator_buffers 1) Нет настроек для отображения второго буфера Сам буфер объявлен как неотображаемый (DRAW_NONE) Непонятно, как возможно отображать время на шкале цены hoz пишет: Ещё я заметил, что у вас не используется метод ArraySetAsSeries В MQL4 эта функция при работе с таймсериями не требуется. Это же не MQL5, в котором таймсерии развернуты по умолчанию. hoz пишет: И ещё один момент. Метод GetExtremumOnCurrentTF странный. Он же ищет индекс экстремума от текущего до предыдущего бара. В заголовке функции описано, что она делает. Описание соответствует коду функции. Поэтому Ваше описание задачи, которую решает функция, некорректно.

hoz: Scriptong пишет: В индикаторе разрешено отображение только одного буфера (#property indicator_buffers 1) Ну так всё верно. Мне и не нужно отображать второй буфер т.е. буфер времени. Он нужен будет лишь для программирования отображения 1-го буфера. Я строку #property indicator_buffers 1 // используется 1 буфер индикатора оставил как есть. Добавил лишь в метод инициализации OnInit() поле: IndicatorBuffers(2); И всё заработало. Scriptong пишет: Нет настроек для отображения второго буфера А зачем отображать время? Что нам это даст? Ведь время это не то, что нужно выводить в кривую. Scriptong пишет: Сам буфер объявлен как неотображаемый (DRAW_NONE) Да, ведь он и не должен оображатся. Я даже не представляю, прямо сейчас, к чему это могло бы быть нужно. Scriptong пишет: Непонятно, как возможно отображать время на шкале цены Мне тоже. Но я же и не задавал.

Scriptong: hoz пишет: Ну так всё верно. Мне и не нужно отображать второй буфер т.е. буфер времени. Вы задали вопрос: Я, кстати, добавил там буфер времени, но время не показывается. Я резонно ответил, что не понимаю, зачем отображать время на шкале цены. Теперь Вы говорите то же самое. Так в чем же тогда заключался вопрос?

hoz: Scriptong пишет: Я резонно ответил, что не понимаю, зачем отображать время на шкале цены. Теперь Вы говорите то же самое. Так в чем же тогда заключался вопрос? Я не верно выразился. Время не принтовалось. Но вопрос уже решил сам, поэтому последнее сообщение удалил)) А вот то, что индикатор торомзит, это уже вопрос..

Scriptong: hoz пишет: А вот то, что индикатор торомзит, это уже вопрос.. У меня не просто тормозит, а намертво виснет. Причина в том, что Вами была изменена логика функции ProcessBar: вынесено определение текущего тренда из блока, отрабатывающего общее отсутствие тренда, в общий блок. В итоге индикатор пропускал все свечи, на которых невозможно было определить новый тренд. Непонятно, зачем это делать, если тренд уже известен. Другое дело, когда тренд неизвестен. Было: ENUM_TREND_DIR eNewTrend = getTrend(barIndex); if (eNewTrend == TREND_DIR_NONE) continue; // Тренд еще не был определен if (stZZProperty.trend == TREND_DIR_NONE) { stZZProperty.setData(eNewTrend, barIndex, (eNewTrend == TREND_DIR_UPWARD)? iHigh(NULL, i_TF, barIndex) : iLow(NULL, i_TF, barIndex), iTime(NULL, i_TF, barIndex)); showOrDeleteExtremum(stZZProperty, stZZProperty.price); continue; } Нужно: // Тренд еще не был определен if (stZZProperty.trend == TREND_DIR_NONE) { ENUM_TREND_DIR eNewTrend = getTrend(barIndex); if (eNewTrend == TREND_DIR_NONE) continue; stZZProperty.setData(eNewTrend, barIndex, (eNewTrend == TREND_DIR_UPWARD)? iHigh(NULL, i_TF, barIndex) : iLow(NULL, i_TF, barIndex), iTime(NULL, i_TF, barIndex)); showOrDeleteExtremum(stZZProperty, stZZProperty.price); continue; }

hoz: Я перенёс цикл из функции ZigZag в функцию processBar т.к. иначе не придумал как реализовать присвоение значений таймсерии буфера времени образования экстремумов. Из-за этой причины видимо у меня сейчас подтормаживает индикатор при первоначальной загрузке графика, смене таймфрейма и тд. Потом всё работает нормально. Как можно понять в чём причина торможения? Вот исходник



полная версия страницы