//+---------------------------------------------------------------------+
//|                                           Gliding Channels [CF].mq4 |
//|                                                      Crazy_Fox [UA] |
//|                                            e-mail: crazy_fox@ua.fm  |
//|                                                        ICQ: 529330  |
//|   ДЛЯ НЕКОММЕРЧЕСКОГО ИСПОЛЬЗОВАНИЯ, ПУБЛИКАЦИЯ РАЗРЕШЕНА ТОЛЬКО С  |
//| УКАЗАНИЕМ ПЕРВОИСТОЧНИКА (http://www.community.finlist.org)         |
//| И ИМЕНИ АВТОРА (Crazy_Fox [UA])                                     |
//|   РЕДАКТИРОВАНИЕ ИСХОДНОГО КОДА РАЗРЕШАЕТСЯ ТОЛЬКО ПРИ УСЛОВИИ      |
//| СОХРАНЕНИЯ ДАННОГО ТЕКСТА, АДРЕСОВ И ССЫЛОК. ПРОДАЖА, ИНДИКАТОРА,   |
//| ОТДЕЛЬНЫХ ЧАСТЕЙ ИСХОДНОГО КОДА, ГРАФИКОВ, ИМ ПОСТРОЕННЫХ ЗАПРЕЩЕНА |
//|   АВТОР НЕ НЕСЁТ ОТВЕТСТВЕННОСТИ ЗА ВОЗМОЖНЫЕ УБЫТКИ, ПОЛУЧЕННЫЕ    |
//| В РЕЗУЛЬТАТЕ РАБОТЫ ИНДИКАТОРА                                      |
//|         Скользящие каналы Баришпольца                               |
//| Каналы строятся по трем последним экстремумам - линия по двум       |
//| низам и параллельная через вершину, или наоборот, линия по двум     |
//| вершинам и параллельная по низу. Линии строятся ПО МАКСИМАЛЬНЫМ     |
//| (МИНИМАЛЬНЫМ) ЗНАЧЕНИЯМ, то есть по теням свечей. Экстремум         |
//| идентифицируется при не менее 2 свечек до и 2 свечек после его      |
//| прохождения. То есть для максимума необходимо не менее 2 свечек     |
//| меньше максимальной свечи до, и не менее 2 свечек меньше максимума  |
//| - после. Расстояние между соседними экстремумами не ограничивается. |
//| Встречаются "групповые экстремумы" - две или даже три свечи с       |
//| практически одинаковыми максимумами (минимумами). Идентифицируем их |
//| как один экстремум, линию канала проводим через верх (низ) правой   |
//| из них.                                                             |
//+---------------------------------------------------------------------+
#property copyright "Crazy_Fox [UA]"
#property link      "http://finlist.ru"
#property indicator_chart_window
//----
extern int   Start_Bar       = 2;
extern int   Line_Width      = 2;
extern int   Num_of_Channels = 1;
extern int   Sensitivity     = 0;
extern bool  Show_Labels     = true;
extern bool  Channel_as_Ray  = true;
extern bool  Show_Alerts     = true;
extern color Channel_Color1  = Blue;
extern color Channel_Color2  = LightSkyBlue;
extern color Channel_Color3  = DeepPink;
extern color Channel_Color4  = DodgerBlue;
extern color Channel_Color5  = PaleGreen;
extern color Channel_Color6  = DarkOrange;
extern color Channel_Color7  = DodgerBlue;
extern color Channel_Color8  = Yellow;
//----
double x1 = 0, y1 = 0,
       x2 = 0, y2 = 0,
       x_l = 0, y_l = 0,
       x_f = 0, y_f = 0,
       x_m = 0, y_m = 0,
       step = 0,
       l_border = 0, h_border=0,
       Price = 0;
bool main_is_up = true, price_at_border = false;
int CurrentBar = 0,
    Extremum[3],
    TempExtremum[3],
    Colors[8],
    f_bar = 0, m_bar = 0, l_bar = 0;
//+------------------------------------------------------------------+
//| init                                                             |
//+------------------------------------------------------------------+
int init()
  {
   Colors[0] = Channel_Color1;
   Colors[1] = Channel_Color2;
   Colors[2] = Channel_Color3;
   Colors[3] = Channel_Color4;
   Colors[4] = Channel_Color5;
   Colors[5] = Channel_Color6;
   Colors[6] = Channel_Color7;
   Colors[7] = Channel_Color8;
   ArrayInitialize(Extremum, 0);
   ArrayInitialize(TempExtremum, 0);
   return(0);
  }
//+------------------------------------------------------------------+
//|  deinit                                                          |
//+------------------------------------------------------------------+
int deinit()
  {
   // В цикле удаляем все отрисованные объекты
   for (int i = 1; i <= Num_of_Channels; i++)
     {
       ObjectDelete("Channel_"+i);
       if(Show_Labels)
         {
           ObjectDelete("Extremum_1_" + i);
           ObjectDelete("Extremum_2_" + i);
           ObjectDelete("Extremum_3_" + i);
         }
     }
   Comment(" ");
   ArrayInitialize(Extremum, 0);
   ArrayInitialize(TempExtremum, 0);
   return(0);
  }
//+------------------------------------------------------------------+
//|  min_ext                                                         |
//+------------------------------------------------------------------+
int min_ext(int bar)
  {
   int find, i, result;
   result = 0;
   i = bar;
   find = 0;
   while(find != 1)
     {
       if((Low[i-2] >= Low[i]) && (Low[i-1] >= Low[i]) && (Low[i] <= Low[i+1]) &&
          (Low[i] <= Low[i+2]))
         { 
           // Если i меньше либо равно двум близстоящим свечам и соседям этих свечей - 
           // это наш минимум
           result=i;
           find++;
         }
       i++;
     }
   return(result);
  }
//+------------------------------------------------------------------+
//|  max_ext                                                         |
//+------------------------------------------------------------------+
int max_ext(int bar)
  {
   int find, i, result;
   result = 0;
   i = bar;
   find = 0;
   while(find != 1)
     {
       if((High[i-2] <= High[i]) && (High[i-1] <= High[i]) && (High[i] >= High[i+1]) &&
          (High[i] >= High[i+2]))
         { 
           // Если i больше либо равно двум близстоящим свечам и соседям этих свечей - 
           // это наш максимум
           result=i;
           find++;
         }
       i++;
     }
   return(result);
  }
//+------------------------------------------------------------------+
//|  find_extremums                                                  |
//+------------------------------------------------------------------+
void find_extremums(int i)
  {
   ArrayInitialize(Extremum, 0);
// Ищем первый минимум, определяем координаты
   Extremum[0] = min_ext(i); 
   y1=Low[Extremum[0]];  
   x1=Time[Extremum[0]]; 
// Ищем первый максимум, определяем координаты
   Extremum[1] = max_ext(i); 
   y2=High[Extremum[1]]; 
   x2=Time[Extremum[1]];    
// Если минимум встречается раньше максимума - третья экстремум ищем внизу
   if(Extremum[0] < Extremum[1])
     {
       // Функция min_ext возвращает номер первого минимума, поиск начинается с
       Extremum[2] = min_ext(Extremum[1]);  
       y_l = Low[Extremum[2]];
       x_l = Time[Extremum[2]];
       y_f = y1; 
       x_f = x1;
       y_m = y2; 
       x_m = x2;
       f_bar = Extremum[0]; 
       m_bar = Extremum[1]; 
       l_bar = Extremum[2];
       main_is_up = false;
     }
   if(Extremum[0] > Extremum[1])
     {
       Extremum[2] = max_ext(Extremum[0]);
       y_l = High[Extremum[2]];
       x_l = Time[Extremum[2]];
       y_f = y2; 
       x_f = x2;
       y_m = y1; 
       x_m = x1;
       f_bar = Extremum[1]; 
       m_bar = Extremum[0]; 
       l_bar = Extremum[2];
       main_is_up = true;
     }
   if(Extremum[0] == Extremum[1])
       if(min_ext(Extremum[0] + 1) < max_ext(Extremum[0] + 2))
         {
           Extremum[2] = min_ext(Extremum[0] + 2);
           y_l = Low[Extremum[2]]; 
           x_l = Time[Extremum[2]];
           y_f = y1; 
           x_f = x1;
           y_m = y2; 
           x_m = x2;
           f_bar =Extremum[0]; 
           m_bar = Extremum[1]; 
           l_bar = Extremum[2];
           main_is_up = false;
         }
       else
         {
           Extremum[2] = max_ext(Extremum[0] + 2);
           y_l = High[Extremum[2]]; 
           x_l = Time[Extremum[2]];
           y_f = y2; 
           x_f = x2;
           y_m = y1; 
           x_m = x1;
           f_bar = Extremum[0]; 
           m_bar = Extremum[1]; 
           l_bar = Extremum[2];
           main_is_up = true;
         }
  }
//+------------------------------------------------------------------+
//| indicator start function                                         |
//+------------------------------------------------------------------+
int start()
  {
   int n = 1, c = 0, i = 0;  // Счётчик каналов и счётчик цветов
   if(Start_Bar > 0) 
       CurrentBar = Start_Bar; 
   else 
       CurrentBar = 2; //Текущий бар - 2 (для подтверждения экстремума)
   ArrayInitialize(TempExtremum, 0);
   find_extremums(CurrentBar);
// На сколько изменяется цена с каждой последующей свечёй
   step = (y_f - y_l) / (l_bar - f_bar);
   if(main_is_up)
     {
       h_border = High[f_bar] + step*f_bar;
       l_border = Low [m_bar] + step*m_bar;
     }
   else
     {
       l_border = Low [f_bar] + step*f_bar;
       h_border = High[m_bar] + step*m_bar;
     }
// Если достигли верхней границы канала
   if((Bid >= (h_border - Sensitivity*Point)) && (Bid <= (h_border + Sensitivity*Point)))
     {
       if(Show_Alerts) 
           Alert("Верх канала - продажа.");  
     }
// Если достигли нижней границы канала
   if((Ask <= (l_border + Sensitivity*Point)) && (Ask >= (l_border - Sensitivity*Point)))
     {
       if(Show_Alerts) 
           Alert("Низ канала - покупка");
     }
   deinit();
   Comment("Параметры канала:\nШирина = ", (h_border - l_border) / Point, "; Наклон = ", 
           -step / Point, ";\nВерхняя граница = ", DoubleToStr(h_border, Digits), 
           "; Нижняя граница = ", DoubleToStr(l_border, Digits), ";");  
// В цикле от 1 до Num_of_Channels расчитываем экстремумы и рисуем канал с номером N
   while(n <= Num_of_Channels)
     {
       TempExtremum[0] = Extremum[0];
       TempExtremum[1] = Extremum[1];
       TempExtremum[2] = Extremum[2];
       find_extremums(CurrentBar);
       if((TempExtremum[0] == Extremum[0]) && (TempExtremum[1] == Extremum[1]) && 
          (TempExtremum[2] == Extremum[2])) 
           CurrentBar++;
       else
         {
           //SetIndexStyle(0, DRAW_ARROW);
           //SetIndexArrow(0, 164);
           //SetIndexBuffer(0, ExtMapBuffer);
           //SetIndexEmptyValue(0, 0.0);
           if(Show_Labels)
             {
               ObjectCreate("Extremum_1_" + n, OBJ_ARROW, 0, x1, y1); 
               ObjectSet("Extremum_1_" + n, OBJPROP_COLOR, Colors[c]); 
               ObjectSet("Extremum_1_" + n, OBJPROP_WIDTH, 1); 
               ObjectSet("Extremum_1_" + n, OBJPROP_ARROWCODE, SYMBOL_LEFTPRICE); 
               ObjectSet("Extremum_1_" + n, OBJPROP_STYLE, STYLE_SOLID);
               ObjectCreate("Extremum_2_" + n, OBJ_ARROW, 0, x2, y2); 
               ObjectSet("Extremum_2_" + n, OBJPROP_COLOR, Colors[c]); 
               ObjectSet("Extremum_2_" + n, OBJPROP_WIDTH, 1); 
               ObjectSet("Extremum_2_" + n, OBJPROP_ARROWCODE, SYMBOL_LEFTPRICE); 
               ObjectSet("Extremum_2_" + n, OBJPROP_STYLE, STYLE_SOLID);
               ObjectCreate("Extremum_3_" + n, OBJ_ARROW, 0, x_l, y_l); 
               ObjectSet("Extremum_3_" + n, OBJPROP_COLOR, Colors[c]); 
               ObjectSet("Extremum_3_" + n, OBJPROP_WIDTH, 1); 
               ObjectSet("Extremum_3_" + n, OBJPROP_ARROWCODE, SYMBOL_RIGHTPRICE); 
               ObjectSet("Extremum_3_" + n, OBJPROP_STYLE, STYLE_SOLID);
             }
           ObjectCreate("Channel_" + n, OBJ_CHANNEL, 0, x_l, y_l, x_f, y_f, x_m, y_m);
           ObjectSet("Channel_" + n, OBJPROP_COLOR, Colors[c]); 
           ObjectSet("Channel_" + n, OBJPROP_WIDTH, Line_Width); 
           ObjectSet("Channel_" + n, OBJPROP_RAY, Channel_as_Ray);
           ObjectSet("Channel_" + n, OBJPROP_STYLE, STYLE_SOLID);
           n++;
           if(c < 7) 
               c++; 
           else 
               c=0;
         }
       CurrentBar++;
     }
   return(0);
  }
//+------------------------------------------------------------------+

