English 中文 Español Deutsch 日本語 Português
Show Must Go On... или очередное возвращение к ZigZag'у

Show Must Go On... или очередное возвращение к ZigZag'у

MetaTrader 4Торговые системы | 30 мая 2008, 09:12
4 610 26
Rider
Rider

Введение

Огромное количество всевозможных версий ZigZag'а подтверждает наличие постоянного и неослабевающего интереса к этому индикатору. Вполне оправданного интереса. Это, пожалуй, единственный индикатор, который одним своим ярким наглядным графическим представлением основных движений рынка напрямую воздействует на эмоции трейдера, побуждая к немедленному действию. Видимо, только этим и можно объяснить феномен, когда при полном понимании большинством, что этот индикатор не предназначен для прямой генерации сигналов на совершение торговых операций, тем не менее раз за разом предпринимаются попытки максимально приблизить его к текущей рыночной ситуации. Сомнительное преимущество, особенно при его восприятии, когда наблюдаешь бесконечные перерисовки последнего прогнозиремого излома.

Давайте немного порассуждаем. Хотите верьте, хотите нет, но именно с этого все и начинается.

Лирика

Все мы, придя и ОСТАВШИСЬ на этом рынке, рано или поздно понимаем, что он не так прост, как нам казалось в начале. Осознав это, мы начинаем читать, кто умеет, конечно. Вот только воспринимаем прочитанное как-то уж очень своеобразно. Если коротко, то выбираем не то, что Правильно, а то, что Просто. Соответственно, и на вооружение берем только то, что лежит на поверхности, очевидно для понимания и легко (быстро) переводится на язык алгоритмов. Примеров множество. Вот только один из них, может не самый удачный, но какой уж есть.

Все знают и помнят базовый тезис ТА, никем еще не опровергнутый, как и строго не доказанный, впрочем:

Цена - это наше ВСЁ!

Понимая это прямо и в лоб, мы начинаем искать не опорные точки рынка, а непременно максимумы и минимумы – это же проще и очевидней. По линеечке чертить уровни сопротивления и поддержки, отсчитывать от них фибоуровни, считать циклы в барах и т.д. и т.п. Дальше больше – начинаем выдергивать из кем-то созданных торговых систем только то, что доступно нашему пониманию, зачастую не обращая внимания ни на предостережения, ни даже на то, для какого рынка и в какое время эта система создавалась ….. Что еще хуже, мы начинаем упрощать… упрощать Ганна(!!!), которому, как предполагаю, удалось найти ( или очень близко подойти) решение задачи Цены-Времени.... бред... как можно упростить то, что еще до конца никем не понято?

А потом, когда убеждаемся, что все это работает как-то не так, всего лишь чуть лучше чем 50 на 50, мы очень громко начинаем говорить, что Гуру врут, их методы не работают, книги написаны из-за денег, золотого сечения не существует.... и т.д. и т.п. А все от того, что глядя на какой-нибудь экстремум, мы забываем, что это совсем не синоним минимакса, а то, что это - действительно максимум или минимум - всего лишь одно из проявлений его внутренней сущности, до которой нужно еще докопаться. И вот, на основании этого поверхностного суждения мы пытаемся спрогнозировать будущее, даже не пытаясь проанализировать, что именно сделало эту точку тем что она есть именно в этом месте и именно в этот момент времени.

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

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

К теме.

Мультифреймовый Фрактальный ZigZag


Мне потребовался индикатор, который отображает не просто минимумы и максимумы, а логически обоснованные движениями цены экстремальные точки рынка (ЛОЭТР - может приживется?), да еще и подтвержденные, по возможности. Задача сделать из него генератор торговых сигналов не ставилась изначально. Сначала попытался из стандартного (не того, что в МТ4, а в широком смысле "стандартного") ZigZag конструировать, но кое-что насторожило и заставило от этой идеи отказаться:

  • несмотря на множество обсуждений в сети и обилие различных его вариантов - однотипность всех алгоритмов (кстати, может не по глазам, но так нигде и не встретил, чтобы черным по русскому и членораздельно где-то этот алгоритм расшифровали);
  • отсутствие единого понимания того, "что" же он все-таки ищет;
  • безобразно частая, а что самое неприятное, труднопредсказуемая перерисовка;
  • прямая зависимость от временного периода и/или так же заранее заданной амплитуды ценового движения;

Последнее, лично для меня, самое неприемлемое. Не приглянулся он мне, в общем. Ничего личного.

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

Свое, оно может и не лучше, но, однозначно, роднее. Потому чужой код не искал, написал "свой" простенький индикатор типа фрактала, вернее его подобие – правила выбора точек немного от стандартных отличаются. Попробовал его с разных таймфреймов через iCustom повызывать, но понял, что рациональней на текущем (рабочем) таймфрейме (ТФ) все посчитать. Дальше логика программирования уже сама все подсказала и про модульную конструкцию, которая в дальнейшем напрашивается, и про нестандартные ТФ. Вот и получилось, то что получилось.

На картинках то, как он отображается с параметрами ТФ 1440, 360, 60. График H1 выбран для наглядности, чтобы можно было увидеть, что черная линия (60) не все фрактальные точки забирает, а кое-какие отбрасывает. Первая картинка - чтобы на кончик посмотреть, как это в динамике выглядит, а вторая, просто из середины графика.

Цветовое решение не самое удачное, в аттаче картинка, как сам на него смотрю.


Код


Давайте посмотрим каким образом это реализовано, не "на пальцах" же нам объясняться ;)
Индикатор формирует на рабочем текущем (ТФ) последовательность узлов зигзага, вычисленных на сэмулированных трех старших. Работает на всех и со всеми, в т.ч. и нестандартными ТФ, со следующими ограничениями, реализованными в коде:
- старшие ТФ должны быть кратны рабочему, если это не так, то принудительно устаавливаются ближайшие правильные значения;
- рабочий ТФ не более наименьшего из старших;
- периоды в параметрах указываются в минутах и должны быть выставлены в порядке убывания;
- период самого большого ТФ не более 43200 (месяц) - это не предел, можно и больше;
Особенность в том, что для каждого ТФ используется только один буфер. Два не нужно, так как при разумной комбинации ТФ, вероятность появления двух разнонаправленных экстремумов на одном баре рабочего ТФ очень мала.

Вот этот фрагмент:

//-----------------------------------------------------------------------
// MF_Fractal_ZZ_3in1.mq4
//-----------------------------------------------------------------------
#property copyright "Copyright © 2008, BiViSi Corp."
#property link      "riderfin@bk.ru"
#property link      "ICQ 499949112"

#property indicator_chart_window    
#property indicator_buffers 3
//---- стиль  индикаторной линии
#property indicator_color1 Blue 
#property indicator_color2 Red
#property indicator_color3 Yellow        
#property indicator_style1 0
#property indicator_style2 0
#property indicator_style3 0
#property indicator_width1 5
#property indicator_width2 3
#property indicator_width3 1
//---- ВХОДНЫЕ ПАРАМЕТРЫ ИНДИКАТОРА 
extern int VolExt=50; // вычисление "VolExt+1" последних опорных точек
extern int TFLarge=1440;
extern int TFMidle=240;
extern int TFSmall=60;
//---- Variables 
double Large[],Midle[],Small[];  // опорные точки (буферы индикатора)
datetime PrevTimePer[4];         // времена последнего расчета по каждому ТФ
datetime PrevTimeCalc=0; 
double P60,CP60;
int CurPeriod, ErrorTF=0, NumberExt, Per,  largelast=0, midlelast=0, smalllast=0;
//-----------------------------------------------------------------------
int init() 
{
   // инициализация 
   IndicatorBuffers(3); // строка "на перспективу" :)
   SetIndexBuffer(0,Large); SetIndexStyle(0,DRAW_SECTION);
   SetIndexEmptyValue(0,0.0);
   SetIndexBuffer(1,Midle); SetIndexStyle(1,DRAW_SECTION);
   SetIndexEmptyValue(1,0.0); 
   SetIndexBuffer(2,Small); SetIndexStyle(2,DRAW_SECTION);
   SetIndexEmptyValue(2,0.0);
   ArrayInitialize(PrevTimePer,0);
   CurPeriod=Period(); CP60=CurPeriod*60;
   // Ограничения:
   // контроль ТФ и введенных параметров
   if (MathCeil(TFSmall/CurPeriod) != TFSmall/CurPeriod) 
      TFSmall=MathCeil(TFSmall/CurPeriod)*CurPeriod;
   if (MathCeil(TFMidle/CurPeriod) != TFMidle/CurPeriod)
      TFMidle=MathCeil(TFMidle/CurPeriod)*CurPeriod;
   if (MathCeil(TFLarge/CurPeriod) != TFLarge/CurPeriod)
       TFLarge=MathCeil(TFLarge/CurPeriod)*CurPeriod;
   if (CurPeriod > TFSmall) 
      {Alert ("Период графика должен быть меньше или равен ", TFSmall," мин.");
       ErrorTF=1;return;}
   if (TFSmall >= TFMidle || TFMidle >= TFLarge || TFLarge>43200)
      {Alert ("Некорректный выбор таймфреймов для расчета!!!"); ErrorTF=1;return;}
   return;              
}
//--------------------------------------------------------------------

Следующий блок отвечает за поиск опорных точек, вычисление узлов зигзага и занесение их в буферные массивы индикатора.

Отказ от использования конструкции типа: int IC=IndicatorCounted(); и т.д., обусловлен самим алгоритмом расчета индикатора, который и без того обеспечивает достаточное быстродействие (см. Force #1-3 в коде), которое, кстати, можно еще и увеличить, чуть позже об этом.

//--------------------------------------------------------------------
int start()
{
   if ( ErrorTF==1 ) return; // некорректный таймфрейм   
   FractalCalc(); 
   return;
}
//======================================================================
// Поиск 5-ти барных фракталов и вычисление узлов зигзага 
// на эмуляции старших ТФ, удаление лишних и отображение на текущем ТФ
//======================================================================
void FractalCalc ()
{   
   // Force  №1 - выч только на полностью сформировавшемся баре рабочего ТФ
   if (PrevTimeCalc == Time[0]) return; else PrevTimeCalc=Time[0];
   int y, x, k, i, j, extr=0; 
   // время последнего бара тек ТФ, закрывающего бар №1-5 старшего ТФ
   int t1, t2, t3, t4, t5;                     
   // номер последнего бара тек ТФ, закрывающего бар №1-5 старшего ТФ
   int limit1, limit2, limit3, limit4, limit5; 
   // номера баров тек ТФ с пиками и донышками соотв барам 1-5 старшего ТФ
   int up1,up2,up3,up4,up5,dn1,dn2,dn3,dn4,dn5;
      
   for (y=1; y<=3; y++) // цикл по рассчитываемым ТФ
      {
      if (y==1) Per=TFLarge; if (y==2) Per=TFMidle; if (y==3) Per=TFSmall;
      P60=Per*60;
      // Force №2 - Вычисляем изломы только с формированием бара старшего ТФ
      if (PrevTimePer[y] !=0)
         { 
         if (Per<43200 && (Time[0] - PrevTimePer[y])<P60 )continue;
         if (Per==43200 && Month()==TimeMonth(PrevTimePer[y]))continue;
         }
      // Обработка пропуска баров
      // Если прямолинейно PrevTimePer[y]=Time[0], то в случае пропуска баров
      // на рабочем ТФ произойдет сдвиг всей цепочки расчета на величину пропуска
      PrevTimePer[y]=MathCeil(Time[0]/Per/60)*P60; 
      
      NumberExt=0;  extr=0;
      k=Per/CurPeriod;
      // ограничение цикла - в зависимости от того какой ТФ обсчитываем
      // и от последнего найденного фрактала
      i=MathCeil(Bars/k)-5;
      // Force #3 - обсчитываем, начиная с последнего излома
      if(y==1 && largelast !=0) i=largelast+k;
      if(y==2 && midlelast !=0) i=midlelast+k;
      if(y==3 && smalllast !=0) i=smalllast+k;
      for (x=1; x<=i; x++) 
         {
         // находим пики и донышки
         // время начала последнего бара тек ТФ, закрывающего бар №1 старшего ТФ
         if (PrevTimePer[y] !=0) t1=PrevTimePer[y]-x*P60+(k-1)*CP60;
         else t1=MathCeil(Time[0]/Per/60)*P60-x*P60+(k-1)*CP60;
         t2=t1-P60; t3=t2-P60; t4=t3-P60; t5=t4-P60;
         limit1=iBarShift(NULL,0,t1, false); limit2=iBarShift(NULL,0,t2, false);
         limit3=iBarShift(NULL,0,t3, false); limit4=iBarShift(NULL,0,t4, false);
         limit5=iBarShift(NULL,0,t5, false);         
         up1=iHighest(NULL,0,MODE_HIGH,k,limit1); up2=iHighest(NULL,0,MODE_HIGH,k,limit2);
         up3=iHighest(NULL,0,MODE_HIGH,k,limit3); up4=iHighest(NULL,0,MODE_HIGH,k,limit4);
         up5=iHighest(NULL,0,MODE_HIGH,k,limit5);
         dn1=iLowest(NULL,0,MODE_LOW,k,limit1); dn2=iLowest(NULL,0,MODE_LOW,k,limit2);
         dn3=iLowest(NULL,0,MODE_LOW,k,limit3); dn4=iLowest(NULL,0,MODE_LOW,k,limit4);
         dn5=iLowest(NULL,0,MODE_LOW,k,limit5);

         // ищем опорные точки
         if(High[up3]>High[up2] && High[up3]>High[up1] && High[up3]>=High[up4] && High[up3]>=High[up5])
            {
            if (y==1){Large[up3]=High[up3];largelast=up3;}
            if (y==2){Midle[up3]=High[up3];midlelast=up3;}
            if (y==3){Small[up3]=High[up3];smalllast=up3;}
            NumberExt++;  extr++;
            }
         if(Low[dn3]<Low[dn2] && Low[dn3]<Low[dn1] && Low[dn3]<=Low[dn4] && Low[dn3]<=Low[dn5])
            {
            if (y==1){Large[dn3]=Low[dn3];largelast=dn3;}
            if (y==2){Midle[dn3]=Low[dn3];midlelast=dn3;}
            if (y==3){Small[dn3]=Low[dn3];smalllast=dn3;}
            NumberExt++; extr++;
            }
         if (NumberExt>VolExt) break;   
         } 
      }

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

Следующий блок производит своего рода «прополку» - удаление лишних экстремумов (это когда между двумя пиками несколько донышек появляются и наоборот) для формирования правильного зигзага: из 2-х и более подряд идущих пиков\донышков выбираются максимальный\минимальный, а при равенстве - с наименьшим номером бара.... лишние обнуляются. С алгоритмом можно поспорить и варианты имеют место быть, но решил пока сделать так.
В коде есть закоментированные строки, которые позволяют избавиться от рассогласования в появлении пиков\донышков на различных ТФ, но их нужно дорабатывать - в том виде как сейчас, это работает некорректно. Временно отказался от этой идеи, кому интересно может попробовать сделать самостоятельно.
В этом же фрагменте скрыта возможность еще больше ускорить его работу, если использовать вместо конструкции if (NumberExt>VolExt) break; заранее рассчитанный сдвиг, но и от этого я тоже пока отказался.

И раз уж речь зашла о скорости, то самым очевидным и простым способом будет уменьшение VolExt во входных параметрах индикатора, вряд ли кому нужно больше 10-15 не для анализа, а для торговли, разве что для гурманов :).

   if (extr==0) return;
   for (y=1; y<=3; y++)
      {
      if (y==1) j=ArraySize(Large);if (y==2)j=ArraySize(Midle);
      if (y==3)j=ArraySize(Small);      
      int min=0, max=0, extmin=0, extmax=0;
      NumberExt=0;      
      for (x=1;x<=j;x++)
         {
         if (y==1)
            {
            if (Large[x] == 0.0 ) continue;
            if (Large[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Large[max]>=Large[x])Large[x]=0.0;
                  else {Large[max]=0.0;max=x;}
                  extmax--;  
                  }
               else max=x;
               }
            if (Large[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Large[min]<=Large[x])Large[x]=0.0;
                  else {Large[min]=0.0;min=x;}
                  extmin--;  
                  }
               else min=x;
               }
            }         
         if (y==2)
            {
            if (Midle[x] == 0.0 ) continue;
            if (Midle[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Midle[max]>=Midle[x])Midle[x]=0.0;
                  else {Midle[max]=0.0;max=x;}
                  extmax--;  
                  // можно и попроще, как выше, но.... убираем расхождения
                  /*
                  if (Midle[max]>Midle[x])Midle[x]=0.0; 
                  if (Midle[max]==Midle[x])
                     {
                     if (Large[x] == High[x]) {Midle[max]=0.0;max=x;}
                     else Midle[x]=0.0; 
                     }
                  if (Midle[max]<Midle[x]){Midle[max]=0.0;max=x;}
                  */
                  }
               else max=x;
               }
            if (Midle[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Midle[min]<=Midle[x])Midle[x]=0.0;
                  else {Midle[min]=0.0;min=x;}
                  extmin--;  
                  // можно и попроще, как выше, но.... убираем расхождения
                  /*
                  if (Midle[min]<Midle[x])Midle[x]=0.0; 
                  if (Midle[min]==Midle[x])
                     {
                     if (Large[x] == Low[x]) {Midle[min]=0.0;min=x;}
                     else Midle[x]=0.0; 
                     }
                  if (Midle[min]>Midle[x]){Midle[min]=0.0;min=x;}
                  */
                  }
               else min=x;
               }
            }         
         if (y==3)
            {
            if (Small[x] == 0.0 ) continue;
            if (Small[x] == High[x])
               {
               NumberExt++; extmax++; extmin=0;
               if (extmax==2)
                  {
                  if (Small[max]>=Small[x])Small[x]=0.0;
                  else {Small[max]=0.0;max=x;}
                  extmax--;  
                  // можно и попроще, как выше, но.... убираем расхождения
                  /*
                  if (Small[max]>Small[x])Small[x]=0.0; 
                  if (Small[max]==Small[x])
                     {
                     if (Midle[x] == High[x]) {Small[max]=0.0;max=x;}
                     else Small[x]=0.0; 
                     }
                  if (Small[max]<Small[x]){Small[max]=0.0;max=x;}
                  */
                  }
               else max=x;
               }
            if (Small[x] == Low[x])
               {
               NumberExt++; extmax=0; extmin++;
               if (extmin==2)
                  {
                  if (Small[min]<=Small[x])Small[x]=0.0;
                  else {Small[min]=0.0;min=x;}
                  extmin--;  
                  // можно и попроще, как выше, но.... убираем расхождения
                  /*
                  if (Small[min]<Small[x])Small[x]=0.0; 
                  if (Small[min]==Small[x])
                     {
                     if (Midle[x] == Low[x]) {Small[min]=0.0;min=x;}
                     else Small[x]=0.0; 
                     }
                  if (Small[min]>Small[x]){Small[min]=0.0;max=x;}
                  */
                  }
               else min=x;
               }
            }         
         if (NumberExt>VolExt) break;
         }
      }         

}


Заключение


В итоге получился индикатор, пусть с очевидным, но никем ранее не использованным алгоритмом, избавленный от некоторых недостатков стандартного ZigZag и обладающий следующими достоинствами:

  • относительно редкие и прогнозируемые перерисовки узлов, их обоснованность не только по амплитуде, но и по предшествующему движению цены. Причем, если произошло их совпадение на различных ТФ, то перерисовки процентов на 90-95 уже не будет;
  • возможность видеть на одном графике все, что происходит на трех более крупных ТФ и, как следствие, выявлять господствующие тенденции без использования дополнительных построений и инструментов;
  • использование для расчета ZigZag нестандартных, на любой вкус и потребности, таймфреймов (от M5 до MN1);
  • экономичность, высокая скорость расчетов, прозрачный алгоритм и код, который легко корректировать и совершенствовать.

Спросите, почему бы не сделать эту коррекцию сразу? Мне пока достаточно того что получилось.... ПОКА достаточно :)
А еще мне известно, что готовый работоспособный код можно вылизывать до бесконечности. Это как карандаши затачивать.... за сим увлекательным занятием можно забыть, что ими рисовать нужно. Я порисую, уже очень хочется :)

Что дальше и Что с этим делать? Готовых решений нет. Это, всего лишь, инструмент, а что с его помощью ваять, Буратино или табуретку, каждый Папа Карло решает сам.
Могу только сказать, что в сухом остатке 5 свободных индикаторных буферов, возможность легко добавлять новые модули и вполне адекватная реакция на вызов через iCustom().... фантазируйте.

Самое вкусное, БЛАГОДАРНОСТИ.

ANG3110 - за самое ценное - идеи, которые, собственно, и подтолкнули к написанию этого индикатора;
Korey
- за поддержку и помощь в диагностике ТimeCurrent и оптимизации вычислений;
Форумчанам
, которые вольно или невольно, осознано или неосознанно, но иногда высказывают мысли, которые хочется "думать".

Прикрепленные файлы |
i_M_Fractal.mq4 (1.7 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (26)
Alexei Kharchenko
Alexei Kharchenko | 6 июн. 2008 в 13:14
rider:вариантов несчитано :)...... главное во всех этих временах не запутаться и чтобы быстродействие не сильно пострадало


вариантов действительно масса... быстродействие страдает... ведь используются котировки на младших ТФ, а, значит, в расчет берется больше баров, чем на основном графике... еще надо следить, чтобы на младшем ТФ была закачена история без "дыр"... Теперь сравним ЗигЗаг с котировками М1 (желтая линия) и Н1 (голубая линия)...

ExtDepth =1...

 

или ExtDepth =4

 

Котировки с младших ТФ показывают наиболее приближенный результат к реальному движению цены...

Rider
Rider | 6 июн. 2008 в 17:13
kharko:

.......

ExtDepth =1...

Результат, скажем так, "на любителя", так же как и в моем случае..... Здесь оценка зависит от того кто и что от него получить хочет и для чего использовать. А вот один момент в реализации заинтересовал........Почту посмотрите.

Vladimir Perervenko
Vladimir Perervenko | 8 июн. 2008 в 02:03

Отличная работа, снимаю шляпу.

Для себя добавил бы :

1. Возможность автоматической установки отрисовываемых ТФ в зависимости от текущего ТФ с помощью коэффициентов

kS,kM,kL. Причём для каждого ТФ можно заранее установить коэффициенты предпочитаемых периодов.Например -

для М5-1/3/4 и т.д.

Ручками при каждом переключении ТФ как-то лень.


2.Выводить индикацию об отрисовываемых ТФ, после второго переключеня забываю где я. Т.е в правом нижнем углу цифирки

15-30-240 и всё ясно.

#property copyright "Copyright © 2008, BiViSi Corp."
#property link      "riderfin@bk.ru"
#property link      "ICQ 499949112"
 
#property indicator_chart_window    
#property indicator_buffers 3
//---- стиль  индикаторной линии
#property indicator_color1 Blue 
#property indicator_color2 Gold
#property indicator_color3 Indigo        
#property indicator_style1 0
#property indicator_style2 0
#property indicator_style3 0
#property indicator_width1 8
#property indicator_width2 5
#property indicator_width3 2
//---- ВХОДНЫЕ ПАРАМЕТРЫ ИНДИКАТОРА 
extern int VolExt=25; // вычисление "VolExt+1" последних опорных точек
extern int TFLarge=240;
extern int TFMidle=120;
extern int TFSmall=30;
extern string TF="auto";
extern int kS=1;
extern int kM=4;
extern int kL=4;
//---- Variables 
double Large[],Midle[],Small[];  // опорные точки (буферы индикатора)
datetime PrevTimePer[4];         // времена последнего расчета по каждому ТФ
datetime PrevTimeCalc=0; 
double P60,CP60;
int CurPeriod, ErrorTF=0, NumberExt, Per,  largelast=0, midlelast=0, smalllast=0;
static bool Up1,Up2,Up3,Dn1,Dn2,Dn3;
//-----------------------------------------------------------------------
int init() 
{
   // инициализация 
   IndicatorBuffers(3); // строка "на перспективу" :)
   SetIndexBuffer(0,Large); SetIndexStyle(0,DRAW_SECTION);
   SetIndexEmptyValue(0,0.0);
   SetIndexBuffer(1,Midle); SetIndexStyle(1,DRAW_SECTION);
   SetIndexEmptyValue(1,0.0); 
   SetIndexBuffer(2,Small); SetIndexStyle(2,DRAW_SECTION);
   SetIndexEmptyValue(2,0.0);
   ArrayInitialize(PrevTimePer,0);
   CurPeriod=Period(); CP60=CurPeriod*60;
   // Ограничения:
   // контроль ТФ и введенных параметров
   
   
   
   /*if (MathCeil(TFSmall/CurPeriod) != TFSmall/CurPeriod) 
      TFSmall=MathCeil(TFSmall/CurPeriod)*CurPeriod;
   if (MathCeil(TFMidle/CurPeriod) != TFMidle/CurPeriod)
      TFMidle=MathCeil(TFMidle/CurPeriod)*CurPeriod;
   if (MathCeil(TFLarge/CurPeriod) != TFLarge/CurPeriod)
       TFLarge=MathCeil(TFLarge/CurPeriod)*CurPeriod;
   if (CurPeriod > TFSmall) 
      {Alert ("Период графика должен быть меньше или равен ", TFSmall," мин.");
       ErrorTF=1;return;}
   //if (TFSmall >= TFMidle || TFMidle >= TFLarge || TFLarge>43200)
    //  {Alert ("Некорректный выбор таймфреймов для расчета!!!"); ErrorTF=1;return;}*/
   return;              
}
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   ObjectDelete("Гор1");
   ObjectDelete("Гор2");
   ObjectDelete("Гор3"); 
//----
   return(0);
  }
//--------------------------------------------------------------------
int start()
{
   double   top=WindowPriceMax();
   double botton=WindowPriceMin();
   string гор1,гор2,гор3;
   color cvet1,cvet2,cvet3;
   if ( ErrorTF==1 ) return; // некорректный таймфрейм 
   if(TF=="auto")
   {
    if(CurPeriod==5)    kM=6; 
    if(CurPeriod==15)   kM=2;
    if(CurPeriod==240) {kM=2;kL=3;гор3="4H";гор2="8H";гор1="24H";}
    if(CurPeriod==1440){kM=5;kL=2;гор3="1D";гор2="5D";гор1="10D";}
    if(CurPeriod==10080){kM=4;kL=2;гор3="1W";гор2="4W";гор1="8W";}
    TFSmall=kS*CurPeriod; TFMidle=TFSmall*kM; TFLarge=TFMidle*kL;
   }  
   if(CurPeriod<=60||TF!="auto")
   {гор3=TFSmall;
    гор2=TFMidle;
    гор1=TFLarge;
    }
   int dist=MathFloor(((top-botton)/30)/Point);
   ObjectDelete("Гор1");
   ObjectDelete("Гор2");
   ObjectDelete("Гор3"); 
   FractalCalc();
   if(Up3)cvet3=Blue; if(Dn3) cvet3=Red;
   if(Up2)cvet2=Blue; if(Dn2) cvet2=Red;
   if(Up1)cvet1=Blue; if(Dn1) cvet1=Red;
   LabelCreate1("Гор1",3,10,3*dist,гор1,15,cvet1);
   LabelCreate1("Гор2",3,10,2*dist,гор2,15,cvet2);
   LabelCreate1("Гор3",3,10,1*dist,гор3,15,cvet3);
   
   return;
}
////////////////////////////////////////////////////////////////////////////////
 
bool LabelCreate1 ( string _LabelName,int _LabelCorner, int _Xdist, int _Ydist,
                   string text,int widt,color cvet)
/////////////////////////////////////////////////////////////////////////////////
// Создание объекта "Текстовая метка" с именем _LabelName.
// Координаты: х = _LabelXDistance, у = _LabelYDistance, угол - _LabelCorner.
/////////////////////////////////////////////////////////////////////////////////
{
   
    ObjectCreate( _LabelName, OBJ_LABEL,0,0,0); 
    ObjectSet(_LabelName,OBJPROP_CORNER,_LabelCorner); 
    ObjectSet(_LabelName,OBJPROP_XDISTANCE,_Xdist); 
    ObjectSet(_LabelName,OBJPROP_YDISTANCE,_Ydist);
    ObjectSetText ( _LabelName,text ,widt,"Arial Black",cvet );
    
}

3.Поскольку линии накладываются скрывая нижних желательно эти цифирки окрашивать в соответствующий цвет.Например вверх-синий, вниз красный.

Вот первые два пункта реалзовал без проблем а с третьим проблема. Я использовал флаги Up/Dn устанавливаемые в функции вычисления фрактала ( в той части где вычисляются вершины и донышки). И облом . На некоторых ТФ цвета совпадают, на некоторых перевернуты, вобщем нет системы. Очевидно я не совсем понял логику работы функции. А может это связано с тем, что я прлверял в выходные.

Привожу кусок кода ф-ии где устанавливаются флаги

// ищем опорные точки
         if(High[up3]>High[up2] && High[up3]>High[up1] 
            && High[up3]>=High[up4] && High[up3]>=High[up5])
            {
            if (y==1){Large[up3]=High[up3];largelast=up3;Up1=false;Dn1=true;}
            if (y==2){Midle[up3]=High[up3];midlelast=up3;Up2=false;Dn2=true;}
            if (y==3){Small[up3]=High[up3];smalllast=up3;Up3=false;Dn3=true;}
            NumberExt++;  extr++;
            }
         if(Low[dn3]<Low[dn2] && Low[dn3]<Low[dn1] 
            && Low[dn3]<=Low[dn4] && Low[dn3]<=Low[dn5])
            {
            if (y==1){Large[dn3]=Low[dn3];largelast=dn3;Up1=true;Dn1=false;}
            if (y==2){Midle[dn3]=Low[dn3];midlelast=dn3;Up2=true;Dn2=false;}
            if (y==3){Small[dn3]=Low[dn3];smalllast=dn3;Up3=true;Dn2=false;}
            NumberExt++; extr++;
            }
         if (NumberExt>VolExt) break;   
         }

Просьба:

1.Не могли бы Вы посмотреть код и помочь решить эту проблему с цветом?

2.Нельзя ли другим способом определять пики оставив отрисовку Вашу?

3.Не могли бы Вы поподробней писать способ вычислений на нестандартных ТФ без их конвертации? Поскольку мой предпочитаемый ТФ 2 часа для меня это интересно.

Прилагаю картинки показывающие результат. Как приложить код не нашел.


1H


4H


1D


Так и картинки не пошли.

Подскажите как вставить правильно картинку и приктепить код.

Rider
Rider | 8 июн. 2008 в 09:04

vlad1949  писал(а):



Спасибо за оценку. Так думаю, что здесь в комментариях прикрепленные файлы просто не предусмотрены. На форуме топик есть - там можно: 'Статья: Show Must Go On... или очередное возвращение к ZigZag'у'

Но картинки однозначно вставляться должны, если с путями и форматами ничего не напутали.

Что касается цвета, то, честно говоря, пока не понял, что вы хотите разными цветами маркировать, но то, что в том виде как вы написали работать это не будет мне уже понятно:

// ищем опорные точки
         if(High[up3]>High[up2] && High[up3]>High[up1] 
            && High[up3]>=High[up4] && High[up3]>=High[up5])
            {
            if (y==1){Large[up3]=High[up3];largelast=up3;Up1=false;Dn1=true;}
            if (y==2){Midle[up3]=High[up3];midlelast=up3;Up2=false;Dn2=true;}
            if (y==3){Small[up3]=High[up3];smalllast=up3;Up3=false;Dn3=true;}
            NumberExt++;  extr++;
            }
         if(Low[dn3]<Low[dn2] && Low[dn3]<Low[dn1] 
            && Low[dn3]<=Low[dn4] && Low[dn3]<=Low[dn5])
            {
            if (y==1){Large[dn3]=Low[dn3];largelast=dn3;Up1=true;Dn1=false;}
            if (y==2){Midle[dn3]=Low[dn3];midlelast=dn3;Up2=true;Dn2=false;}
            if (y==3){Small[dn3]=Low[dn3];smalllast=dn3;Up3=true;Dn2=false;}
            NumberExt++; extr++;
            }
         if (NumberExt>VolExt) break;   
         }

Ваши Up и Dn нигде не запоминаются и в конечном итоге принимают значение по последнему найденному фракталу...... а во второй части кода очистка производится, и не факт, что этот фрактал в построении зигзага участвовать будет. Видимо, значения им там присваивать нужно, но..... код так построен, что в том месте ничто ничему не присваивается, а только обнуляется....  :( . Нужно Вам там кое-что переписать будет, без этого не обойтись.

Еще одно. Вот этот не маленький кусочек:

int start()
{
   double   top=WindowPriceMax();
   double botton=WindowPriceMin();
   string гор1,гор2,гор3;
   color cvet1,cvet2,cvet3;
   if ( ErrorTF==1 ) return; // некорректный таймфрейм 
   if(TF=="auto")
   {
    if(CurPeriod==5)    kM=6; 
    if(CurPeriod==15)   kM=2;
    if(CurPeriod==240) {kM=2;kL=3;гор3="4H";гор2="8H";гор1="24H";}
    if(CurPeriod==1440){kM=5;kL=2;гор3="1D";гор2="5D";гор1="10D";}
    if(CurPeriod==10080){kM=4;kL=2;гор3="1W";гор2="4W";гор1="8W";}
    TFSmall=kS*CurPeriod; TFMidle=TFSmall*kM; TFLarge=TFMidle*kL;
   }  
   if(CurPeriod<=60||TF!="auto")
   {гор3=TFSmall;
    гор2=TFMidle;
    гор1=TFLarge;
    }
   int dist=MathFloor(((top-botton)/30)/Point);
   ObjectDelete("Гор1");
   ObjectDelete("Гор2");
   ObjectDelete("Гор3"); 
   FractalCalc();
   if(Up3)cvet3=Blue; if(Dn3) cvet3=Red;
   if(Up2)cvet2=Blue; if(Dn2) cvet2=Red;
   if(Up1)cvet1=Blue; if(Dn1) cvet1=Red;
   LabelCreate1("Гор1",3,10,3*dist,гор1,15,cvet1);
   LabelCreate1("Гор2",3,10,2*dist,гор2,15,cvet2);
   LabelCreate1("Гор3",3,10,1*dist,гор3,15,cvet3);
   
   return;
}

у вас на каждом тике выполнятся будет. Оно вам надо? Может логичнее все что одноразовое в init вынести?
Индикатор хотя и шустр, но аппаратные ресурсы беречь все равно нужно. 

И последнее, по таймфремам. Все расчеты на двух китах держатся: CurPerid - период графика к которому он прикреплен и Per - период рассчитываемого зигзага. Никогда эмуляцией нестандартных не занимался (в индикаторе "нестандартными" могут быть только Per), но если у вас в этом есть необходимость и вы будете прикреплять его на H2 (допустим), то нужно просто в функции init (или через extern) 

int init() 
{
   // инициализация 
   IndicatorBuffers(3); // строка "на перспективу" :)
   //............
   SetIndexEmptyValue(2,0.0);
   ArrayInitialize(PrevTimePer,0);
   //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   CurPeriod=Period(); CP60=CurPeriod*60;
   //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   // Ограничения:
   // контроль ТФ и введенных параметров
   //...............
   return;              
}

задать нужное значение для CurPeriod, так как функция Period() на нестандартном ТФ вряд ли заработает. После этого все должно работать.... теоретически :)





Rider
Rider | 10 июл. 2008 в 09:40
vlad1949:

Для себя добавил бы :

1. Возможность автоматической установки отрисовываемых ТФ......


Для себя и добавьте :)

Я не ерничаю vlad1949, просто мыслЕй и так хватает, а на каждый чих не надышишься...... к примеру, мне недавно захотелось, чтобы при одном вызове через icustom у меня все посчитанные массивы были доступны..... ан нет - mql не разрешает.... так и и извращаюсь черезь глобальные.... или недавно обнаружил, что ускорить его еще можно.... так все равно руки не дошли, пока не подперло.....

Код, дело интимное :)

И извините, плз, что вовремя не ответил :)

Статистический анализ рыночных движений и их прогнозов Статистический анализ рыночных движений и их прогнозов
В данной статье рассматриваются широкие возможности статистического подхода к изучению рынка. К сожалению, трейдеры-новички сознательно не используют эту поистине могущественную науку – статистику. А ведь, во-первых, это - единственное, чем они пользуются подсознательно при анализе рынка, а во-вторых, статистика может дать ответы на многие вопросы.
Интеграция MetaTrader 4  с MS SQL-сервером Интеграция MetaTrader 4 с MS SQL-сервером
В статье показан пример интеграции клиентского терминала MetaTrader 4 и сервером MS SQL посредством использования dll. Приложены как исходные коды на С++ и MQL4, так и готовый скомпилированный проект Visual C++ 6.0 SP5.
Записки дилетанта. ZigZag… Записки дилетанта. ZigZag…
Наверняка каждого начинающего трейдера, впервые увидевшего “загадочную” ломаную, посещала “шальная” мысль торговать вблизи экстремумов. Ведь это так “просто”. Вот максимум. А здесь был минимум. Красивая картинка на истории. А что на деле? Луч нарисовался. Казалось бы, вот она - вершина. Пора продавать. Сейчас пойдем вниз. Но - нет. Цена по-прежнему предательски идет вверх. М-да! Ерунда, а не индикатор. На помойку его!
Неторгующий эксперт тестирует индикаторы Неторгующий эксперт тестирует индикаторы
Все индикаторы можно разделить на две группы: статические - изображение которых на истории остается статичным и не меняется с приходом новых котировок, и динамические - которые отображают свое состояние только для текущего момента времени и полностью переририсовываются при приходе новой цены. Работопригодность статического индикатора видна сразу на графике, а вот как проверить, что динамический индиктор работает правильно? Этому вопросу и посвящена данная статья.