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





Сообщение: 70
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 27.10.18 14:00. Заголовок: Zig-Zag на истории отрисовывается корректно, а в реале не всегда


Написал я индикатор Zig-Zag (после достаточно длительного использования другого). Хотелось, написать самому, что бы научится это делать. К тому же, в том, который я раньше использовал был косяк, который не очень очевиден, на первый взгляд. В нём есть 1 недочёт, но он не критичный. Его я опускаю сейчас. Но самый сложный вопрос, который меня напрягает уже несколько дней это то, что индикатор отрисовывает на истории всё согласно логике и на реале тоже обычно всё так, НО есть места, в которых индикатор ведёт себя странно и не адекватно. Смысл в том, что иногда не обновляются хаи/лоу Zig-Zag'а. Как найти причину? Отладчик в подобных ситуациях не применим т.к. здесь будет писаться огромный пласт данных и такое очень сложно анализировать.
Вот какой момент я обнаружил в тестере:



Код прилагаю. Код читабелньый с комментариями, где они нужны. Единственное, это ещё прилагаю библиотеку TimeSeries, которая должна лежать в папке EnvironmentInfo

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 11 [только новые]







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


hoz пишет:

 цитата:
НО есть места, в которых индикатор ведёт себя странно и не адекватно.


Посмотрел на код бегло, замечая основные моменты.
Сразу скажу, что лучше всего начинать с простого - сделать свой ZZ для текущего ТФ. Вы же сразу взялись за сложное - за MTF индикатор. А MTF-индикаторы - достаточно сложные, когда сталкиваешься с ними впервые.
Наиболее распространенная ошибка, которая появляется при разработке MTF-индикатора, в коде имеется. Это оперирование индексом одного ТФ, когда происходит обработка другого ТФ. Эта ошибка бросается в глаза в функции:

 цитата:
int previousExtremumIndexOtherTF(int i) { // Индекс обрабатываемого бара c таймфрейма i_tf
//---
for (int bar = i + 1; bar < barsTotal(i_tf); bar++) {
if (extremum_price_other_tf_buffer[bar] == EMPTY_VALUE) continue;
return bar;
}
//---
return barsTotal(i_tf) - 1;
}


Вы воспринимаете индекс i как индекс бара старшего ТФ. Так, если индикатор работает на ТФ М15 (как на рисунке), а оперирует данными с ТФ Н1 (как по умолчанию в настроечном параметре), то цикл с итератором bar пробегает по индексам ТФ Н1, но использует индексацию текущего ТФ. Ведь extremum_price_other_tf_buffer - это индикаторный буфер, который, как ни крути, использует нумерацию текущего ТФ.
Поэтому правилом №1 при разработке MTF-индикаторов является использование индикаторныъ буферов только для отображения данных и ни в коем случае - для хранения данных с других ТФ. Для хранения данных других ТФ необходимо использовать свои массивы и структуры, но никак не индикаторные буфера.

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





Сообщение: 71
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 02.11.18 15:20. Заголовок: Scriptong пишет: По..


Scriptong пишет:

 цитата:
Посмотрел на код бегло, замечая основные моменты.
Сразу скажу, что лучше всего начинать с простого - сделать свой ZZ для текущего ТФ. Вы же сразу взялись за сложное - за MTF индикатор. А MTF-индикаторы - достаточно сложные, когда сталкиваешься с ними впервые.


Обычный я написал уже месяц назад за пару дней. Вот он..

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





Сообщение: 73
Зарегистрирован: 30.05.13
Репутация: 0
ссылка на сообщение  Отправлено: 02.11.18 15:29. Заголовок: Scriptong пишет: На..


Scriptong пишет:

 цитата:
Наиболее распространенная ошибка, которая появляется при разработке MTF-индикатора, в коде имеется. Это оперирование индексом одного ТФ, когда происходит обработка другого ТФ. Эта ошибка бросается в глаза в функции:

 цитата:
int previousExtremumIndexOtherTF(int i) { // Индекс обрабатываемого бара c таймфрейма i_tf
//---
for (int bar = i + 1; bar < barsTotal(i_tf); bar++) {
if (extremum_price_other_tf_buffer[bar] == EMPTY_VALUE) continue;
return bar;
}
//---
return barsTotal(i_tf) - 1;
}


Вы воспринимаете индекс i как индекс бара старшего ТФ. Так, если индикатор работает на ТФ М15 (как на рисунке), а оперирует данными с ТФ Н1 (как по умолчанию в настроечном параметре), то цикл с итератором bar пробегает по индексам ТФ Н1, но использует индексацию текущего ТФ. Ведь extremum_price_other_tf_buffer - это индикаторный буфер, который, как ни крути, использует нумерацию текущего ТФ.
Поэтому правилом №1 при разработке MTF-индикаторов является использование индикаторныъ буферов только для отображения данных и ни в коем случае - для хранения данных с других ТФ. Для хранения данных других ТФ необходимо использовать свои массивы и структуры, но никак не индикаторные буфера.



Так я же не для отрисовки это значение запоминаю, а для того, что бы найти предыдущий экстремум на другом ТФ (в данном случае H1). Я уже поправил сверху пару дней назад этот момент:

 цитата:
SetIndexBuffer(1, extremum_price_other_tf_buffer, INDICATOR_CALCULATIONS); // Второй буфер - экстремумы Zig-Zag'а таймфрейма i_tf
ArraySetAsSeries(extremum_price_other_tf_buffer, true);


То что размер массива для хранения данных другого ТФ, который повыше будет иметь размер количества баров на ТФ открытого графика (в моём случает ТФ М15) я понимаю. Но разница какая? Главное что не меньше. Этот массив забьётся данными с 0-го индекса до какого-то индекса (разница количество баров на ТФ М15). Остальные индексы будут иметь дефолтное значение. Но мешать это не должно кака я понимаю.
Последний вариант мультитаймфреймного индикатора вот выложил.

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





Сообщение: 2646
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 07.11.18 12:11. Заголовок: hoz пишет: То что р..


hoz пишет:

 цитата:
То что размер массива для хранения данных другого ТФ, который повыше будет иметь размер количества баров на ТФ открытого графика (в моём случает ТФ М15) я понимаю. Но разница какая?


Так ведь нумерация баров смещается постоянно, несинхронно со смещением баров старшего ТФ. В итоге При поиске индекса бара экстремума получается не тот индекс бара, который нужно. Отсюда и все беды.

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

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





Сообщение: 2645
Зарегистрирован: 03.03.13
Откуда: Украина, Каменское (Днепродзержинск)
Репутация: 3
ссылка на сообщение  Отправлено: 01.11.18 14:17. Заголовок: Кстати, советую не и..


Кстати, советую не использовать библиотеку TimeSeries по двум причинам:
  • В МQL5 уже имеются функции, идентичные функциям MQL4. Речь об i-функциях: iLow, iOpen, iTime и т. д. С ними работать намного проще, чем с CopyXXXX
  • Библиотека не совсем корректная. К примеру, функция barOpenPrice (любая из перезагрузок) может вернуть "мусор" в качестве корректного значения, хотя функция CopyOpen при этом отработала с ошибкой. Это возможно в тех случаях, когда данные заданного бара имеются, но попросту не были скопированы в barsOpenPrice. Функция CopyOpen вернет значение 0 (а не -1, как ожидается в коде), что приведет к возврату неинициализированного значения из barsOpenPrice. Правильный подход - сравнить количество скопированных баров с ожидаемым количеством. Если эти значения не равны, то получаем ошибку.

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





    Сообщение: 2647
    Зарегистрирован: 03.03.13
    Откуда: Украина, Каменское (Днепродзержинск)
    Репутация: 3
    ссылка на сообщение  Отправлено: 07.11.18 12:46. Заголовок: Чтобы было понятнее,..


    Чтобы было понятнее, почему нельзя применять выбранный Вами способ хранения данных о предыдущем экстремуме, рассмотрим конкретную ситуацию:


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

     цитата:
    // На предыдущем баре тенденция отрисовки Zig-Zag'а была восходящей
    if (tendention__other_tf_buffer[i + 1] == TREND_UPWARDS) {
    if (barHighPrice(i, i_tf) >= barHighPrice(i + 1, i_tf)) { // Было обновление максимума
    if (barHighPrice(i, i_tf) >= extremum_price_other_tf_buffer[previousExtremumIndexOtherTF]) {
    if (tendention__other_tf_buffer[previousExtremumIndexOtherTF] == TREND_UPWARDS)
    cleanBuffers(TREND_UPWARDS, previousExtremumIndexOtherTF);
    setBuffers(TREND_UPWARDS, barHighPrice(i, i_tf), i);
    // Draw :: wingdings("extremum_increase_" + (string)i, LOCATION_BELOW, 71, 2, clrBlue, i, 2.5);
    } else {
    setBuffers(TREND_DOWNWARDS, barLowPrice(i, i_tf), i);
    }
    return;
    }
    // Обновления максимума не было, но был пробой минимума предыдущей свечи. Смена направления
    if (barLowPrice(i, i_tf) < barLowPrice(i + 1, i_tf))
    {
    if (i < 10)
    Print("Смена с восх. на нисх. Бар: ", iTime(NULL, i_tf, i), ", пред. экстремум: ", iTime(NULL, i_tf, previousExtremumIndexOtherTF),
    ", high: ", iHigh(NULL, i_tf, previousExtremumIndexOtherTF), ", low: ", iLow(NULL, i_tf, previousExtremumIndexOtherTF), ", extremum: ", extremum_price_other_tf_buffer[previousExtremumIndexOtherTF]);
    setBuffers(TREND_DOWNWARDS, barLowPrice(i, i_tf), i);
    // Draw :: wingdings("UPPEST_EXTREMUM_" + (string)i, LOCATION_ABOVE, 83, 2, clrRed, i, 2.5);
    return;
    }
    }


    Вставил в код логирование значений. Что получилось, видно на рисунке. Вместо ожидаемого нахождения экстремума на баре 2018.09.26 21:00 видим, что экстремум найден на следующем баре, 22:00, там, где его в принципе нет. Также видно, что значение самого экстремума какое-то "мусорное" - 1.31705 вместо ожидаемого 1.31856.

    Для исправления ситуации я бы посоветовал просто запоминать в коде последний найденный экстремум и все (создать специальную структуру). Зачем сохранять все имеющиеся экстремумы? Это лишнее.

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





    Сообщение: 74
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 18.11.18 11:53. Заголовок: Действительно, я при..


    Действительно, я пришёл к такому же выводу. Храня только актуальные данные проще с ними работать. Отдохнул недельку от зиг-зага. Решил продолжить.
    Вот что получилось сейчас.
    По сути, базовая часть уже работает. Т.е. зиг-заг рисует по базовому сценарию. Дальше будет доработка. Но остался 1 интересный момент.
    В коде я задаю пустое значение, по которому нет отрисовки:
    Скрытый текст


    Так вот мне такой вариант не нравится. Хочется сделать, как я обычно, делаю:
    Скрытый текст

    Но если я задаю, что нет отрисовки именно по EMPTY_VALUE, то зиг-заг ломается. Причём, самое интересное, что я нигде в коде не присваиваю в этот буфер 0.0,.. тем не менее, когда 0.0 значение по которому нет отрисовки, то всё корректно.
    Как это понять интересно?

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





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


    hoz пишет:

     цитата:

    PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); // Установка пустого значения буфера extremum_price_buffer, по которому нет отрисовки

    Но если я задаю, что нет отрисовки именно по EMPTY_VALUE, то зиг-заг ломается. Причём, самое интересное, что я нигде в коде не присваиваю в этот буфер 0.0,.. тем не менее, когда 0.0 значение по которому нет отрисовки, то всё корректно.


    Проверить, к сожалению, не могу, т. к. не хватает файлов HOZ_Code\Enums\TrendDirection.mqh и Structures\ZZ_properties.mqh.
    По тому, как сделано сейчас в коде, могу лишь заметить, что имется явное несоответствие между заданным пустым значением (0.0) и тем, чем заполняется буфер индикатора по умолчанию (EMPTY_VALUE). То есть в таком варианте как раз и должно проявляться неправильное поведение индикатора. Ведь значение EMPTY_VALUE им должно восприниматься как корректное значение для отрисовки.
    Обратите внимание на строки 124, 141, 164 и 182. В них буфер принимает значение EMPTY_VALUE, а не 0.

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





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


    Scriptong пишет:

     цитата:
    Обратите внимание на строки 124, 141, 164 и 182. В них буфер принимает значение EMPTY_VALUE, а не 0.


    В том то и абсурдность ситуации. В таком виде всё работает. А если при связывании буфера в OnInit() переопределить пустое значение, по которому не отрисовывается как не 0.0 .. как сейчас и есть, а как EMPTY_VALUE, то индикатор рисует абы что. Вот в чём суть.
    На данный момент имеется такое:
    Скрытый текст

    И всё работает.
    А если сделать так:
    Скрытый текст

    Не работает...
    Вот что странно.

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





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


    hoz пишет:

     цитата:
    Не работает...
    Вот что странно.


    Это не странность. Код работает с данными другого ТФ и при этом как бы игнорирует то, что происходит на текущем ТФ. А происходит следующее.
    При первом запуске индикатор проходит по всей истории старшего и текущего ТФ, заполняя буфер extremum_price_buffer корректными значениями. Затем приходит время нового бара текущего ТФ, но не старшего. Согласно вот этому условию:

     цитата:
    if (lastBarTimeOtherTF == iTime(_Symbol, i_tf, 0))
    return;


    которое расположено в начале функции ZigZag, обработка нового бара игнорируется. То есть в буфер не записывается какое-либо значение. Там остается то, что находится в памяти компьютера, на котором исполняется программа. Там может быть все, что угодно, т. н. "мусор". Чаще всего этот "мусор" равен 0.0. Вот откуда берется нулевое значение. Но так будет не всегда, т. к. это все-таки "мусор". Мораль здесь такова: всегда инициализировать значения переменных. В данном случае - элементов массива-таймсерии. Сам терминал МТ5, в отличие от терминала МТ4, их не инициализирует.

    На скорую руку создал такой вот код, решающий проблему (думаю, можно придумать что-то получше):

     цитата:
    void ZigZag(int limit) {
    //---
    datetime dtOtherTFNullBar = iTime(NULL, i_tf, 0);
    for (int i = 0; iTime(NULL, PERIOD_CURRENT, i) >= dtOtherTFNullBar; ++i)
    extremum_price_buffer[ i ] = EMPTY_VALUE;

    if (lastBarTimeOtherTF == iTime(_Symbol, i_tf, 0))
    return;

    if (limit > 1)
    ZZ.init();

    for (int i = limit; i > 0; i--) {
    if (limit == 1)
    ZZ.barIndex++;
    iterationHandling(i);
    }
    lastBarTimeOtherTF = iTime(_Symbol, i_tf, 0);
    }


    Условие:

     цитата:
    if (limit == 1)


    убрал за ненадобностью, т. к. это контроль за образованием нового бара старшего ТФ, но никак не текущего.

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





    Сообщение: 75
    Зарегистрирован: 30.05.13
    Репутация: 0
    ссылка на сообщение  Отправлено: 19.11.18 12:36. Заголовок: Действительно. Вот в..


    Действительно. Вот всё, что необходимо.

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

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