#property copyright "Scriptong" #property link "http://autograf.dp.ua" #property indicator_chart_window // Индикатор выводится в окне графика #property indicator_buffers 1 // используется 1 буфер индикатора #property indicator_color1 DodgerBlue // Цвет отображения данных 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 (High[index] > High[index+1]) { if (Low[index] >= Low[index+1]) // Новая свеча не пробивала предыдущую return(TREND_UP); // ..вниз - рост. В противном случае.. if (Open[index] < Close[index]) // ..прибегаем к дополнительному.. return(TREND_UP); // ..критерию - типу свечи. Свеча.. // ..бычья - тренд восходящий if (Open[index] > Close[index]) // Свеча медвежья - тренд нисходящий return(TREND_DOWN); return(NO_TREND); // Для дожи тренд не определен } // - 1 - == Окончание блока ============================================================= // - 2 - == Новая свеча ниже предыдущей ================================================= if (Low[index] < Low[index+1]) { if (High[index] <= High[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 TrendChangeOrMissing(int trend, int i) { // - 1 - == Отсутствие нового сигнала - продолжение существующего тренда ================ if (trend == NO_TREND) // Новая свеча поглощена предыдущей { // Тренд созраняется, последний.. UpDnBuf[i] = UpDnBuf[i+1]; // ..экстремум остается на своем месте return; } // - 1 - == Окончание блока ============================================================= // - 2 - == Тренд изменился с нисходящего на восходящий ================================= 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; // ..баре } // - 2 - == Окончание блока ============================================================= // - 3 - == Тренд изменился с восходящего на нисходящий ================================= CheckHigh(i); // Проверка появления нового максимума if (ZZBuf[i] != EMPTY_VALUE) // Если максимум обновлен, то минимум ZZBuf[i-1] = Low[i]; // ..отображается на следующем баре else // Если максимум не обновлен, то.. ZZBuf[i] = Low[i]; // ..минимум отображается на текущем.. // ..баре // - 3 - == Окончание блока ============================================================= } //+-------------------------------------------------------------------------------------+ //| Расчет значений индикатора | //+-------------------------------------------------------------------------------------+ void ZigZag(int limit) { for (int i = limit; i > 0; i--) // По всем новым барам { int trend = GetTrend(i); // Получение направления на баре i if (trend != UpDnBuf[i+1]) // Направление на текущем баре.. { // ..отличается от направления на.. TrendChangeOrMissing(trend, i); // ..предыдущем баре. continue; } UpDnBuf[i] = trend; // Направление не изменяется if (trend == TREND_UP) // Сохранение восходящего тренда { CheckHigh(i); // Обновление максимума continue; } if (trend == TREND_DOWN) // Сохранение нисходящего тренда CheckLow(i); // Обновление минимума } } //+-------------------------------------------------------------------------------------+ //| Custom indicator iteration function | //+-------------------------------------------------------------------------------------+ int start() { int limit = GetRecalcIndex(); // Определим первый расчетный бар ZigZag(limit); // Расчет значений индикатора return(0); }