А давайте разберём это zig-zag!

hoz

Активный участник
Решил я освоить индикатор zig-zag. По-сколько дефолтовый вариант данного индюка включённого в стандартную поставку с МТ4 я не особо въехал, я погуглив нашёл один из вариантов с комментами...Начал его штудировать, но тут тоже возникли нюансы. Выношу первый вариант данного zig-zag'а, который строится канкретно по закрытию. Попутно у меня есть огромное желание разобрать его по полочкам. Да я думаю это будет полезно не только мне, а многим присуствующим!

Вот данный код:

PHP:
#property copyright "Scriptong"
#property link "http://autograf.dp.ua"

#property indicator_chart_window                   // Индикатор выводится в окне графика
#property indicator_buffers 1                      // используется 1 буфер индикатора
#property indicator_color1 Blue                    // Цвет отображения данных 1-го буфера

#property indicator_width1 1                       // Толщина линий 1-го буфера

double ZZBuf[];                                    // Буфер экстремумов
double UpDnBuf[];                                  // Буфер признака текущего тренда
                                                   
#define NO_TREND        0                          // Нет тренда
#define TREND_UP        1                          // Восходящий тренд
#define TREND_DOWN     -1                          // Нисходящий тренд      

//+-------------------------------------------------------------------------------------+
//| Custom indicator initialization function                                            |
//+-------------------------------------------------------------------------------------+
int init()
{
   IndicatorBuffers(2);
// - 1 - == Проверка корректности значений настроечных параметров индикатора ============
   string name = WindowExpertName();
// - 1 - == Окончание блока =============================================================

// - 2 - == Связывание буферов с индексами, определение стилей ==========================
   SetIndexBuffer(0, ZZBuf);                       // Первый буфер - экстремумы
   SetIndexStyle(0, DRAW_SECTION);                 // В виде линии между непустыми..
                                                   // ..значениями

   SetIndexBuffer(1, UpDnBuf);                     // Второй буфер - признак тренда
   SetIndexStyle(1, DRAW_NONE);                    // Не отображается
// - 2 - == Окончание блока =============================================================

   return(0);
}
  
//+-------------------------------------------------------------------------------------+
//| Custom indicator deinitialization function                                          |
//+-------------------------------------------------------------------------------------+
int deinit()
{
   return(0);
}
  
//+-------------------------------------------------------------------------------------+
//| Определение индекса бара, с которого необходимо производить перерасчет              |
//+-------------------------------------------------------------------------------------+
int GetRecalcIndex()
{
   int counted_bars = IndicatorCounted();
   if (counted_bars == 0)                          // Кол-во посчитанных баров - 0. Будут
   {                                               // ..пересчитаны все буфера с самого..
      ArrayInitialize(ZZBuf, EMPTY_VALUE);         // ..начала. Очистка буферов
      ArrayInitialize(UpDnBuf, 0);
      return(Bars - 2);                            // Начинаем со второго бара истории
   }
   return(Bars - counted_bars - 1);                // Начинаем с нового бара
}

//+-------------------------------------------------------------------------------------+
//| Определение тенденции по соотношению указанной и предыдущей свечей                  |
//+-------------------------------------------------------------------------------------+
int GetTrend(int index)
{
// - 1 - == Закрытие новой свечи выше максимума предыдущей ==============================
   if (Close[index] > High[index+1])
      return(TREND_UP);                            // Рост
// - 1 - == Окончание блока =============================================================

// - 2 - == Закрытие новой свечи ниже минимума предыдущей ===============================
   if (Close[index] < Low[index+1])
      return(TREND_DOWN);                          // Падение
// - 2 - == Окончание блока =============================================================

   return(NO_TREND);                               // Если свеча не пробита - нет тренда
}
//+-------------------------------------------------------------------------------------+
//| Поиск последнего элемента ZZBuf с непустым значением                                |
//+-------------------------------------------------------------------------------------+
int GetLastIndexNoEmptyValue(int index)
{
   while (ZZBuf[index] == EMPTY_VALUE && index < Bars)// Поиск по графику справа налево
      index++;                                     // Пока не будет найден экстремум или
                                                   // ..пока не достигнем конца истории
   return(index);                                  // Индекс бара с непустым значением..
                                                   // ..зиг-зага
}

//+-------------------------------------------------------------------------------------+
//| Сравнение последнего максимума с новым максимумом                                   |
//+-------------------------------------------------------------------------------------+
void CheckHigh(int index)
{
   int cnt = GetLastIndexNoEmptyValue(index);      // Найдем последний непустой элемент..
                                                   // ..зиг-зага
   if (cnt == Bars)                                // Если элемент не найден (достигнут..
   {                                               // ..конец истории), то максимумом..
      ZZBuf[index] = High[index];                  // ..считается текущий максимум
      return;
   }

   if (High[index] > ZZBuf[cnt])                   // Элемент найден. Сравним его..
   {                                               // ..значение с новым максимумом. Если
      ZZBuf[cnt] = EMPTY_VALUE;                    // ..новый максимум выше, то..
      ZZBuf[index] = High[index];                  // ..предыдущий максимум уничтожается,
                                                   // ..а новый сохраняется
   }
}
//+-------------------------------------------------------------------------------------+
//| Сравнение последнего минимума с новым минимумом                                     |
//+-------------------------------------------------------------------------------------+
void CheckLow(int index)
{
   int cnt = GetLastIndexNoEmptyValue(index);      // Найдем последний непустой элемент..
                                                   // ..зиг-зага
   if (cnt == Bars)                                // Если элемент не найден (достигнут..
   {                                               // ..конец истории), то минимумом..
      ZZBuf[index] = Low[index];                   // ..считается текущий минимум
      return;
   }
   
   if (Low[index] < ZZBuf[cnt])                    // Элемент найден. Сравним его..
   {                                               // ..значение с новым минимумом. Если
      ZZBuf[cnt] = EMPTY_VALUE;                    // ..новый минимум ниже, то..
      ZZBuf[index] = Low[index];                   // ..предыдущий минимум уничтожается,
                                                   // ..а новый сохраняется
   }
}
//+-------------------------------------------------------------------------------------+
//| Смена тренда или его продолжение при отсутствии нового сигнала                      |
//+-------------------------------------------------------------------------------------+
void TrendChange(int trend, int i)
{
// - 1 - == Тренд изменился с нисходящего на восходящий =================================
   UpDnBuf[i] = trend;                             // Сохранение признака направления
   if (trend == TREND_UP)                          // Тренд изменился на восходящий
   {
      CheckLow(i);                                 // Проверка появления нового минимума
      if (ZZBuf[i] != EMPTY_VALUE)                 // Если минимум обновлен, то максимум
         ZZBuf[i-1] = High[i];                     // ..переносим на следующий бар
      else                                         // Если минимум не обновлен, то..
         ZZBuf[i] = High[i];                       // ..максимум отображается на текущем
      return;                                      // ..баре
   }
// - 1 - == Окончание блока =============================================================

// - 2 - == Тренд изменился с восходящего на нисходящий =================================
   CheckHigh(i);                                   // Проверка появления нового максимума
   if (ZZBuf[i] != EMPTY_VALUE)                    // Если максимум обновлен, то минимум
      ZZBuf[i-1] = Low[i];                         // ..отображается на следующем баре
   else                                            // Если максимум не обновлен, то..
      ZZBuf[i] = Low[i];                           // ..минимум отображается на текущем..
                                                   // ..баре
// - 2 - == Окончание блока =============================================================
}

//+-------------------------------------------------------------------------------------+
//| Расчет значений индикатора                                                          |
//+-------------------------------------------------------------------------------------+
void ZigZag(int limit)
{
   for (int i = limit; i > 0; i--)                 // По всем новым барам
   {
      int trend = GetTrend(i);                     // Получение направления на баре i
      if (trend != UpDnBuf[i+1] && trend != 0)     // Направление на текущем баре..
      {                                            // ..отличается от направления на..
         TrendChange(trend, i);                    // ..предыдущем баре.
         continue;
      }
      
      UpDnBuf[i] = UpDnBuf[i+1];                   // Направление не изменяется
      if (UpDnBuf[i] == TREND_UP)                  // Сохранение восходящего тренда
      {
         CheckHigh(i);                             // Обновление максимума
         continue;
      }
         
      if (UpDnBuf[i] == TREND_DOWN)                // Сохранение нисходящего тренда
         CheckLow(i);                              // Обновление минимума
   }
}

//+-------------------------------------------------------------------------------------+
//| Custom indicator iteration function                                                 |
//+-------------------------------------------------------------------------------------+
int start()
{
   int limit = GetRecalcIndex();                   // Определим первый расчетный бар
   
   ZigZag(limit);                                  // Расчет значений индикатора
   
   return(0);
}


В функции ZigZag(int limit) цикл идёт по убывающей. По логике, чтоб исключить перерисовку нужно наоборот идти слева направо... т.е. я думаю, правильнее будет так:

PHP:
for (int i = 0; i < limit; i++)


В чём загвоздка? Кто что думает по этому поводу?

Идём дальше. В старте объявлены 2 функции: GetRecalcIndex() и ZigZag(limit)

В функции ZigZag(limit) в строке:

PHP:
 if (trend != UpDnBuf[i+1] && trend != 0)


Проверяется условие:

PHP:
trend != UpDnBuf[i+1]


Откуда программа в этот момент будет знать какое значение имеет данный буфер, ведь по сути нигде об этом в коде по ходу работы кода не упоминается...

А присвоится значение данному буферу только в функции TrendChange(int trend, int i)

Но в данный момент она ещё не вызывается..
 
Последнее редактирование модератором:

ale002

::: __,,,^._.^,,,__ :::
Это вопросы не про зигзаг - ответами должны быть ссылки на соотв статьи в учебнике MQL или в справке MT4. Правильнее было бы этим занимаццо в топике про изучение языка, котор ведёт диавольский просветитель Evil. И правильнее таки с учебника и начать, иначе вы много чего возьмётесь усовершенствовать, напрасно убивая собственное время

И еще, не по теме, но просто полезный принцип, который оч помогает жить. Особенно кодерам. Не стоит браться за что-то лишь тока потому что ты можешь это сделать/переделать
 

hoz

Активный участник
Это вопросы не про зигзаг - ответами должны быть ссылки на соотв статьи в учебнике MQL или в справке MT4. Правильнее было бы этим занимаццо в топике про изучение языка, котор ведёт диавольский просветитель Evil. И правильнее таки с учебника и начать, иначе вы много чего возьмётесь усовершенствовать, напрасно убивая собственное время

И еще, не по теме, но просто полезный принцип, который оч помогает жить. Особенно кодерам. Не стоит браться за что-то лишь тока потому что ты можешь это сделать/переделать


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

ale002

::: __,,,^._.^,,,__ :::
Надеюсь на более канкретные ответы, а не - читай учебник.. что читать? Всё в подряд читать нет резона, т.к. я уже многое знаю.
Ах батенька, да вас ещё и учиться нужно научить.. Берёте любой свой вопрос:

По логике, чтоб исключить перерисовку нужно наоборот идти слева направо... т.е. я думаю, правильнее будет так
Не надо додумывать "по логике", прочтите таки в учебнике как нумеруются тайм-серии в MQL4 - от прошлого к настоящему или наоборот

Откуда программа в этот момент будет знать какое значение имеет данный буфер, ведь по сути нигде об этом в коде по ходу работы кода не упоминается...
Прочтите об области видимости переменных (глобальных, суперглобальных и локальных) и к которому из них относятся буферные массивы

Надеюсь на помощь.
Надеюсь кто-то вам поможет, звиняйте что влез, не удержалсо, виноват, исправлюсь
 

hoz

Активный участник
Не надо додумывать "по логике", прочтите таки в учебнике как нумеруются тайм-серии в MQL4 - от прошлого к настоящему или наоборот

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




Я понимаю, и знаю, что первым баром вообще в таймсерии является нулевой бар, но тут же не та ситуация. Здесь мы лишь задаём цикл и всё!

Прочтите об области видимости переменных (глобальных, суперглобальных и локальных) и к которому из них относятся буферные массивы

Причём тут область видимости. На тот момент, буфер ещё ничего не содержит. Поэтому у него не может быть никакого значения. Вот это я имел ввиду! А про область видимости я прекрасно понимаю..

Надеюсь кто-то вам поможет, звиняйте что влез, не удержалсо, виноват, исправлюсь


Зачем тогда форум, если все друг друга будут сторонкой обходить.. Давайте тогда нос воротить друг от друга!? Если кто-то это всё понимает, ХОТЯ Я СОМНЕВАЮСЬ, ЧТО БОЛЬШИНСТВО ИЗ ЗДЕСЬ ПРИСУСТВУЮЩИХ ЭТО ПОНИМАЕТ, то это не значит, что всем это просто понять.
 
Последнее редактирование:

hoz

Активный участник
В общем-то пока всякие гуру и те кто на них косит проходили мимо я уже сам понял в чём дело. Больше помощь не требуется...
 
Верх