//+----------------------------------------------------------------------------+
//|                                                  AverageStatistic1.07.mq4  |
//|                                                                            |
//|  09.07.2017  Скрипт/Советник для расчёта:                                  |
//|              средней волатильности инструмента High-Low                    |
//|              среднего размера тела свечи       ABS(Open-Close)             |
//|              среднего размера тени свечи                                   |
//|              среднего размера верхней и нижней свечи                       |
//|              а также максимальные значения указанных параметров            |
//+----------------------------------------------------------------------------+
#property copyright "Usver73"
#property version   "1.07"
//#property strict
//#property show_inputs           //Скрипт
#property indicator_chart_window  //Индикатор

extern datetime BeginDateCalc = D'2017.12.01 16:00:00';
extern datetime EndDateCalc   = D'2017.12.01 19:59:59';
extern string aa1="ИНТРАДЕЙ ПЕРИОДЫ";
extern int      IDbegin       =0;//Интрадей начало  периода, час
extern int      IDlenth       =2;//Интрадей продолжительность периода, час
extern string aa3="-----------------------";
//extern bool     SetChart      =false;//Очищать чарт и устанавливать цвета
//------------------------------------------------------------------+
//    входные параметры инфопанели
//------------------------------------------------------------------+
input string          aa6="НАСТРОЙКИ ИНФОРМАЦИОННОЙ ПАНЕЛИ";//    
                
extern  int            ShiftCol      = 320;               //ширина между столбцами
extern  int            ShiftRow      = 160;               //высота между строк
extern  int            StartShiftX   = 20;               // смещение от левого края
extern  int            StartShiftY   = 20;               // смещение от верхнего края
extern  int            FontSize      = 9;                //Размер шрифта

input color           BackColor     = clrWhiteSmoke;          //Цвет фона
input color           FontColor     = clrDarkBlue;          //Цвет шрифта 
int                   PanelCorn     = CORNER_LEFT_UPPER; // Угол расположения инфопанели на графике 
int                   CountBlock    =6; //кличество выводимых блоков     
int                   handle;    
bool                  Work          =true;    
string                s0,s1,s2;
double                maxPrice=0, minPrice=0; //максимальная / минимальная цена за период
//int                   dig=4;   //Кол-во знаков после запятой
//+----------------------------------------------------------------------------+
//|  script program start function                                             |
//+----------------------------------------------------------------------------+
/* Описание индексов в массиве

0	Все свечи	Колич. свечей	            Весь период
1	Свечи BUY	Сумма. р-р свечи	         Понедельник
2	Свечи SELL	Сумма. р-р тела	         Вторник
3	            Сумма. р-р верхней тени	   Среда
4	            Сумма. р-р нижней тени	   Четверг
5	            Макс. свеча	               Пятница
6	            Макс. тело	               1 Intraday
7	            Макс. верхняя тень	      2 Intraday
8	            Макс. нижняя тень	         3 Intraday
9			                                 4 Intraday
*/
int DataArr[3][9][12];                        //Массив с данными
int ExpArr[3][9][12];            //массив с подготовленными данными

string NameGrCdl [3]  ={"ALL", "BUY","SELL"}; //массив с названиями групп по типу свечей
                                              //массив с названиями групп периодов
string NamePrm [9]  ={
                      "Кол-во.свечей      ", 
                      "Средн. р-р свечи   ", 
                      "Средн. р-р тела    ", 
                      "Средн. р-р Up тени ", 
                      "Средн. р-р Dn тени ",
                      "Макс.  свеча       ", 
                      "Макс.  тело        ", 
                      "Макс.  Up тень     ",
                      "Макс.  Dn тень     "
                      };
                                               //массив с названиями групп периодов
string NameGr [12] ={"Весь период", "Понедельник","Вторник","Среда","Четверг","Пятница", 
                     "Неделя с ", "ПН. с ", "ВТ. с ", "СР. с ", "ЧТ. с ", "ПТ. с "}; 
string shortname;                      
//================================================================
void init() 
{
 Work=true;
 if (IDlenth !=0)
  {
   CountBlock=12;
   int EndHour     = IDbegin+IDlenth;
  // int LenthPeriod = IDlenth;
   if (EndHour >=24) {EndHour=24; IDlenth=24-IDbegin;}
   //Print ("EndHour ", EndHour);
   for (int n=6;n<=11;n++)
     {
      NameGr[n]=StringConcatenate(NameGr[n], IDbegin, ":00 до ", EndHour-1, ":59. Длина ",IDlenth,"ч.");
     } 
  }
  PutRectangle("lbl_background", StartShiftX-10, StartShiftY-10, ShiftCol*3,55+55*CountBlock,CORNER_LEFT_UPPER, BackColor);
  PutButton("lblClose","X",ShiftCol*3-30);
  PutButton("lblRecalc","O",ShiftCol*3-50);
  
  shortname= "AverageSat_" + Symbol() + "_" + GetNameTF(Period());
  IndicatorSetString(INDICATOR_SHORTNAME,shortname);
  //if (Digits==2 || Digits==3) dig=2;
}
//================================================================
void start() 
{
  if(!Work)return;// Если был проход, то выход
  int    i, b=0, bb=0;
  ArrayInitialize (DataArr,0);
  ArrayInitialize (ExpArr,0);
  
  for (i=Bars; i>0; i--) 
  {
    if ((Time[i]>=BeginDateCalc && Time[i]<=EndDateCalc )) 
    {
      int BarHour = TimeHour (Time[i]);     // час бара
      int DayW    = TimeDayOfWeek(Time[i]); //день недели бара
      
      if (maxPrice < High[i])                 maxPrice= High[i];// поиск максимальной цены за период
      if (minPrice > Low[i] || minPrice==0 )  minPrice= Low[i]; // поиск минимальной цены за период
      GetStat(i,0);                                             //статистика за весь период
      GetStat(i,DayW);                                          // статистика по дням недели
      
      if (IDlenth!=0 && IDbegin <= BarHour && BarHour < (IDbegin+IDlenth))
       {
        GetStat(i,6);                       //статистика за все дни в период IntraDay
        GetStat(i,6+DayW);                  //статистика по дням недели в период IntraDay
       }
    }
  }
  
  string FirstTime= TimeToStr(BeginDateCalc,TIME_DATE | TIME_MINUTES);
  if (BeginDateCalc < iTime(NULL,0,Bars-1))
   {
    string TimeFirstBar= TimeToString(iTime(NULL,0,Bars-1));
    string str = "На графике "+IntegerToString(Bars-1)+" баров. Начальная дата "+ TimeToStr(BeginDateCalc)+ " меньше даты самого раннего бара "+ TimeFirstBar;
    Alert(str);
    FirstTime= TimeToStr(BeginDateCalc,TIME_DATE | TIME_MINUTES)+ "("+ TimeFirstBar  +")";
   } 
  
  //Рисуем заголовок по инструменту и фон
  
   string LastTime= TimeToStr(EndDateCalc,TIME_DATE | TIME_MINUTES);
    //меньшее время между текущим и заданным в настройках вр. окончания. Для заголовка
   if (TimeCurrent() < EndDateCalc) LastTime=TimeToStr(TimeCurrent(),TIME_DATE | TIME_MINUTES);// Print("TimeCurrent ", TimeCurrent());}

   string filename = "AverageStat_" + Symbol() + "_" + GetNameTF(Period()) +".csv";
   handle=FileOpen(filename,FILE_CSV|FILE_READ|FILE_WRITE," ");
   if (handle < 0) Print("Error: file " + filename + " cannot be created");
   while (!FileIsEnding(handle)) string data = FileReadString(handle);  
   
   //пишем заголовок на экран 
   s0=StringConcatenate(Symbol(),", ",GetNameTF(Period()),", значность ", _Digits);
   PutLabel("lbl_Head0", StartShiftX ,StartShiftY, s0,PanelCorn,FontSize+2, clrGreen);// заголовок Группы периода
   
   s0=StringConcatenate("Период с ", FirstTime, " по ",LastTime);
   PutLabel("lbl_Head01", StartShiftX ,StartShiftY+20, s0,PanelCorn,FontSize+2, clrGreen);
   
   s0= StringConcatenate("Макс. цена ", DoubleToStr(maxPrice,_Digits), " Мин.цена ", DoubleToStr(minPrice,_Digits),
                         " Размах ", (maxPrice-minPrice)/_Point , " пп");
   PutLabel("lbl_Head02", StartShiftX ,StartShiftY+40, s0,PanelCorn,FontSize+2, clrGreen);// информация о макс. и мин. цене
   // пишем заголовок в файл
   FileWrite(handle, StringConcatenate(Symbol(), ";TF= ",GetNameTF(Period()),";",TimeToStr(BeginDateCalc,TIME_DATE | TIME_MINUTES),";", LastTime));
   FileWrite(handle,"Максимальная цена;", DoubleToStr(maxPrice,_Digits), ";Минимальная цена;", DoubleToStr(minPrice,_Digits), ";Размах;",((maxPrice-minPrice)/_Point) );
  
  //DrawBlock(0);// вывод на экран и в файл блоков по всему периоду
  
  for (int d=0; d<=CountBlock-1;d++)
   {
    DrawBlock(d);// вывод на экран и в файл блоков по всему периоду
   }
  Print("Конец работы индикатора");
  FileClose(handle);
  ChartSetInteger (0,CHART_FOREGROUND,false);
  ChartRedraw(0);
  Work=false;
}
//================================================================
void DrawBlock(int g)//g- номер периода
 {
  //+------------------------------------------------------------------+
//|  Создание ИНФО панели                                            |
//+------------------------------------------------------------------+
 string LBLname="lbl"+IntegerToString(g); 
 int x, y;

 for (int n=0; n<3; n++)
  {
    //Print(__FUNCTION__ ": Group = ", n," Block = ",g,  " DataArr[n][0][g] ",DataArr[n][0][g]);
    if (DataArr[n][0][g] !=0){// break;
    
    ExpArr[n][0][g]=DataArr[n][0][g];                   // Использовано баров
    ExpArr[n][1][g]=DataArr[n][1][g] / DataArr[n][0][g];// Средняя волатильность
    ExpArr[n][2][g]=DataArr[n][2][g] / DataArr[n][0][g];//Средний размер тела 
    ExpArr[n][3][g]=DataArr[n][3][g] / DataArr[n][0][g];//Средний размер верхней тени
    ExpArr[n][4][g]=DataArr[n][4][g] / DataArr[n][0][g];//Средний размер нижней тени 
    ExpArr[n][5][g]=DataArr[n][5][g];                   //Максимальная волатильность
    ExpArr[n][6][g]=DataArr[n][6][g];                   //Максимальный размер тела  
    ExpArr[n][7][g]=DataArr[n][7][g];                   //Максимальный размер верхней тени
    ExpArr[n][8][g]=DataArr[n][8][g];                   //Максимальный размер нижней тени
   } 
  } 

 int row=(int)MathFloor((g)/3);
 int col=g-row*3;
 x = StartShiftX+ShiftCol*col;
 y = StartShiftY+20+ShiftRow*row;
 y=y+40;
 PutLabel(StringConcatenate(LBLname,"HeadGr"),   x , y, NameGr[g],   PanelCorn,   FontSize+2, clrBrown);// заголовок Группы периода
 FileWrite(handle,NameGr[g]);
 s1=s1+NameGr[g]+GetFixStr(" ",4);
 y=y+20; 
 string sHeadGrC=StringConcatenate("ПАРАМЕТР             ",NameGrCdl[0],"     ",NameGrCdl[1],"     ",NameGrCdl[2]);
 PutLabel(StringConcatenate(LBLname,"HeadGrC"),x ,y,sHeadGrC ,   PanelCorn,   FontSize,  clrFireBrick);//шапка таблицы
 FileWrite(handle,StringConcatenate("ПАРАМЕТР;",NameGrCdl[0],";",NameGrCdl[1],";",NameGrCdl[2]));
 s2=s2+sHeadGrC+GetFixStr(" ",4);
 y=y+15;

 
 for (int i=0; i< ArraySize(NamePrm); i++)
  {
   string sg0= GetFixStr(IntegerToString(ExpArr[0][i][g]),8);
   string sg1= GetFixStr(IntegerToString(ExpArr[1][i][g]),8);
   string sg2= GetFixStr(IntegerToString(ExpArr[2][i][g]),8);
   PutLabel(StringConcatenate(LBLname,i),x ,y+ (12*i), StringConcatenate(NamePrm[i],": ", sg0,sg1,sg2),PanelCorn,FontSize,  FontColor);
   FileWrite(handle,StringConcatenate(NamePrm[i],":;", sg0 , ";",sg1,";",sg2));
  }
 FileWrite(handle,"--------");
 }
 
 //-------------Возвращает строку определенной длины-------------
 string GetFixStr(string str,int len)//str- исходная строка, len- конечная длина
  {
    int     AddCountChr = len- StringLen (str);
    string  AddStr ="";
    StringInit (AddStr,AddCountChr,032);
    return(str+AddStr);
  }
//+------------------------------------------------------------------+
//|  Создание контрола "LABLE"                                       |
//+------------------------------------------------------------------+
void PutLabel(string name,int x,int y,string text,int coner, int w, color clr)
  {
   if (ObjectFind(name)<0)ObjectCreate(0,name,OBJ_LABEL,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
   ObjectSetInteger(0,name,OBJPROP_CORNER,coner);
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
   ObjectSetInteger(0,name,OBJPROP_BACK,false);
   ObjectSetText(name,text,w,"Courier New",clr);
  } 
void PutButton(string name, string txt, int x)
  {
  ObjectCreate(0,name,OBJ_BUTTON,0,0,0);
  ObjectSetText(name,txt,10,"Arial");  
  ObjectSetInteger(0,name,OBJPROP_BGCOLOR,clrDodgerBlue);
  ObjectSetInteger(0,name,OBJPROP_COLOR,clrWhite);
  ObjectSetInteger(0,name,OBJPROP_CORNER,CORNER_LEFT_UPPER);
  ObjectSetInteger(0,name,OBJPROP_XDISTANCE,StartShiftX+x);
  ObjectSetInteger(0,name,OBJPROP_YDISTANCE,StartShiftY);
  ObjectSetInteger(0,name,OBJPROP_XSIZE ,15);

  
  }  
//================================================================
void GetStat(int k, int i) // k- номер бара, i- период
{
  int    CandleSize =(int) NormalizeDouble( (High[k]-Low[k])/_Point,0);
  int    BodySize   =(int) NormalizeDouble(  MathAbs(Open[k]-Close[k])/_Point,0); 
  int    UpShd, DnShd;
  
//============ параметры свечи  ===================================================      
      DataArr[0][0][i]++;                     //Количество свечей
      DataArr[0][1][i]+= CandleSize;          //Накопительный размер свеч
      DataArr[0][2][i]+= BodySize;            //Накопительный размер тел свеч
      if (DataArr[0][5][i] < CandleSize) DataArr[0][5][i] = CandleSize; //Запись максимального размера свечи
      if (DataArr[0][6][i] < BodySize  ) DataArr[0][6][i] = BodySize;   //Запись максимального размера  тела свечи
      
//============параметры, зависящие от направления свечи=============================       
      
      if (Open[k]<Close[k]) //для БАЙ свечи
      {
        UpShd=(int)NormalizeDouble((High[k]-Close[k])/_Point,0);                        //Размер верхней тени
        DnShd=(int)NormalizeDouble((Open[k]-Low[k])  /_Point,0);                        //Размер нижней тени
        
        // Записываем для всех свечей
        DataArr[0][3][i]+=UpShd;                               //Накопительный размер верхних теней
        DataArr[0][4][i]+=DnShd;                               //Накопительный размер нижних теней
        if(DataArr[0][7][i] < UpShd) DataArr[0][7][i] = UpShd; //Запись максимального размера верхней тени
        if(DataArr[0][8][i] < DnShd) DataArr[0][8][i] = DnShd; //Запись максимального размера нижней тени
        
        // Записываем для БАЙ- группы
        DataArr[1][0][i]++;                                    //Количество свечей БАЙ
        DataArr[1][1][i]+= CandleSize;                         //Накопительный размер свеч БАЙ
        DataArr[1][2][i]+= BodySize;                           //Накопительный размер тел свеч БАЙ
        if (DataArr[1][5][i] < CandleSize) DataArr[1][5][i] = CandleSize; //Запись максимального размера свечи БАЙ
        if (DataArr[1][6][i] < BodySize  ) DataArr[1][6][i] = BodySize;   //Запись максимального размера  тела свечи БАЙ
        
        DataArr[1][3][i]+=UpShd;                               //Накопительный размер верхних теней БАЙ
        DataArr[1][4][i]+=DnShd;                               //Накопительный размер нижних теней БАЙ
        if(DataArr[1][7][i] < UpShd) DataArr[1][7][i] = UpShd; //Запись максимального размера верхней тени БАЙ
        if(DataArr[1][8][i] < DnShd) DataArr[1][8][i] = DnShd; //Запись максимального размера нижней тени БАЙ
        
      } 
      else // для СЕЛЛ свечи
      {
        UpShd =(int)NormalizeDouble((High[k]-Open[k])/Point,0);                      //Размер верхней тени
        DnShd =(int)NormalizeDouble((Close[k]-Low[k])/Point,0);                      //Размер нижней тени      
        
        // Записываем для всех свечей
        DataArr[0][3][i]+=UpShd;                               //Накопительный размер верхних теней
        DataArr[0][4][i]+=DnShd;                               //Накопительный размер нижних теней
        if(DataArr[0][7][i] < UpShd) DataArr[0][7][i] = UpShd; //Запись максимального размера верхней тени
        if(DataArr[0][8][i] < DnShd) DataArr[0][8][i] = DnShd; //Запись максимального размера нижней тени
        
        // Записываем для СЕЛЛ- группы
        DataArr[2][0][i]++;                                    //Количество свечей СЕЛЛ
        DataArr[2][1][i]+= CandleSize;                         //Накопительный размер свеч СЕЛЛ
        DataArr[2][2][i]+= BodySize;                           //Накопительный размер тел свеч СЕЛЛ
        if (DataArr[2][5][i] < CandleSize) DataArr[2][5][i] = CandleSize; //Запись максимального размера свечи СЕЛЛ
        if (DataArr[2][6][i] < BodySize  ) DataArr[2][6][i] = BodySize;   //Запись максимального размера  тела свечи СЕЛЛ
        
        DataArr[2][3][i]+=UpShd;                               //Накопительный размер верхних теней СЕЛЛ
        DataArr[2][4][i]+=DnShd;                               //Накопительный размер нижних теней СЕЛЛ
        if(DataArr[2][7][i] < UpShd) DataArr[2][7][i] = UpShd; //Запись максимального размера верхней тени СЕЛЛ
        if(DataArr[2][8][i] < DnShd) DataArr[2][8][i] = DnShd; //Запись максимального размера нижней тени СЕЛЛ
      }
     //Print(__FUNCTION__ , " Count ALL ", DataArr[0][0][i], " Count BUY ",DataArr[1][0][i], " Count SELL ",DataArr[2][0][i]) ;
}
//+----------------------------------------------------------------------------+
//|  Автор    : Ким Игорь В. aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Версия   : 01.09.2005                                                     |
//|  Описание : Возвращает наименование таймфрейма                             |
//+----------------------------------------------------------------------------+
//|  Параметры:                                                                |
//|    TimeFrame - таймфрейм (количество секунд)      (0 - текущий TFmain)     |
//+----------------------------------------------------------------------------+
string GetNameTF(int TimeFrame=0) {
  if (TimeFrame==0) TimeFrame=Period();
  switch (TimeFrame) {
    case PERIOD_M1:  return("M1");
    case PERIOD_M5:  return("M5");
    case PERIOD_M15: return("M15");
    case PERIOD_M30: return("M30");
    case PERIOD_H1:  return("H1");
    case PERIOD_H4:  return("H4");
    case PERIOD_D1:  return("Daily");
    case PERIOD_W1:  return("Weekly");
    case PERIOD_MN1: return("Monthly");
    default:         return("UnknownPeriod");
  }
}
//+------------------------------------------------------------------+
//|  Создание контрола Прямоугольник                                 |
//+------------------------------------------------------------------+  
void PutRectangle(string Oname,long x,long y,long xSize, long ySize, int coner, color cl )
{
    if (ObjectFind(Oname)<0)
     { 
      if(!ObjectCreate(0,Oname,OBJ_RECTANGLE_LABEL,0,0,0)) 
       { 
        Print(__FUNCTION__,": не удалось создать прямоугольную метку! Код ошибки = ",GetLastError()); 
       }
     }   
      ObjectSetInteger (0,Oname,OBJPROP_XDISTANCE,x);
      ObjectSetInteger (0,Oname,OBJPROP_YDISTANCE,y);
      ObjectSetInteger (0,Oname,OBJPROP_XSIZE ,xSize);
      ObjectSetInteger (0,Oname,OBJPROP_YSIZE ,ySize);
      ObjectSetInteger (0,Oname,OBJPROP_CORNER,coner);
      ObjectSetInteger (0,Oname,OBJPROP_BGCOLOR,cl);  
      ObjectSetInteger (0,Oname,OBJPROP_BORDER_TYPE,BORDER_FLAT); 
      ObjectSetInteger (0,Oname,OBJPROP_BACK,false);
} 
//---------Реакция на события-------------------------  
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//--- проверим событие на нажатие кнопки мышки
   if(id==CHARTEVENT_OBJECT_CLICK)
     {
      string clickedChartObject=sparam;
      if(clickedChartObject=="lblClose")       Remove();
      if(clickedChartObject=="lblRecalc")      Work=true;
      if(ObjectGetInteger(0, clickedChartObject, OBJPROP_STATE)==true)
      {
        Sleep(100);
        ObjectSetInteger(0,clickedChartObject,OBJPROP_STATE,false);
      }
      ChartRedraw();// принудительно перерисуем все объекты на графике
     }
}
void Remove()
{
  DeleteControl();
  ChartRedraw();
  if (ChartIndicatorDelete(0,0,shortname)) Print("Удален индикатор ",shortname);
  else PrintFormat("Не удалось удалить индикатор %s с окна #%d. Код ошибки %d", 
                     shortname,0,GetLastError()); 
}
// Удаляем "наши" контролы
void DeleteControl()
{
    for(int i=ObjectsTotal()-1;i>=0;i--) 
     { 
       string name=ObjectName(i); 
       if (StringFind (name,"lbl",0)>-1) ObjectDelete(name); 
     } 
} 