Формирование пика происходит, при выполнении следующих условий:
1. Если имеется такой high свечи в окружении которого, как до него, так и после имеются другие high свечи меньшие на параметр Delta (задается в процентах);
2. Последняя впадина меньше, чем предыдущая.
3. Если второе условие не выполняется, то пик не формируется до тех пор, пока high свечи не будет выше последнего сформированного ранее пика;
Формирование впадины происходит аналогичным образом, при выполнении следующих условий:
1. Если имеется такой low свечи в окружении которого имеются другие свечи с low большим на значение параметр delta(задается в процентах);
2. Последний пик больше, чем предыдущий.
3. Если второе условие не выполняется, то впадина не формируется до тех пор, пока low свечи не будет меньше последней сформированной ранее впадины;
Я полагал, что если таким образом сформированный ZigZag (далее ZigZag_N) наложить, на ZigZag, сформированный по классическому алгоритму, то там, где нет направленного движения цены, а это как правило, четвертая волна (ее можно увидеть по характерному флэту) ZigZag_N не будет формировать пики и впадины, в то время как ZigZag будет отрисовывать флэт.
Изначально мне показалось, что автор идеи, пользователь с ником Pisces, имеет то же представление, что и я. И даже позавидовал его проницательности. Правда потом выяснилось, что автор идеи имел совсем другое в виду и считал, что дельта это разница между пиком и впадиной. Но оставим это в стороне.
Итак, первый прототип индикатора ZigZag_N готов, спасибо огромное Евгению (ник evge), что помог разобраться с механизмом накопления значений по предыдущим пикам и впадинам.
Код: Выделить всё
function Initialize()
{
IndicatorName = "ZigZag_N";
PriceStudy = true;
AddInput("Input", Inputs.Candle);
AddSeries("ZZWL", DrawAs.Custom, Color.Blue, true, Axes.Parent); //отображение локального ZigZag
AddSeries("ZZG", DrawAs.Custom, Color.Blue, true, Axes.Parent); //отображение глобального ZigZag
AddSeries("Lh_Ll", DrawAs.Custom, Color.Magenta, true, Axes.Parent); //отображение последнего плеча
AddSeries("Peak", DrawAs.Custom, Color.Green); //текуший пик
AddSeries("Trough", DrawAs.Custom, Color.Orange); //текущая впадина
AddSeries("Peak1", DrawAs.Custom, Color.Gray); //предыдущий пик
AddSeries("Trough1", DrawAs.Custom, Color.Red); //предыдущая впадина
AddSeries("Marker", DrawAs.Custom, Color.Red);
AddParameter("Delta", 0.2); //параметр ZigZag задается в процентах
AddGlobalVariable("peakbar", Types.Int, 0);
AddGlobalVariable("troughbar", Types.Int, 0);
AddGlobalVariable("Direction", Types.Int, 0); //направление локального ZigZag
AddGlobalVariable("DirG", Types.Int, 0); //направление глобального ZigZag
AddGlobalVariable("hi", Types.Double, 0);
AddGlobalVariable("lo", Types.Double, 0);
AddGlobalVariable("hibar", Types.Int, 0);
AddGlobalVariable("lobar", Types.Int, 0);
AddGlobalVariable("exPkbar", Types.IntList); //процедура записи последних пиков
AddGlobalVariable("exTghbar", Types.IntList); //процедура записи последних впадин
AddGlobalVariable("hiG", Types.Double, 0);
AddGlobalVariable("loG", Types.Double, 0);
AddGlobalVariable("hibarG", Types.Int, 0);
AddGlobalVariable("lobarG", Types.Int, 0);
AddGlobalVariable("peakbarG", Types.Int, 0);
AddGlobalVariable("troughbarG", Types.Int, 0);
}
function Evaluate()
{
// Alfadirect4.ru Gerig
// ZigZag
// Новый минимум, если Close бара вырос от текущего Low на % и при этом
// последний Peak выше предыдущего Peak1
// Новый максимум, если Close бара снизился от текущего High на % и при этом
// последняя впадина Trough меньше предыдущей впадины Trough1
if (CurrentIndex < 2)
{
lo = Input.Low[0]; //Впервые присваиваемые значения для локального минимума
hi = Input.High[0]; //Впервые присваиваемые значения для локального максимума
loG = Input.Low[0]; //Впервые присваиваемые значения для глобального минимума
hiG = Input.High[0]; //Впервые присваиваемые значения для глобального максимума
}
else
{
double delta = 0.01*Delta;
//Задаем значения локальному минимуму lo и локальному максимуму hi
if(Input.High[0] > hi)
{
hi = Input.High[0];
hibar = CurrentIndex;
}
if(Input.Low[0] < lo)
{
lo = Input.Low[0];
lobar = CurrentIndex;
}
if(Direction >= 0)
{
if((Input.Low[0] > (1 + delta)*lo))
{
Direction = -1; //нашли впадину локального ZigZag
hi = Input.High[0]; //локальный максимум
hibar = CurrentIndex; //номер бара локального максимума
troughbar = lobar; //номер бара впадины
exTghbar.Add(troughbar); //добавляем номер бара впадины в перечень
if ( exTghbar.Count > 2 ) //записываем номера баров последних впадин.
exTghbar.RemoveAt(0);
ZZWL[lobar-CurrentIndex] = lo;
Marker[lobar-CurrentIndex] = lo;
}
}
if(Direction <= 0)
{
if(Input.High[0] <(1 - delta)*hi)
{
Direction = 1; // нашли пик локального ZigZag
lo = Input.Low[0]; //локальный минимум
lobar = CurrentIndex; //мер бара локального минимума
peakbar = hibar; //номер бара пика
exPkbar.Add(peakbar); //добавляем номер пика в перечень
if (exPkbar.Count > 2 ) //записываем номера баров последних пиков.
exPkbar.RemoveAt(0);
ZZWL[hibar-CurrentIndex] = hi;
Marker[hibar-CurrentIndex] = hi;
}
}
Trough = Input.Low[troughbar-CurrentIndex]; //впадина
Peak = Input.High[peakbar-CurrentIndex]; //пик
if (exTghbar.Count > 1)
{
Trough1 = Input.Low[exTghbar[0]-CurrentIndex]; //предыдущая впадина локального ZigZag
}
if(exPkbar.Count > 1)
{
Peak1 = Input.High[exPkbar[0]-CurrentIndex]; //предыдущий пик локального ZigZag
//ShowMessage(peakbar-CurrentIndex); //Для отладки использовали
}
Marker.DrawCircle();
Peak.DrawDash();
Trough.DrawDash();
Peak1.DrawDash();
Trough1.DrawDash();
ZZWL.DrawLine(Color.Blue, Line.Dot, 2); //отрисовка локального ZigZag цвета Blue
//Задаем значения глобальному минимуму loG и глобального максимуму hiG
if(Input.High[0] > hiG)
{
hiG = Input.High[0];
hibarG = CurrentIndex;
}
if(Input.Low[0] < loG)
{
loG = Input.Low[0];
lobarG = CurrentIndex;
}
if(DirG >= 0)
{
if((Input.Low[0] > (1 + delta)*loG))
{
if ((Peak>Peak1)||((Peak<Peak1)&&(Input.Low[0]<Trough)))
{
DirG = -1; //нашли впадину глобального ZigZag
hiG = Input.High[0]; //глобального максимум
hibarG = CurrentIndex; //номер бара глобального максимума
troughbarG = lobarG; //номер бара впадины
ZZG[lobarG-CurrentIndex] = loG;
// Marker[lobarG-CurrentIndex] = loG;
}
}
}
if(DirG <= 0)
{
if(Input.High[0] <(1 - delta)*hiG)
{
if((Trough1>Trough)||((Trough1<Trough)&&(Input.High[0]>Peak)))
{
DirG = 1; // нашли пик глобального ZigZag
loG = Input.Low[0]; //глобального минимум
lobarG = CurrentIndex; //мер бара глобального минимума
peakbarG = hibar; //номер бара пика
ZZG[hibarG-CurrentIndex] = hiG;
// Marker[hibarG-CurrentIndex] = hiG;
}
}
}
ZZG.DrawLine(Color.Blue, Line.Solid, 3); //отрисовка глобального ZigZag цвета Blue
// Последнее плечо, где отображаются локальные экстремумы (не зафиксированно)
// отображается пунктирной линией цвета Magenta
if (CurrentIndex == MaxIndex)
{
if (troughbar > peakbar)
{
Lh_Ll[troughbar-CurrentIndex]=ZZWL[troughbar-CurrentIndex];
Lh_Ll[hibar-CurrentIndex] = hi;
}
if (troughbar < peakbar)
{
Lh_Ll[peakbar-CurrentIndex]=ZZWL[peakbar-CurrentIndex];
Lh_Ll[lobar-CurrentIndex] = lo;
}
}
Lh_Ll.DrawLine(Color.Magenta, Line.Dot, 2);
}
}
Что же можно увидеть? Есть некоторая неточность в отображении некоторых пиков и впадин ZigZag_N, связанная с тем, что если в условиях большой волатильности будет сформирован пик или впадина в ZigZag, то ZigZag_N ее не будет считать, а рассчитает новую рядом стоящую свечу. Я хотел было усовершенствовать алгоритм и предусмотреть правило пересчета вершин в таких случаях, но решил на график вывести еще один ZigZag, но с другой величиной Delta. Я был очень удивлен, но ZigZag c параметром delta увеличенным в 2,5 раза практически совпадает с ZigZag_N.
Получается, что мое предположение об отображении четвертой волны таким способом полностью ошибочно. И действительно был прав пользователь с ником Геннадий, предложивший просто увеличить параметр delta.