//+------------------------------------------------------------------+
//|                                            FractalsDetector.mq4  |
//|                                         Alexander Kalinovski (c) |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, Alexander Kalinovski"
#property link      "Alexander Kalinovski © 2009"

/**
 * Индикатор для отрисовки фракталов с различных ТФ, а также определения
 * различных фрактальных формаций и их поиска
 */
#property indicator_chart_window
#property indicator_buffers 8

#property indicator_color1 HotPink
#property indicator_color2 Lime
#property indicator_color3 Orange
#property indicator_color4 Blue
#property indicator_color5 Red
#property indicator_color6 Green
#property indicator_color7 Sienna
#property indicator_color8 DarkViolet

// Общие настройки индикатора
extern double P0 = 90;   // Первый ТФ
extern double P1 = 120;  // Второй ТФ
extern double P2 = 180;  // Третий ТФ
extern double P3 = 240;  // Четвертый ТФ
extern double P4 = 360;  // Пятый ТФ
extern double P5 = 480;  // Шестой ТФ
extern double P6 = 720;  // Седьмой ТФ
extern double P7 = 1440; // Восьмой ТФ

extern bool Show_P0 = true;
extern bool Show_P1 = true;
extern bool Show_P2 = true;
extern bool Show_P3 = true;
extern bool Show_P4 = true;
extern bool Show_P5 = true;
extern bool Show_P6 = true;
extern bool Show_P7 = true;

// Код стрелки для отрисовки фракталов
extern int ArrowCode = 108;

// Буферы для значений индикатора
double FractalsBuffer0[];
double FractalsBuffer1[];
double FractalsBuffer2[];
double FractalsBuffer3[];
double FractalsBuffer4[];
double FractalsBuffer5[];
double FractalsBuffer6[];
double FractalsBuffer7[];

#define NONE 0
#define UP 1
#define DOWN -1
#define FS_LENGTH 3
#define START 3
#define DELTA 30
#define YDIST 20

static int periods[8];
static color colors[8];
static bool shows[8];

string GetPeriodName(int period)
{
   switch (period)
   {
      case 90:   return ("M90");
      case 120:  return ("H2");
      case 180:  return ("H3");
      case 240:  return ("H4");
      case 360:  return ("H6");
      case 480:  return ("H8");
      case 720:  return ("H12");
      case 1440: return ("D1");
      default:   return ("M" + period);
   }
}

/**
 * Отображает фрактальную легенду
 */
void ShowLegend()
{
   int start_x = START;
   for (int i = 0; i < 8; i++)
   {
      if (shows[i])
      {
         string pn = "P" + i;
         ObjectCreate(pn, OBJ_LABEL, 0, 0, 0);
         ObjectSetText(pn, GetPeriodName(periods[i]), 8, "Verdana", colors[i]);
         ObjectSet(pn, OBJPROP_XDISTANCE, start_x);  
         ObjectSet(pn, OBJPROP_YDISTANCE, YDIST);
         start_x = start_x + DELTA;   
      }
   }
}

/**
 * Удаляет фрактальную легенду
 */
void RemoveLegend()
{
   ObjectDelete("P0");
   ObjectDelete("P1");
   ObjectDelete("P2");   
   ObjectDelete("P3");   
   ObjectDelete("P4");      
   ObjectDelete("P5");   
   ObjectDelete("P6");      
   ObjectDelete("P7");         
}
 
/**
 * Функция инициализации индикатора
 */
int init()
{
   periods[0] = P0;
   periods[1] = P1;
   periods[2] = P2;
   periods[3] = P3;
   periods[4] = P4;
   periods[5] = P5;
   periods[6] = P6;
   periods[7] = P7;

   shows[0] = Show_P0;
   shows[1] = Show_P1;
   shows[2] = Show_P2;
   shows[3] = Show_P3;
   shows[4] = Show_P4;
   shows[5] = Show_P5;
   shows[6] = Show_P6;
   shows[7] = Show_P7;
   
   colors[0] = indicator_color1;
   colors[1] = indicator_color2;
   colors[2] = indicator_color3;
   colors[3] = indicator_color4;
   colors[4] = indicator_color5;
   colors[5] = indicator_color6;
   colors[6] = indicator_color7;
   colors[7] = indicator_color8;
     
   SetIndexBuffer(0, FractalsBuffer0);
   SetIndexBuffer(1, FractalsBuffer1);
   SetIndexBuffer(2, FractalsBuffer2);
   SetIndexBuffer(3, FractalsBuffer3);
   SetIndexBuffer(4, FractalsBuffer4);
   SetIndexBuffer(5, FractalsBuffer5);
   SetIndexBuffer(6, FractalsBuffer6);
   SetIndexBuffer(7, FractalsBuffer7);   
   
   for (int i = 0; i < 8; i++)
   {
      SetIndexEmptyValue(i, 0.0);   
      SetIndexStyle(i, DRAW_ARROW);
      SetIndexArrow(i, ArrowCode);                    
   }
   
   ShowLegend();
   
   return(0);
}
  
/**
 * Функция деинициализации индикатора
 */
int deinit()
{  
   RemoveLegend();
   return(0);
}

/**
 * Функция определения фракталов
 */
bool Fractal (int f, int per, int shift)
{
   int p = per;
   if (per < Period()) return(-1);   
   per = per / Period() * 2 + MathCeil(per / Period() / 2);   
  
   if (shift < per || shift > Bars - per) return(-1);

   for (int i=1; i <= per; i++)
     {
      if (f == UP)
      {
         if (High[shift + i] >  High[shift]) return(-1);
         if (High[shift - i] >= High[shift]) return(-1);     
      }
      
      if (f == DOWN)
      {
         if (Low[shift + i] <  Low[shift]) return(-1);
         if (Low[shift - i] <= Low[shift]) return(-1);
      }        
   }
   
   return(1);   
}  

void DetectFractal(double& buffer[], int period, int shift)
{
    if (Fractal(UP, period, shift) == 1) 
    {
        buffer[shift] = High[shift];
    } 
    else if (Fractal(DOWN, period, shift) == 1) 
    {
        buffer[shift] = Low[shift];
    }
    else 
    {
       buffer[shift] = 0;
    }
} 

//------------------------------------------------------------------
int start()
{  
   int bars_count = Bars;     
   for (int shift = bars_count; shift > 0; shift--)
   {
       if (shows[0]) DetectFractal(FractalsBuffer0, P0, shift);
       if (shows[1]) DetectFractal(FractalsBuffer1, P1, shift);
       if (shows[2]) DetectFractal(FractalsBuffer2, P2, shift);
       if (shows[3]) DetectFractal(FractalsBuffer3, P3, shift);
       if (shows[4]) DetectFractal(FractalsBuffer4, P4, shift);
       if (shows[5]) DetectFractal(FractalsBuffer5, P5, shift);
       if (shows[6]) DetectFractal(FractalsBuffer6, P6, shift);
       if (shows[7]) DetectFractal(FractalsBuffer7, P7, shift);
   }
      
   return(0);
}