#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; } else if (UpDnBuf[i] == TREND_DOWN) // Сохранение нисходящего тренда CheckLow(i); // Обновление минимума } } //+-------------------------------------------------------------------------------------+ //| Custom indicator iteration function | //+-------------------------------------------------------------------------------------+ int start() { int limit = GetRecalcIndex(); // Определим первый расчетный бар ZigZag (limit); // Расчет значений индикатора return(0); }