АвторСообщение





Сообщение: 54
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 08.03.18 15:54. Заголовок: MQL4 Zig-Zag не делается мультитаймфреймным


Я позаимствовал у Игоря Зиг-зага из статьи, которая называлась как-то так... "Идеальный зиг-заг". Привёл в читабельный вид.
И хотел было сделать ещё некоторые вещи с ним, как заметил, что у меня не получается сделать этот зиг-заг МТФ.
Версия Зиг-зага, которая коректно отображает экстремумы называется 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). Так вот Зиг-заг рисуется какой-то левый. У меня такое ощущение, что он экстремумы рисует со сдвигом. Но почему вопрос. Ведь я получил количество баров с оответствующего таймфрейма, а так же цены максимальные и минимальные беру тоже с того же таймфрейма. Что не так?
Ссылка на имеющийся код

Спасибо: 0 
ПрофильЦитата Ответить
Новых ответов нет , стр: 1 2 All [см. все]







Сообщение: 55
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 08.03.18 23:33. Заголовок: Я понял, что суть ка..


Я понял, что суть касяка кроется в том, что я произвожу анализ на другом ТФ, а рисовать пытают на индексах другого ТФ, а не открытого графика. Но полностью как-то не улаживается в голове всё. Вот 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);
}
}

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2585
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 09.03.18 23:26. Заголовок: Написание MTF-индика..


Написание MTF-индикаторов - это довольно непростое дело. В обычной жизни можно сравнить с пространственным мышлением. Ведь мозг человека больше привык мыслить двумерно. Тех, кто умеет мыслить трехмерно, не так уж и много (стереометрия мало, кому дается). Поэтому, если программирование еще только осваиваете, то не беритесь за такую сложную задачу.

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

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 56
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 10.03.18 13:17. Заголовок: Scriptong пишет: Дл..


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);
}
}

Вот код весь, кстати

Спасибо: 0 
ПрофильЦитата Ответить





Сообщение: 2586
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 10.03.18 18:03. Заголовок: hoz пишет: Просто я..


hoz пишет:

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


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

    Я бы решил эту задачу вот так.

  • Спасибо: 1 
    ПрофильЦитата Ответить





    Сообщение: 57
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 21.03.18 02:51. Заголовок: Я понимаю, что вопро..


    Я понимаю, что вопрос видимо примитивный и мне за него уже где-то даже стыдно, но, тем не менее. Прямо в методе 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

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 2591
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 21.03.18 17:30. Заголовок: hoz пишет: Прямо в ..


    hoz пишет:

     цитата:
    Прямо в методе OnCalculate пишу:


    Без полного кода я вряд ли смогу угадать причину. Ведь сразу встает вопрос о том, в каком именно месте OnCalculate все это выводится?

    P. S. При написании кода на этом форума, чтобы не пропадал в коде индекс i, копируйте последовательность символов [, i, ] с пробелом внутри. Иначе форум воспринимает это за BB-код и не отображает символы.

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 58
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 21.03.18 23:15. Заголовок: Scriptong пишет: Бе..


    Scriptong пишет:

     цитата:
    Без полного кода я вряд ли смогу угадать причину. Ведь сразу встает вопрос о том, в каком именно месте OnCalculate все это выводится?


    Полный Вот весь исходный код. Кстати, я там под себя чутка переназвал и добавил буфер времени. Вроде как правильно. Вот его планирую прикрутить и дальше пилить индюк. Много ещё чего нужно сделать. Это ещё только начало. Как допилю обязательно Вам покажу, есс-но как увиижу, что есть подвижки в плане мат. ожидания.
    Scriptong пишет:

     цитата:

    P. S. При написании кода на этом форума, чтобы не пропадал в коде индекс i, копируйте последовательность символов [, i, ] с пробелом внутри. Иначе форум воспринимает это за BB-код и не отображает символы.


    Это я понял уже. Учту.

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 2592
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 22.03.18 10:33. Заголовок: hoz пишет: Полный В..


    hoz пишет:

     цитата:
    Полный Вот весь исходный код.


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


    Спасибо: 1 
    ПрофильЦитата Ответить





    Сообщение: 59
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 22.03.18 17:03. Заголовок: Scriptong пишет: В ..


    Scriptong пишет:

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


    Действительно, простая задача, а я продолбался ((
    Я, кстати, добавил там буфер времени, но время не показывается. Какая-то причина в этом есть? Вот последний актуальный код.

    Ещё я заметил, что у вас не используется метод ArraySetAsSeries. Он замеляет выполнение кода? Я к тому, что удобнее, в принципе, при работе с массивами таймсерий работать как с таймсериями. Не критично, но всё-таки. Вот и возник такой вопрос..

    И ещё один момент. Метод GetExtremumOnCurrentTF странный. Он же ищет индекс экстремума от текущего до предыдущего бара. Вот мне интересно зачем это вообще нужно? Ведь в прошлой версии зиг-зага, который работал на одном ТФ был метод getLastNoEmptyValueIndex, который искал последний экстремум. Он более очевиден.

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 2593
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 27.03.18 20:22. Заголовок: hoz пишет: Я, кстат..


    hoz пишет:

     цитата:
    Я, кстати, добавил там буфер времени, но время не показывается. Какая-то причина в этом есть?


    Причин сразу четыре:
  • В индикаторе разрешено отображение только одного буфера (#property indicator_buffers 1)
  • Нет настроек для отображения второго буфера
  • Сам буфер объявлен как неотображаемый (DRAW_NONE)
  • Непонятно, как возможно отображать время на шкале цены

    hoz пишет:

     цитата:
    Ещё я заметил, что у вас не используется метод ArraySetAsSeries


    В MQL4 эта функция при работе с таймсериями не требуется. Это же не MQL5, в котором таймсерии развернуты по умолчанию.

    hoz пишет:

     цитата:
    И ещё один момент. Метод GetExtremumOnCurrentTF странный. Он же ищет индекс экстремума от текущего до предыдущего бара.


    В заголовке функции описано, что она делает. Описание соответствует коду функции. Поэтому Ваше описание задачи, которую решает функция, некорректно.

  • Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 60
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 28.03.18 16:06. Заголовок: Scriptong пишет: В..


    Scriptong пишет:

     цитата:

    В индикаторе разрешено отображение только одного буфера (#property indicator_buffers 1)


    Ну так всё верно. Мне и не нужно отображать второй буфер т.е. буфер времени. Он нужен будет лишь для программирования отображения 1-го буфера.
    Я строку
    #property indicator_buffers 1 // используется 1 буфер индикатора
    оставил как есть.
    Добавил лишь в метод инициализации OnInit() поле:
    IndicatorBuffers(2);
    И всё заработало.

    Scriptong пишет:

     цитата:

    Нет настроек для отображения второго буфера


    А зачем отображать время? Что нам это даст? Ведь время это не то, что нужно выводить в кривую.

    Scriptong пишет:

     цитата:

    Сам буфер объявлен как неотображаемый (DRAW_NONE)


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

    Scriptong пишет:

     цитата:

    Непонятно, как возможно отображать время на шкале цены


    Мне тоже. Но я же и не задавал.

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 2594
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 02.04.18 21:04. Заголовок: hoz пишет: Ну так в..


    hoz пишет:

     цитата:
    Ну так всё верно. Мне и не нужно отображать второй буфер т.е. буфер времени.


    Вы задали вопрос:

     цитата:
    Я, кстати, добавил там буфер времени, но время не показывается.



    Я резонно ответил, что не понимаю, зачем отображать время на шкале цены. Теперь Вы говорите то же самое. Так в чем же тогда заключался вопрос?

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 63
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 04.04.18 11:42. Заголовок: Scriptong пишет: Я ..


    Scriptong пишет:

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


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

    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 2595
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 04.04.18 15:06. Заголовок: hoz пишет: А вот то..


    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;
    }



    Спасибо: 0 
    ПрофильЦитата Ответить





    Сообщение: 62
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 04.04.18 11:40. Заголовок: Я перенёс цикл из фу..


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

    Спасибо: 0 
    ПрофильЦитата Ответить
    Новых ответов нет , стр: 1 2 All [см. все]
    Ответ:
    1 2 3 4 5 6 7 8 9
    большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

    показывать это сообщение только модераторам
    не делать ссылки активными
    Имя, пароль:      зарегистрироваться    
    Тему читают:
    - участник сейчас на форуме
    - участник вне форума
    Все даты в формате GMT  2 час. Хитов сегодня: 0
    Права: смайлы да, картинки да, шрифты да, голосования нет
    аватары да, автозамена ссылок вкл, премодерация откл, правка нет