hoz
Активный участник
Решил я освоить индикатор zig-zag. По-сколько дефолтовый вариант данного индюка включённого в стандартную поставку с МТ4 я не особо въехал, я погуглив нашёл один из вариантов с комментами...Начал его штудировать, но тут тоже возникли нюансы. Выношу первый вариант данного zig-zag'а, который строится канкретно по закрытию. Попутно у меня есть огромное желание разобрать его по полочкам. Да я думаю это будет полезно не только мне, а многим присуствующим!
Вот данный код:
В функции ZigZag(int limit) цикл идёт по убывающей. По логике, чтоб исключить перерисовку нужно наоборот идти слева направо... т.е. я думаю, правильнее будет так:
В чём загвоздка? Кто что думает по этому поводу?
Идём дальше. В старте объявлены 2 функции: GetRecalcIndex() и ZigZag(limit)
В функции ZigZag(limit) в строке:
Проверяется условие:
Откуда программа в этот момент будет знать какое значение имеет данный буфер, ведь по сути нигде об этом в коде по ходу работы кода не упоминается...
А присвоится значение данному буферу только в функции TrendChange(int trend, int i)
Но в данный момент она ещё не вызывается..
Вот данный код:
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)
Но в данный момент она ещё не вызывается..
Последнее редактирование модератором: