Зигзаг в советнике. - страница 2

 

Не ругайте художника,

 вижу я так:

struct ZZ
  {
   int               bar;          //номер бара экстремума ЗигЗага
   double            price;        //цена бара экстремума ЗигЗага
  };

ZZ ZigZag[];

input  int size = 20;               //количество экстремум


//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   int i;

   ArrayResize(ZigZag,size);

   for(i=0; i<size; i++)
     {
      ZigZag[i].bar = GetExtremumZZBar(Symbol(),0,i);
      ZigZag[i].price = GetExtremumZZPrice(Symbol(),0,i);
     }


   Comment("\n bar = ",ZigZag[0].bar,"    price = ",ZigZag[0].price,    //в 0 ячейке хранится 0 самый правый экстремум
           "\n bar = ",ZigZag[19].bar,"    price = ",ZigZag[19].price); //в 19 ячейке хранится 20 дальний левый экстремум


  }
//+------------------------------------------------------------------+
//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 07.10.2006                                                     |
//|  Описание : Возвращает номер бара экстремума ЗигЗага по его номеру.        |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    sy - наименование инструмента   (NULL или "" - текущий символ)          |
//|    tf - таймфрейм                  (      0     - текущий ТФ)              |
//|    ne - номер экстремума           (      0     - последний)               |
//|    dp - ExtDepth                                                           |
//|    dv - ExtDeviation                                                       |
//|    bs - ExtBackstep                                                        |
//+----------------------------------------------------------------------------+
int GetExtremumZZBar(string sy="", int tf=0, int ne=0, int dp=12, int dv=5, int bc=3)
  {
   if(sy=="" || sy=="0")
      sy=Symbol();
   double zz;
   int    i, k=iBars(sy, tf), ke=0;

   for(i=0; i<k; i++)
     {
      zz=iCustom(sy, tf, "ZigZag", dp, dv, bc, 0, i);
      if(zz!=0)
        {
         ke++;
         if(ke>ne)
            return(i);
        }
     }
   Print("GetExtremumZZBar(): Экстремум ЗигЗага номер ",ne," не найден");
   return(-1);
  }
//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 07.10.2006                                                     |
//|  Описание : Возвращает экстремум ЗигЗага по его номеру.                    |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    sy - наименование инструмента   (NULL или "" - текущий символ)          |
//|    tf - таймфрейм                  (      0     - текущий ТФ)              |
//|    ne - номер экстремума           (      0     - последний)               |
//|    dp - ExtDepth                                                           |
//|    dv - ExtDeviation                                                       |
//|    bs - ExtBackstep                                                        |
//+----------------------------------------------------------------------------+
double GetExtremumZZPrice(string sy="", int tf=0, int ne=0, int dp=12, int dv=5, int bs=3)
  {
   if(sy=="" || sy=="0")
      sy=Symbol();
   double zz;
   int    i, k=iBars(sy, tf), ke=0;

   for(i=0; i<k; i++)
     {
      zz=iCustom(sy, tf, "ZigZag", dp, dv, bs, 0, i);
      if(zz!=0)
        {
         ke++;
         if(ke>ne)
            return(zz);
        }
     }
   Print("GetExtremumZZPrice(): Экстремум ЗигЗага номер ",ne," не найден");
   return(0);
  }
//+------------------------------------------------------------------+
 
Alekseu Fedotov:

Не ругайте художника,

 вижу я так:

да вариант рабочий - это вариант, который я описал

"limit >1 - нужно считать последние 20 вершин в цикле iCustom(NULL,0,"ZIGZAG,<buffer index>,?); - но мы не знаем сколько баров нужно считать чтобы получить эти 20 вершин, т.е. их нужно считывать до тех пор пока не наберутся эти 20 вершин."

но это не оптимально, потому что на каждом тике будет вызвано 20*Ki раз iCustom, где Ki количество баров до  i-й вершины зиг-зага. 
 
Peter Vorobyev:

да вариант рабочий - это вариант, который я описал

"limit >1 - нужно считать последние 20 вершин в цикле iCustom(NULL,0,"ZIGZAG,<buffer index>,?); - но мы не знаем сколько баров нужно считать чтобы получить эти 20 вершин, т.е. их нужно считывать до тех пор пока не наберутся эти 20 вершин."

но это не оптимально, потому что на каждом тике будет вызвано 20*Ki раз iCustom, где Ki количество баров до  i-й вершины зиг-зага. 

Вызывайте раз в минуту, при закрытии минутного бара

 
Peter Vorobyev:

Поделитесь кто как реализовывает структуру обработки котировок для советника. 

вот можете по тестировать с индикатором rsizig.mq5 с помощью этого эксперта  Semaphore Line.mq5 (348.21 KB)

- вот настроить тут

настройка

настройка 2

настройка 3

Файлы:
rsizig.mq5  18 kb
 
SanAlex:

вот можете по тестировать с индикатором rsizig.mq5 с помощью этого эксперта  Semaphore Line.mq5 (348.21 KB)

- вот настроить тут


посмотрел, в MQL5 есть грамотная функция BarsCalculated, MQL4 - такого нет. Придется все таки возвращать  через буфер разницу 

rates_total - prev_calculated

если эта разница >1 то вызываем iCustom для всех 20-ти вершин, иначе только 0-й индекс.

 
Peter Vorobyev:

посмотрел, в MQL5 есть грамотная функция BarsCalculated, MQL4 - такого нет. Придется все таки возвращать  через буфер разницу 

если эта разница >1 то вызываем iCustom для всех 20-ти вершин, иначе только 0-й индекс.

я влез не в тему - ну мало-ли, может кого и заинтересует.

Снимок 2.PNG

Снимок

Файлы:
Linezig.mq5  36 kb
 
igrok333:

Как?

запустить в цикле поиск от нулевого бара до n-ного?

Нашёл пользовательский индикатор в код базе, который рассчитывает вершины зигзага и приспособил под свои нужды, работает, в код сильно не вникал, по моему цикл перебирает пики а значения берутся из баров

 

Нужно хранить данные внутри советника без вызовов посторонних программ, обращений к истории и лишних циклов. Это индикатор, всё так же в советнике.

#property strict
#property indicator_chart_window
input int Distance=500;    //Минимальное расстояние, пункты

//каждый элемент массива будет содержать три поля: дата, цена и положение экстремума (верх, низ) 
struct Extrem
   {
   datetime time;          //дата окончания тренда
   double price;           //цена окончания тренда
   int direction;          //направление тренда +1/-1
   } extremes[];
//последний элемент массива
int finish;

//текущий символ и таймфрейм
string symbol;
ENUM_TIMEFRAMES frame;

long chart_id;
int window;

//дата окончания обработанного периода
datetime calculation_time=0;
string name;

int OnInit()
   {
   symbol=Symbol();
   frame=(ENUM_TIMEFRAMES)Period();
   chart_id=ChartID();
   window=ChartWindowFind();
   return(INIT_SUCCEEDED);
   }

void OnDeinit(const int eReason)
   {
   //удаляем все нарисованные объекты индикатора
   ObjectsDeleteAll(chart_id,"Mike");
   }

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
   {
   //время окончания цикла
   datetime finish_time=iTime(symbol,frame,0);
   //проходим циклом по всем свечам истории
   do
      {
      //записываем экстремумы в массив
      WriteExtremum(extremes,(double)Distance*Point,symbol,frame,calculation_time);
      
      //последний элемент массива
      finish=ArraySize(extremes)-1;
      //рисуем зиг-заг, если массив заполнен
      if(finish>0)
         {
         //тренд вниз
         if(extremes[finish].direction==-1)
            {
            //сейчас происходит обновление минимума
            if(extremes[finish].time==calculation_time)
               {
               //имя состоит из названия индикатора, направления движения и времени начала движения
               name="Mike_Dn_"+TimeToString(extremes[finish-1].time);
               RedrawLine(chart_id,window,name,extremes[finish-1].time,extremes[finish-1].price,extremes[finish].time,extremes[finish].price,clrRed,1,Digits);
               }
            }
         //тренд вверх
         else
            {
            //сейчас происходит обновление максимума
            if(extremes[finish].time==calculation_time)
               {
               //имя состоит из названия индикатора, направления движения и времени начала движения
               name="Mike_Up_"+TimeToString(extremes[finish-1].time);
               RedrawLine(chart_id,window,name,extremes[finish-1].time,extremes[finish-1].price,extremes[finish].time,extremes[finish].price,clrBlue,1,Digits);
               }
            }      
         }
               
      //переводим время на один бар вперёд в будущее
      if(calculation_time<finish_time)
         {
         calculation_time=iTime(symbol,frame,(iBarShift(symbol,frame,calculation_time)-1));
         }
      else
         {
         break;
         }
      }
   while(calculation_time<=finish_time);
   return(rates_total);
   }

//здесь записываем экстремумы в массив
void WriteExtremum(Extrem &eExtremes[], double eDistance, string eSymbol, ENUM_TIMEFRAMES eTimeFrame, datetime eTime)
   {
   int eFinish=ArraySize(eExtremes)-1;
   int eShift=iBarShift(eSymbol,eTimeFrame,eTime);
   double eHigh=iHigh(eSymbol,eTimeFrame,eShift);
   double eLow=iLow(eSymbol,eTimeFrame,eShift);
   //если массив пустой
   if(eFinish<0)
      {
      ArrayResize(eExtremes,++eFinish+1);
      eExtremes[eFinish].time=eTime;
      //пока мы не знаем какой из экстремумов будет в первом элементе, поэтому берём цену по середине
      //можно сделать более грамотнее, но лень. Поэтому первый экстремум у нас будет бракованный 
      //и мы его потом затрём 
      eExtremes[eFinish].price=(eHigh+eLow)/2;
      eExtremes[eFinish].direction=0;
      }
   //если в массиве есть элементы
   else
      {
      //текущий элемент - максимум
      if(eExtremes[eFinish].direction==1)
         {
         //произошло обновление текущего экстремума
         if(eHigh-eExtremes[eFinish].price>0)
            {
            eExtremes[eFinish].time=eTime;
            eExtremes[eFinish].price=eHigh;
            }    
         else
            {     
            //произошло превышение расстояния между противоположными экстремумами
            if(eExtremes[eFinish].price-eLow>eDistance && eTime-eExtremes[eFinish].time>0)
               {
               ArrayResize(eExtremes,++eFinish+1,10000);
               eExtremes[eFinish].time=eTime;
               eExtremes[eFinish].price=eLow;
               eExtremes[eFinish].direction=-1;
               }
            }
         }
      //текущий элемент - минимум
      if(eExtremes[eFinish].direction==-1)
         {
         //произошло обновление текущего экстремума
         if(eExtremes[eFinish].price-eLow>0)
            {
            eExtremes[eFinish].time=eTime;
            eExtremes[eFinish].price=eLow;
            }    
         else
            {     
            //произошло превышение расстояния между противоположными экстремумами
            if(eHigh-eExtremes[eFinish].price>eDistance && eTime-eExtremes[eFinish].time>0)
               {
               ArrayResize(eExtremes,++eFinish+1,10000);
               eExtremes[eFinish].time=eTime;
               eExtremes[eFinish].price=eHigh;
               eExtremes[eFinish].direction=1;
               }
            }
         }
      //эта ситуация, когда первый элемент не закрылся, и не понятно максимум это будет или минимум
      //если произошло превышение в любую сторону, тогда затираем значения первого элемента
      if(eExtremes[eFinish].direction==0)
         {       
         //произошло превышение расстояния между противоположными экстремумами
         if(eHigh-eExtremes[eFinish].price>eDistance)
            {
            eExtremes[eFinish].time=eTime;
            eExtremes[eFinish].price=eHigh;
            eExtremes[eFinish].direction=1;
            }            
         if(eExtremes[eFinish].price-eLow>eDistance)
            {
            eExtremes[eFinish].time=eTime;
            eExtremes[eFinish].price=eLow;
            eExtremes[eFinish].direction=-1;
            }
         }
      }   
   }

//перерисовывает линию по новым координатам, если её нет, то создаёт
void RedrawLine(long eChartId, int eWindow, string eName, datetime eTime1, double ePrice1, datetime eTime2, double ePrice2, color eColor, int eWidth, int eDigits)
   {
   if(ObjectFind(eChartId,eName)==-1)
      {
      if(!ObjectCreate(eChartId,eName,OBJ_TREND,eWindow,0,0)) return;
      ObjectSetInteger(eChartId,eName,OBJPROP_STYLE,STYLE_SOLID);
      ObjectSetInteger(eChartId,eName,OBJPROP_WIDTH,eWidth);
      ObjectSetInteger(eChartId,eName,OBJPROP_BACK,true);
      ObjectSetInteger(eChartId,eName,OBJPROP_SELECTABLE,false);
      ObjectSetInteger(eChartId,eName,OBJPROP_SELECTED,false);
      ObjectSetInteger(eChartId,eName,OBJPROP_RAY_RIGHT,false);
      ObjectSetInteger(eChartId,eName,OBJPROP_HIDDEN,true);
      }
   if(ObjectFind(eChartId,eName)==-1) return;   
   if(ObjectGetInteger(eChartId,eName,OBJPROP_TIME)!=eTime1) ObjectSetInteger(eChartId,eName,OBJPROP_TIME,eTime1);
   if(NormalizeDouble(ObjectGetDouble(eChartId,eName,OBJPROP_PRICE)-ePrice1,eDigits)!=0) ObjectSetDouble(eChartId,eName,OBJPROP_PRICE,ePrice1);
   if(ObjectGetInteger(eChartId,eName,OBJPROP_TIME,1)!=eTime2) ObjectSetInteger(eChartId,eName,OBJPROP_TIME,1,eTime2);
   if(NormalizeDouble(ObjectGetDouble(eChartId,eName,OBJPROP_PRICE,1)-ePrice2,eDigits)!=0) ObjectSetDouble(eChartId,eName,OBJPROP_PRICE,1,ePrice2);
   if(ObjectGetInteger(eChartId,eName,OBJPROP_COLOR)!=eColor) ObjectSetInteger(eChartId,eName,OBJPROP_COLOR,eColor);
   }