//+------------------------------------------------------------------+
//|                                     clusterbox_histogramm_ad.mq4 |
//|                                        Copyright 2015, Scriptong |
//|                                          http://advancetools.net |
//+------------------------------------------------------------------+
#property copyright "Scriptong"
#property link      "http://advancetools.net"
#property description "English: Displays the ticks volume of specified interval in the form of cluster histogram.\nRussian: Îňîáđŕćĺíčĺ ňčęîâűő îáúĺěîâ çŕäŕííîăî číňĺđâŕëŕ â âčäĺ ăčńňîăđŕěěű ęëŕńňĺđîâ."
#property strict

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

#define MAX_VOLUMES_SHOW      5                                                                    // Ęîëč÷ĺńňâî óđîâíĺé ěŕęńčěŕëüíîăî îáúĺěŕ, ęîňîđűĺ ńëĺäóĺň îňîáđŕćŕňü
#define VIEWRANGE_STARTBAR    10                                                                   // Číäĺęń áŕđŕ, íŕ ęîňîđîě íŕ÷číŕĺňń˙ îáëŕńňü îňîáđŕćĺíč˙ ăčńňîăđŕěěű
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct LevelVolumeColor                                                                            // Ńňđóęňóđŕ ńîîňâĺňńňâč˙ óđîâíĺé îáúĺěŕ, äîńňčćĺíčĺ ęîňîđűő íŕ öĺíîâîě óđîâíĺ îňîáđŕćŕĺňń˙.. 
  {                                                                                                // ..ńîîňâĺňńňâóţůčě öâĺňîě
   color             levelColor;
   int               levelMinVolume;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct TickStruct                                                                                  // Ńňđóęňóđŕ äë˙ çŕďčńč äŕííűő îá îäíîě ňčęĺ
  {
   datetime          time;
   double            bid;
   double            ask;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct ViewRange                                                                                   // Ńňđóęňóđŕ äë˙ çŕďčńč ăđŕíčö číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű
  {
   datetime          leftTime;
   datetime          rightTime;
   int               rightIndex;
   int               rangeDuration;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct LevelsData                                                                                  // Ńňđóęňóđŕ äë˙ çŕďčńč öĺíîâîăî óđîâí˙, ęîëč÷ĺńňâŕ ĺăî ďîâňîđĺíčé, đîńňŕ č ďŕäĺíč˙ öĺíű íŕ číňĺđâŕëĺ îňîáđŕćĺíč˙ ăčńňîăđŕěěű
  {
   double            price;
   int               repeatCnt;
   int               bullsCnt;
   int               bearsCnt;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_YESNO
  {
   YES,                                                                                           // Yes / Äŕ
   NO                                                                                             // No / Íĺň
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum ENUM_LINEWIDTH                                                                                // Ňîëůčíŕ ëčíčé ăčńňîăđŕěěű
  {
   LINEWIDTH_NULL,                                                                                 // Most thin / Íŕčáîëĺĺ ňîíęŕ˙
   LINEWIDTH_ONE,                                                                                  // Thin / Ňîíęŕ˙
   LINEWIDTH_TWO,                                                                                  // Median / Ńđĺäí˙˙
   LINEWIDTH_THREE,                                                                                // Thick / Ňîëńňŕ˙
   LINEWIDTH_FOUR                                                                                  // Most thick / Íŕčáîëĺĺ ňîëńňŕ˙
  };

// Íŕńňđîĺ÷íűĺ ďŕđŕěĺňđű číäčęŕňîđŕ
input int      i_pointsInBox           = 50;                                                       // Points in one cluster / Ęîëč÷ĺńňâî ďóíęňîâ â îäíîě ęëŕńňĺđĺ
input string   i_string1               = "Min volumes and colors / Ěčí. îáúĺěű č öâĺňŕ";           // ==============================================
input int      i_minVolumeLevel1       = 1;                                                        // Minimal volume. Level 1 / Ěčíčěŕëüíűé îáúĺě. Óđîâĺíü 1
input color    i_colorLevel1           = clrSkyBlue;                                               // Color of level 1 / Öâĺň óđîâí˙ 1
input int      i_minVolumeLevel2       = 50;                                                       // Minimal volume. Level 2 / Ěčíčěŕëüíűé îáúĺě. Óđîâĺíü 2
input color    i_colorLevel2           = clrTurquoise;                                             // Color of level 2 / Öâĺň óđîâí˙ 2
input int      i_minVolumeLevel3       = 75;                                                       // Minimal volume. Level 3 / Ěčíčěŕëüíűé îáúĺě. Óđîâĺíü 3
input color    i_colorLevel3           = clrRoyalBlue;                                             // Color of level 3 / Öâĺň óđîâí˙ 3
input int      i_minVolumeLevel4       = 100;                                                      // Minimal volume. Level 4 / Ěčíčěŕëüíűé îáúĺě. Óđîâĺíü 4
input color    i_colorLevel4           = clrBlue;                                                  // Color of level 4 / Öâĺň óđîâí˙ 4
input int      i_minVolumeLevel5       = 150;                                                      // Minimal volume. Level 5 / Ěčíčěŕëüíűé îáúĺě. Óđîâĺíü 5
input color    i_colorLevel5           = clrMagenta;                                               // Color of level 5 / Öâĺň óđîâí˙ 5
input string   i_string2               = "Delta of volumes / Äĺëüňű îáúĺěîâ";                      // ==============================================
input ENUM_YESNO i_isShowDelta         = YES;                                                      // Show the delta of volumes? / Îňîáđŕćŕňü äĺëüňó îáúĺěîâ?
input color    i_bullDeltaColor        = clrLime;                                                  // Color of line price growth / Öâĺň ëčíčč đîńňŕ öĺíű
input color    i_bearDeltaColor        = clrRed;                                                   // Color of line fall in prices / Öâĺň ëčíčč ďŕäĺíč˙ öĺíű
input string   i_string3               = "Ďŕđŕěĺňđű ăđŕôčęŕ";                                      // ==============================================
input ENUM_LINEWIDTH i_lineWidth       = LINEWIDTH_THREE;                                          // Histogram thickness / Ňîëůčíŕ ëčíčč ăčńňîăđŕěěű
input color    i_viewRangeColor        = clrGoldenrod;                                             // Rectangle color / Öâĺň ďđ˙ěîóăîëüíčęŕ
input ENUM_YESNO i_point5Digits        = YES;                                                      // Use 5-digits in prices? / Čńďîëüçîâŕňü 5-çíŕ÷íîĺ ďđĺäńňŕâëĺíčĺ ęîňčđîâîę?

input int      i_indBarsCount=10000;                                                               // Number of bars to display / Ęîë-âî áŕđîâ îňîáđŕćĺíč˙

// Ďđî÷čĺ ăëîáŕëüíűĺ ďĺđĺěĺííűĺ číäčęŕňîđŕ
bool g_chartForeground,                                                                            // Ďđčçíŕę íŕőîćäĺíč˙ ńâĺ÷ĺé íŕ ďĺđĺäíĺě ďëŕíĺ
     g_activate;                                                                                   // Ďđčçíŕę óńďĺříîé číčöčŕëčçŕöčč číäčęŕňîđŕ

int g_pointMultiply;                                                                               // Ěíîćčňĺëü âĺëč÷číű ďóíęňŕ, čńďîëüçóţůčéń˙ ďđč đŕáîňĺ íŕ 5-çíŕ÷íűő ęîňčđîâęŕő

double g_point,
       g_tickSize;

TickStruct        g_ticks[];                                                                       // Ěŕńńčâ äë˙ őđŕíĺíč˙ ňčęîâ, ďîńňóďčâřčő ďîńëĺ íŕ÷ŕëŕ đŕáîňű číäčęŕňîđŕ                    
LevelVolumeColor  g_volumeLevelsColor[MAX_VOLUMES_SHOW];                                           // Ěŕńńčâ îáúĺěîâ č, ńîîňâĺňńňâóţůčě čě, öâĺňîâ óđîâíĺé
ViewRange         g_viewRange;                                                                     // Ňĺęóůĺĺ ďîëîćĺíčĺ îáëŕńňč îňîáđŕćĺíč˙ ăčńňîăđŕěěű
LevelsData        g_levelsData[];                                                                  // Đŕáî÷čé ěŕńńčâ óđîâíĺé, â ęîňîđűé çŕďčńűâŕĺňń˙ ęîëč÷ĺńňâî ňčęîâ, ďîďŕâřčő íŕ ńîîňâĺňńňâóţůóţ öĺíó

#define PREFIX "CLSTRBXH_"                                                                         // Ďđĺôčęń ăđŕôč÷ĺńęčő îáúĺęňîâ, îňîáđŕćŕĺěűő číäčęŕňîđîě 
#define VIEW_RANGE "VIEWRANGE"                                                                     // Ęîđĺíü čěĺíč ăđŕôč÷ĺńęîăî îáúĺęňŕ "Âđĺěĺííűĺ çîíű", óęŕçűâŕţůĺăî číňĺđâŕë îňîáđŕćĺíč˙..
                                                                                                   // ..ăčńňîăđŕěěű ęëŕńňĺđíűő îáúĺěîâ
#define FONT_NAME "MS Sans Serif"
#define FONT_SIZE 8
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator initialization function                                                                                                                                                          |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int OnInit()
  {
   g_activate=false;                                                                             // Číäčęŕňîđ íĺ číčöčŕëčçčđîâŕí

   if(!IsTuningParametersCorrect()) // Íĺâĺđíî óęŕçŕííűĺ çíŕ÷ĺíč˙ íŕńňđîĺ÷íűő ďŕđŕěĺňđîâ - ďđč÷číŕ íĺóäŕ÷íîé číčöčŕëčçŕöčč
      return INIT_FAILED;

   if(!IsLoadTempTicks()) // Çŕăđóçęŕ äŕííűő î ňčęŕő, ńîőđŕíĺííűő çŕ ďđĺäűäóůčé ďĺđčîä đŕáîňű číäčęŕňîđŕ   
      return INIT_FAILED;

   InitViewRange();                                                                                // Číčöčŕëčçŕöč˙ äŕííűő číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű   
   CreateVolumeColorsArray();                                                                      // Ęîďčđîâŕíčĺ äŕííűő î öâĺňĺ č âĺëč÷číĺ óđîâíĺé â ěŕńńčâ

   g_activate=true;                                                                              // Číäčęŕňîđ óńďĺříî číčöčŕëčçčđîâŕí

   return INIT_SUCCEEDED;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďđîâĺđęŕ ęîđđĺęňíîńňč íŕńňđîĺ÷íűő ďŕđŕěĺňđîâ                                                                                                                                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsTuningParametersCorrect()
  {
   string name=ChartGetString(0,CHART_EXPERT_NAME);

   int period= Period();
   if(period == 0)
     {
      Alert(name,": ôŕňŕëüíŕ˙ îřčáęŕ ňĺđěčíŕëŕ - ďĺđčîä 0 ěčíóň. Číäčęŕňîđ îňęëţ÷ĺí.");
      return (false);
     }

   g_point=_Point;
   if(g_point==0)
     {
      Alert(name,": ôŕňŕëüíŕ˙ îřčáęŕ ňĺđěčíŕëŕ - âĺëč÷číŕ ďóíęňŕ đŕâíŕ íóëţ. Číäčęŕňîđ îňęëţ÷ĺí.");
      return (false);
     }

   g_tickSize=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE);
   if(g_tickSize==0)
     {
      Alert(name,": ôŕňŕëüíŕ˙ îřčáęŕ ňĺđěčíŕëŕ - âĺëč÷číŕ řŕăŕ îäíîăî ňčęŕ đŕâíŕ íóëţ. Číäčęŕňîđ îňęëţ÷ĺí.");
      return (false);
     }

   g_pointMultiply=1;
   if(i_point5Digits==YES)
      g_pointMultiply=10;

   if(i_pointsInBox<3*g_pointMultiply)
     {
      Alert(name,": ęîëč÷ĺńňâî ďóíęňîâ â ęëŕńňĺđĺ äîëćíî áűňü íĺ ěĺíĺĺ ",3*g_pointMultiply,". Číäčęŕňîđ îňęëţ÷ĺí.");
      return (false);
     }

   if(VIEWRANGE_STARTBAR>=Bars(_Symbol,_Period))
     {
      Alert(name,": ňĺęóůĺĺ ęîëč÷ĺńňâî áŕđîâ ăđŕôčęŕ ńëčřęîě ěŕëî. Číäčęŕňîđ îňęëţ÷ĺí.");
      return (false);
     }

   return (true);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| ×ňĺíčĺ äŕííűő î ňčęŕő, íŕęîďëĺííűő â ňĺ÷ĺíčĺ ďđĺäűäóůĺé đŕáî÷ĺé ńĺńńčč ďđîăđŕěěű                                                                                                                  |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsLoadTempTicks()
  {
// Îňęđűňčĺ ôŕéëŕ ňčęîâîé čńňîđčč
   int hTicksFile=FileOpen(Symbol()+"temp.tks",FILE_BIN|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE);
   if(hTicksFile<1)
      return true;

// Đŕńďđĺäĺëĺíčĺ ďŕě˙ňč äë˙ ěŕńńčâŕ g_ticks
   int recSize=(int)(FileSize(hTicksFile)/sizeof(TickStruct));
   if(ArrayResize(g_ticks,recSize,1000)<0)
     {
      Alert(ChartGetString(0,CHART_EXPERT_NAME),": íĺ óäŕëîńü đŕńďđĺäĺëčňü ďŕě˙ňü äë˙ ďîäęŕ÷ęč äŕííűő čç âđĺěĺííîăî ôŕéëŕ ňčęîâ. Číäčęŕňîđ îňęëţ÷ĺí.");
      FileClose(hTicksFile);
      return false;
     }

// ×ňĺíčĺ ôŕéëŕ
   int i=0;
   while(i<recSize)
     {
      if(FileReadStruct(hTicksFile,g_ticks[i])==0)
        {
         Alert(ChartGetString(0,CHART_EXPERT_NAME),": îřčáęŕ ÷ňĺíč˙ äŕííűő čç âđĺěĺííîăî ôŕéëŕ. Číäčęŕňîđ îňęëţ÷ĺí.");
         return false;
        }

      i++;
     }

   FileClose(hTicksFile);
   return true;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Číčöčŕëčçŕöč˙ äŕííűő číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű                                                                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void InitViewRange()
  {
   g_viewRange.rightTime= iTime(_Symbol,_Period,0)+PeriodSeconds();
   g_viewRange.leftTime = iTime(_Symbol,_Period,VIEWRANGE_STARTBAR);
   g_viewRange.rightIndex=-1;
   g_viewRange.rangeDuration=VIEWRANGE_STARTBAR+2;

  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ôîđěčđîâŕíčĺ ěŕńńčâŕ çíŕ÷ĺíčé îáúĺěîâ č ńîîňâĺňńňâóţůčő čě öâĺňŕě óđîâíĺé                                                                                                                         |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void CreateVolumeColorsArray()
  {
   g_volumeLevelsColor[0].levelMinVolume = i_minVolumeLevel1;
   g_volumeLevelsColor[1].levelMinVolume = i_minVolumeLevel2;
   g_volumeLevelsColor[2].levelMinVolume = i_minVolumeLevel3;
   g_volumeLevelsColor[3].levelMinVolume = i_minVolumeLevel4;
   g_volumeLevelsColor[4].levelMinVolume = i_minVolumeLevel5;

   g_volumeLevelsColor[0].levelColor = i_colorLevel1;
   g_volumeLevelsColor[1].levelColor = i_colorLevel2;
   g_volumeLevelsColor[2].levelColor = i_colorLevel3;
   g_volumeLevelsColor[3].levelColor = i_colorLevel4;
   g_volumeLevelsColor[4].levelColor = i_colorLevel5;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator deinitialization function                                                                                                                                                        |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(!IsSavedFile()) // Ĺńëč íč îäčí čç ďîäęëţ÷ĺííűő číäčęŕňîđîâ íĺ ńîőđŕíčë äŕííűĺ, ňî čő ńîőđŕíčň ňĺęóůčé číäčęŕňîđ
      SaveTempTicks();                                                                             // Ńîőđŕíĺíčĺ äŕííűő î ňčęŕő, íŕęîďëĺííűő çŕ ňĺęóůčé ďĺđčîä đŕáîňű číäčęŕňîđŕ   
   DeleteAllObjects();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďđîâĺđęŕ íŕëč÷č˙ çŕďčńŕííűő äŕííűő äđóăčě číäčęŕňîđîě                                                                                                                                             |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsSavedFile()
  {
// Ďîëó÷ĺíčĺ âđĺěĺíč ďîńňóďëĺíč˙ ďîńëĺäíĺăî çŕďčńŕííîăî ňčęŕ
   int lastTickIndex=ArraySize(g_ticks)-1;
   if(lastTickIndex<0) // Íč îäčí ňčę íĺ áűë ďîëó÷ĺí. Çŕďčńü äŕííűő íĺ ňđĺáóĺňń˙
      return true;

// Îňęđűňčĺ ôŕéëŕ ňčęîâîé čńňîđčč
   int hTicksFile=FileOpen(Symbol()+"temp.tks",FILE_BIN|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE);
   if(hTicksFile<1)
      return false;

// Ďĺđĺěĺůĺíčĺ ę ďîńëĺäíĺé çŕďčńč â ôŕéëĺ
   if(!FileSeek(hTicksFile,-sizeof(TickStruct),SEEK_END))
     {
      FileClose(hTicksFile);
      return false;
     }

// ×ňĺíčĺ ďîńëĺäíĺé çŕďčńč č çŕęđűňčĺ ôŕéëŕ
   TickStruct tick;
   uint readBytes=FileReadStruct(hTicksFile,tick);
   FileClose(hTicksFile);
   if(readBytes==0)
      return false;

// Ńđŕâíĺíčĺ äŕňű ňčęŕ, çŕďčńŕííîăî â ôŕéëĺ, č äŕňű ďîńëĺäíĺăî ďîńňóďčâřĺăî ňčęŕ
   return tick.time >= g_ticks[lastTickIndex].time;                                                // Äŕňŕ/âđĺě˙ ďîńëĺäíĺăî çŕďčńŕííîăî â ôŕéëĺ ňčęŕ áîëüřĺ čëč đŕâíŕ äŕňĺ/âđĺěĺíč..
                                                                                                   // ..çŕđĺăčńňđčđîâŕííîăî ňčęŕ. Çíŕ÷čň, ôŕéë óćĺ çŕďčńŕí, č ďîâňîđíŕ˙ çŕďčńü íĺ ňđĺáóĺňń˙
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ńîőđŕíĺíčĺ äŕííűő î ňčęŕő, íŕęîďëĺííűő çŕ ňĺęóůóţ đŕáî÷óţ ńĺńńčţ ďđîăđŕěěű                                                                                                                        |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void SaveTempTicks()
  {
// Ńîçäŕíčĺ ôŕéëŕ ňčęîâîé čńňîđčč
   int hTicksFile=FileOpen(Symbol()+"temp.tks",FILE_BIN|FILE_READ|FILE_WRITE|FILE_SHARE_READ|FILE_SHARE_WRITE);
   if(hTicksFile<1)
      return;

// Çŕďčńü ôŕéëŕ
   int total=ArraySize(g_ticks),i=0;
   while(i<total)
     {
      if(FileWriteStruct(hTicksFile,g_ticks[i])==0)
        {
         Print("Îřčáęŕ ńîőđŕíĺíč˙ äŕííűő âî âđĺěĺííűé ôŕéë...");
         return;
        }

      i++;
     }

   FileClose(hTicksFile);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Óäŕëĺíčĺ âńĺő îáúĺęňîâ, ńîçäŕííűő ďđîăđŕěěîé                                                                                                                                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void DeleteAllObjects()
  {
   for(int i=ObjectsTotal(0,0)-1; i>=0; i--)
      if(StringSubstr(ObjectName(0,i),0,StringLen(PREFIX))==PREFIX)
        ObjectDelete(0,ObjectName(0,i));
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îňîáđŕćĺíčĺ ďđ˙ěîóăîëüíčęŕ                                                                                                                                                                        |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowTrendLine(datetime time1,double price1,datetime time2,double price2,string toolTip,color clr)
  {
   string name=PREFIX+"LINE_"+IntegerToString((int)MathRound(price1/g_point));

   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_TREND,0,time1,price1,time2,price2);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,(int)i_lineWidth);
      ObjectSetInteger(0,name,OBJPROP_RAY,false);
      ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
      ObjectSetString(0,name,OBJPROP_TOOLTIP,toolTip);
      return;
     }

   ObjectMove(0,name,0,time1,price1);
   ObjectMove(0,name,0,time2,price2);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îňîáđŕćĺíčĺ îáúĺęňŕ "Ňĺęńň"                                                                                                                                                                       |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowText(datetime time,double price,string text,color clr)
  {
   string name=PREFIX+"TEXT_"+IntegerToString((int)(price/g_point));
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_TEXT,0,time,price);
      ObjectSetString(0,name,OBJPROP_FONT,FONT_NAME);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,FONT_SIZE);
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT);
      ObjectSetString(0,name,OBJPROP_TEXT,text);
      ObjectSetString(0,name,OBJPROP_TOOLTIP,DoubleToString(price,_Digits));
      ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_BACK,false);
      ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
      return;
     }

   ObjectMove(0,name,0,time,price);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetString(0,name,OBJPROP_TEXT,text);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îňîáđŕćĺíčĺ îáúĺęňŕ "Ďđ˙ěîóăîëüíčę"                                                                                                                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowRectangle(datetime time1,double price1,datetime time2,double price2)
  {
   string name=PREFIX+VIEW_RANGE;
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2);
      ObjectSetInteger(0,name,OBJPROP_COLOR,i_viewRangeColor);
      ObjectSetInteger(0,name,OBJPROP_BACK,false);
      return;
     }

   ObjectMove(0,name,0,time1,price1);
   ObjectMove(0,name,1,time2,price2);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îďđĺäĺëĺíčĺ číäĺęńŕ áŕđŕ, ń ęîňîđîăî íĺîáőîäčěî ďđîčçâîäčňü ďĺđĺđŕń÷ĺň                                                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int GetRecalcIndex(int &total,const int ratesTotal,const int prevCalculated)
  {
// Îďđĺäĺëĺíčĺ ďĺđâîăî áŕđŕ čńňîđčč, íŕ ęîňîđîě áóäóň äîńňóďíű ŕäĺęâŕňíűĺ çíŕ÷ĺíč˙ číäčęŕňîđŕ
   total=ratesTotal-1;

// Ŕ ěîćĺň çíŕ÷ĺíč˙ číäčęŕňîđŕ íĺ íóćíî îňîáđŕćŕňü íŕ âńĺé čńňîđčč?
   if(i_indBarsCount>0 && i_indBarsCount<total)
      total=MathMin(i_indBarsCount,total);

// Ďĺđâîĺ îňîáđŕćĺíčĺ číäčęŕňîđŕ čëč ďđîčçîřëŕ ďîäęŕ÷ęŕ äŕííűő, ň. ĺ. íŕ ďđĺäűäóůĺě ňčęĺ áŕđîâ áűëî íĺ íŕ îäčí áŕđ ěĺíüřĺ, ęŕę ďđč íîđěŕëüíîě đŕçâčňčč čńňîđčč, ŕ íŕ äâŕ čëč áîëĺĺ áŕđîâ ěĺíüřĺ
   if(prevCalculated<ratesTotal-1)
     {
      DeleteAllObjects();
      return (total);
     }

// Íîđěŕëüíîĺ đŕçâčňčĺ čńňîđčč. Ęîëč÷ĺńňâî áŕđîâ ňĺęóůĺăî ňčęŕ îňëč÷ŕĺňń˙ îň ęîëč÷ĺńňâŕ áŕđîâ ďđĺäűäóůĺăî ňčęŕ íĺ áîëüřĺ, ÷ĺě íŕ îäčí áŕđ
   return (MathMin(ratesTotal - prevCalculated, total));
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Đŕâíű ëč ÷čńëŕ?                                                                                                                                                                                   |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsValuesEquals(double first,double second)
  {
   return (MathAbs(first - second) < _Point / 10);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Çŕďčńü äŕííűő î ňčęĺ â ěŕńńčâ g_ticks                                                                                                                                                             |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsUpdateTicksArray(TickStruct &tick)
  {
   int total=ArraySize(g_ticks);
   if(ArrayResize(g_ticks,total+1,100)<0)
     {
      Alert(ChartGetString(0,CHART_EXPERT_NAME),": číäčęŕňîđó íĺ őâŕňŕĺň ďŕě˙ňč äë˙ ńîőđŕíĺíč˙ äŕííűő îá î÷ĺđĺäíîě ňčęĺ.");
      return false;
     }

   g_ticks[total]=tick;
   return true;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Çŕďčńü äŕííűő î ňčęĺ â ěŕńńčâ g_levelsData                                                                                                                                                        |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsSaveTickData(TickStruct &curTick,TickStruct &prevTick)
  {
// Ďđĺîáđŕçîâŕíčĺ öĺíű ę áëčćŕéřĺěó ęëŕńňĺđó
   double clusterPrice=CastPriceToCluster(curTick.bid);

// Ďîčńę ňŕęîé ćĺ öĺíű â ěŕńńčâĺ g_levelsData
   int i=0;
   int total=ArraySize(g_levelsData);
   for(; i<total; i++)
      if(IsValuesEquals(g_levelsData[i].price,clusterPrice))
         break;

// Ďîőîćŕ˙ öĺíŕ íŕéäĺíŕ
   if(i<total)
     {
      g_levelsData[i].repeatCnt++;
      SaveDeltaData(i,curTick.bid,prevTick.bid);
      return true;
     }

// Óęŕçŕííŕ˙ öĺíŕ ˙âë˙ĺňń˙ íîâîé - đŕńřčđĺíčĺ ěŕńńčâŕ
   if(ArrayResize(g_levelsData,total+1)!=total+1)
     {
      Alert(ChartGetString(0,CHART_EXPERT_NAME),": číäčęŕňîđó íĺ őâŕňŕĺň ďŕě˙ňč äë˙ ęîđđĺęňíîé đŕáîňű.");
      return false;
     }

   g_levelsData[total].price=clusterPrice;
   g_levelsData[total].repeatCnt=1;
   g_levelsData[i].bullsCnt = 0;
   g_levelsData[i].bearsCnt = 0;
   SaveDeltaData(i,curTick.bid,prevTick.bid);
   return true;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďđčâĺäĺíčĺ đűíî÷íîé öĺíű ę öĺíĺ ęëŕńňĺđŕ ń ó÷ĺňîě ĺăî âűńîňű                                                                                                                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
double CastPriceToCluster(double price)
  {
   int priceInPoints=(int)MathRound(price/_Point);
   int clusterPrice =(int)MathRound(priceInPoints/1.0/i_pointsInBox);
   return NormalizeDouble(clusterPrice * _Point * i_pointsInBox, _Digits);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Çŕďčńü äŕííűő î đîńňĺ čëč ďŕäĺíčč öĺíű â ďđĺäĺëŕő ęëŕńňĺđŕ                                                                                                                                        |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void SaveDeltaData(int index,double curBid,double prevBid)
  {
   if(curBid>prevBid)
      g_levelsData[index].bullsCnt++;
   if(curBid<prevBid)
      g_levelsData[index].bearsCnt++;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| ×ňĺíčĺ îäíîăî ňčęŕ čç ôŕéëŕ                                                                                                                                                                       |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsReadTimeAndBidAskOfTick(int hTicksFile,TickStruct &tick)
  {
   if(FileIsEnding(hTicksFile))
      return false;

   uint bytesCnt=FileReadStruct(hTicksFile,tick);
   return bytesCnt == sizeof(TickStruct);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ń÷čňűâŕíčĺ ňčęîâ, ďđčíŕäëĺćŕůčő äĺéńňâóţůĺěó číňĺđâŕëó îňîáđŕćĺíč˙ ăčńňîăđŕěěű                                                                                                                    |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool IsReadTicksFromFile(datetime &lastTime)
  {
// Îáíóëĺíčĺ ňĺęóůĺé čńňîđčč
   ArrayResize(g_levelsData,0);

// Îňęđűňčĺ ôŕéëŕ ňčęîâîé čńňîđčč
   int hTicksFile=FileOpen(Symbol()+".tks",FILE_BIN|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE);
   if(hTicksFile<1)
      return true;

// ×ňĺíčĺ ôŕéëŕ
   TickStruct tick={0,0,0};
   TickStruct prevTick;
   bool result=true;
   while(!IsStopped())
     {
      prevTick=tick;
      bool fileClose=!IsReadTimeAndBidAskOfTick(hTicksFile,tick);
      if(fileClose || tick.time==0)
         break;

      if(tick.time<g_viewRange.leftTime)
         continue;

      if(tick.time>g_viewRange.rightTime+PeriodSeconds())
         break;

      if(!IsSaveTickData(tick,prevTick))
        {
         result=false;
         break;
        }
     }

   FileClose(hTicksFile);
   lastTime = tick.time;                                                                           // Óęŕçűâŕĺě ďîńëĺäíţţ ďđî÷čňŕííóţ äŕňó, ÷ňîáű äîďîëíčňü ďîëó÷ĺííűĺ äŕííűĺ čç ëîęŕëüíîăî áóôĺđŕ..
                                                                                                   // ..ďđč íĺîáőîäčěîńňč
   return result;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| ×ňĺíčĺ äŕííűő î ňčęŕő čç ëîęŕëüíîăî áóôĺđŕ, ÷ňîáű íĺ ďîňĺđ˙ňü ňčęč, ďđčřĺäřčĺ ďîńëĺ íŕ÷ŕëŕ đŕáîňű číäčęŕňîđŕ, íî íĺ ďîďŕâřčĺ â ôŕéë                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
bool ReadTicksFromBuffer(datetime lastTime)
  {
// Äîďîëíĺíčĺ íĺ ňđĺáóĺňń˙ - ďđî÷čňŕíű âńĺ ňčęč
   if(lastTime>g_viewRange.rightTime)
      return true;

// Âîçěîćíî, äŕííűĺ čç ăëŕâíîăî ňčęîâîăî ôŕéëŕ çŕęŕí÷čâŕţňń˙ äî ěîěĺíňŕ íŕ÷ŕëŕ číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű
   lastTime=(int)MathMax(lastTime,g_viewRange.leftTime);

// Ďîčńę číäĺęńŕ äë˙ g_ticks, ń ęîňîđîăî íĺîáőîäčěî ďđîäîëćčňü ÷ňĺíčĺ äŕííűő
   int total=ArraySize(g_ticks);
   int i=0;
   while(i<total && lastTime>=g_ticks[i].time)
      i++;

// Îńóůĺńňâëĺíčĺ äîďîëíĺíč˙
   datetime timeTotal=g_viewRange.rightTime+PeriodSeconds();
   TickStruct prevTick={0,0,0};
   if(i>0)
      prevTick=g_ticks[i-1];
   while(i<total && g_ticks[i].time<timeTotal)
     {
      if(!IsSaveTickData(g_ticks[i],prevTick))
         return false;

      prevTick=g_ticks[i];
      i++;
     }

   return true;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îďđĺäĺëĺíčĺ ěŕęńčěŕëüíîăî çíŕ÷ĺíč˙ ňčęîâîăî îáúĺěŕ â ńđĺäč íŕéäĺííűő ęëŕńňĺđîâ                                                                                                                    |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int GetMaxTickVolume()
  {
   int max=0;
   int total = ArraySize(g_levelsData);
   for(int i = 0; i < total; i++)
      if(g_levelsData[i].repeatCnt>max)
         max=g_levelsData[i].repeatCnt;

   return max;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îňîáđŕćĺíčĺ ăčńňîăđŕěěű                                                                                                                                                                           |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowHistogramm()
  {
   DeleteHistogramm();
   int maxVolume= GetMaxTickVolume();
   if(maxVolume == 0)
      return;

   int total = ArraySize(g_levelsData);
   for(int i = 0; i < total; i++)
     {
      int volumeLevel=GetVolumeLevel(g_levelsData[i].repeatCnt);
      if(volumeLevel<0)
         continue;

      // Îňîáđŕćĺíčĺ ăčńňîăđŕěěű îáúĺěŕ
      string price="Ęëŕńňĺđ: "+DoubleToString(g_levelsData[i].price,_Digits);
      datetime histRightTime=GetHistRightTime(g_levelsData[i].repeatCnt,maxVolume);
      ShowTrendLine(g_viewRange.leftTime,g_levelsData[i].price,histRightTime,g_levelsData[i].price,price+". Ëčíč˙ îáúĺěŕ",g_volumeLevelsColor[volumeLevel].levelColor);
      ShowText(g_viewRange.rightTime,g_levelsData[i].price," "+IntegerToString(g_levelsData[i].repeatCnt),g_volumeLevelsColor[volumeLevel].levelColor);

      // Îňîáđŕćĺíčĺ ăčńňîăđŕěě đîńňŕ č ďŕäĺíč˙ öĺíű
      if(i_isShowDelta==NO)
         continue;
      histRightTime=GetHistRightTime(g_levelsData[i].bearsCnt,maxVolume);
      ShowTrendLine(g_viewRange.leftTime,g_levelsData[i].price+g_pointMultiply*_Point,histRightTime,g_levelsData[i].price+g_pointMultiply*_Point,
                    price+". Îáúĺě ďŕäĺíč˙: "+IntegerToString(g_levelsData[i].bearsCnt),i_bearDeltaColor);
      histRightTime=GetHistRightTime(g_levelsData[i].bullsCnt,maxVolume);
      ShowTrendLine(g_viewRange.leftTime,g_levelsData[i].price+2*g_pointMultiply*_Point,histRightTime,g_levelsData[i].price+2*g_pointMultiply*_Point,
                    price+". Îáúĺě đîńňŕ: "+IntegerToString(g_levelsData[i].bullsCnt),i_bullDeltaColor);
     }
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Óäŕëĺíčĺ âńĺő îáúĺęňîâ, ńîńňŕâë˙ţůčő ăčńňîăđŕěěó                                                                                                                                                  |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void DeleteHistogramm()
  {
   for(int i=ObjectsTotal(0,0)-1; i>=0; i--)
     {
      string name=ObjectName(0,i);
      if(StringSubstr(name,0,StringLen(PREFIX+"LINE_"))==PREFIX+"LINE_" ||
         StringSubstr(name,0,StringLen(PREFIX+"TEXT_"))==PREFIX+"TEXT_")
         ObjectDelete(0,name);
     }
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îďđĺäĺëĺíčĺ, ęŕęîěó čç óęŕçŕííűő îáúĺěîâ ńîîňâĺňńňâóĺň đŕńńěŕňđčâŕĺěŕ˙ âĺëč÷číŕ îáúĺěŕ                                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
int GetVolumeLevel(int ticksVolume)
  {
   for(int i=0; i<MAX_VOLUMES_SHOW; i++)
      if(g_volumeLevelsColor[i].levelMinVolume>ticksVolume)
         return i - 1;

   return MAX_VOLUMES_SHOW - 1;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Âű÷čńëĺíčĺ âđĺěĺíč áŕđŕ, íŕ ęîňîđîě äîëćíŕ çŕęŕí÷čâŕňüń˙ ëčíč˙ ăčńňîăđŕěěű ń óęŕçŕííűě ňčęîâűě îáúĺěîě                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
datetime GetHistRightTime(int tickVolume,int maxVolume)
  {
   int barsIndex=(int)(g_viewRange.rightIndex+(g_viewRange.rangeDuration-1) *(1-tickVolume/1.0/maxVolume));
   if(barsIndex<0 || barsIndex>=Bars(_Symbol,_Period))
      return g_viewRange.rightTime;

   return iTime(_Symbol,_Period,barsIndex);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďîääĺđćęŕ číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű îáúĺěîâ                                                                                                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowViewRange(int limit)
  {
// Ĺńëč ďđîčçîřĺë ďĺđĺőîä ę íîâîěó áŕđó, íî číňĺđâŕë ďîçčöčîíčđóĺňń˙ íŕ áŕđŕő 0 č âűřĺ
   if(limit>0 && g_viewRange.rightIndex>=0)
     {
      if(g_viewRange.rightTime != iTime(_Symbol,_Period,g_viewRange.rightIndex))
         g_viewRange.rightIndex = iBarShift(NULL, 0, g_viewRange.rightTime);
     }
   else
// Âîçěîćíî, ďđîčçîřĺë ďĺđĺőîä ę ńëĺäóţůĺěó áŕđó ďđč ďîçčöčîíčđîâŕíčč číňĺđâŕëŕ íŕ íóëĺâîě áŕđĺ
   if(g_viewRange.rightIndex==-1 && g_viewRange.rightTime!=iTime(_Symbol,_Period,0)+PeriodSeconds())
                                                           MoveRangeToNullBar();

   DefineCoordsAndShowViewRange();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďĺđĺěĺůĺíčĺ číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű íŕ íîâűé "íóëĺâîé" áŕđ                                                                                                                              |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void MoveRangeToNullBar()
  {
   g_viewRange.rightTime=iTime(_Symbol,_Period,0)+PeriodSeconds();
   int leftIndex=iBarShift(NULL,0,g_viewRange.leftTime);
   g_viewRange.rangeDuration=leftIndex+2;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îďđĺäĺëĺíčĺ ęîîđäčíŕň îňîáđŕćĺíč˙ číňĺđâŕëŕ ăčńňîăđŕěěű                                                                                                                                           |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void DefineCoordsAndShowViewRange()
  {
// Îďđĺäĺëĺíčĺ ęîîđäčíŕň číňĺđâŕëŕ
   double rightPrice=0,leftPrice=0;
   g_viewRange.rightIndex=(int)MathMin(MathMax(g_viewRange.rightIndex,-1),Bars(_Symbol,_Period)-1);
   g_viewRange.rangeDuration = (int)MathMax(MathMin(g_viewRange.rangeDuration, Bars(_Symbol,_Period) - g_viewRange.rightIndex - 2), 1);
   if(g_viewRange.rightIndex == -1)
     {
      g_viewRange.rangeDuration=(int)MathMax(g_viewRange.rangeDuration,2);
      rightPrice= CastPriceToCluster(iHigh(_Symbol,_Period,iHighest(NULL,0,MODE_HIGH,g_viewRange.rangeDuration-1)))+2 * g_pointMultiply * _Point;
      leftPrice = CastPriceToCluster(iLow(_Symbol,_Period,iLowest(NULL,0,MODE_LOW,g_viewRange.rangeDuration-1)));
     }
   else
     {
      rightPrice= CastPriceToCluster(iHigh(_Symbol,_Period,iHighest(NULL,0,MODE_HIGH,g_viewRange.rangeDuration,g_viewRange.rightIndex)))+2 * g_pointMultiply * _Point;
      leftPrice = CastPriceToCluster(iLow(_Symbol,_Period,iLowest(NULL,0,MODE_LOW,g_viewRange.rangeDuration,g_viewRange.rightIndex)));
     }

// Îňîáđŕćĺíčĺ číňĺđâŕëŕ
   ShowRectangle(g_viewRange.rightTime,rightPrice,g_viewRange.leftTime,leftPrice);
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îńóůĺńňâëĺíčĺ ÷ňĺíč˙ äŕííűő čç ôŕéëŕ č ďîëíîĺ îňîáđŕćĺíčĺ ăčńňîăđŕěěű                                                                                                                             |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowNewData()
  {
// ×ňĺíčĺ äŕííűő čç ôŕéëŕ
   datetime lastTime=0;
   if(!IsReadTicksFromFile(lastTime))
     {
      g_activate=false;
      return;
     }

// Äîďîëíĺíčĺ äŕííűő čç ëîęŕëüíîăî áóôĺđŕ
   if(!ReadTicksFromBuffer(lastTime))
     {
      g_activate=false;
      return;
     }

   ShowHistogramm();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îáíîâëĺíčĺ äŕííűő ďî ęëŕńňĺđŕě                                                                                                                                                                    |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void UpdateData()
  {
   TickStruct tick;
   tick.time= TimeCurrent();
   tick.ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   tick.bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);

// Äîáŕâëĺíčĺ îäíîăî ňčęŕ â ěŕńńčâ őđŕíĺíč˙ ňčęîâ   
   if(!IsUpdateTicksArray(tick))
     {
      g_activate=false;
      return;
     }

// Äŕííűĺ â ěŕńńčâ ęëŕńňĺđîâ íĺ äîáŕâë˙ţňń˙, ĺńëč ďđŕâŕ˙ ăđŕíčöŕ ďđ˙ěîóăîëüíčęŕ íŕőîäčňń˙ íŕ ďĺđâîě áŕđĺ čëč äŕëĺĺ
   if(g_viewRange.rightIndex>0)
      return;

// Äîáŕâëĺíčĺ ňčęŕ â ěŕńńčâ ęëŕńňĺđîâ
   TickStruct prevTick={0,0,0};
   int lastTickIndex=ArraySize(g_ticks)-1;
   if(lastTickIndex>0)
      prevTick=g_ticks[lastTickIndex-1];
   if(!IsSaveTickData(tick,prevTick))
     {
      g_activate=false;
      return;
     }

   DefineCoordsAndShowViewRange();
   ShowHistogramm();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îňîáđŕćĺíčĺ äŕííűő číäčęŕňîđŕ                                                                                                                                                                     |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowIndicatorData(int limit,int total)
  {
   if(limit>0)
     {
      ShowNewData();
      return;
     }

   UpdateData();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ďđîâĺđęŕ ďđŕâčëüíîńňč äŕííűő ďî ęîîđäčíŕňŕě îáúĺęňŕ č óńňŕíîâęŕ íîâűő ăđŕíčö číňĺđâŕëŕ                                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ValidateDataAndSetRange()
  {
// Ďîëó÷ĺíčĺ ęîîđäčíŕň îáúĺęňŕ
   datetime rightTime=(datetime)ObjectGetInteger(0,PREFIX+VIEW_RANGE,OBJPROP_TIME,0);
   datetime leftTime =(datetime)ObjectGetInteger(0,PREFIX+VIEW_RANGE,OBJPROP_TIME,1);
   if(rightTime<leftTime)
     {
      leftTime=rightTime;
      rightTime=(datetime)ObjectGetInteger(0,PREFIX+VIEW_RANGE,OBJPROP_TIME,1);
     }

// Ďđîâĺđęŕ ďđŕâčëüíîńňč óńňŕíîâęč îáúĺęňŕ
   if(rightTime>iTime(_Symbol,_Period,0)+PeriodSeconds())
     {
      rightTime=iTime(_Symbol,_Period,0)+PeriodSeconds();

      if(leftTime>iTime(_Symbol,_Period,0))
         leftTime=iTime(_Symbol,_Period,VIEWRANGE_STARTBAR);
     }

// Óńňŕíîâęŕ íîâűő ęîîđäčíŕň
   g_viewRange.rightTime= rightTime;
   g_viewRange.leftTime = leftTime;
   if(g_viewRange.rightTime <= iTime(_Symbol,_Period,0))
      g_viewRange.rightIndex = iBarShift(NULL, 0, rightTime);
   else
      g_viewRange.rightIndex=-1;
   int leftIndex=iBarShift(NULL,0,leftTime);
   g_viewRange.rangeDuration=leftIndex-g_viewRange.rightIndex+1;

// Îňîáđŕćĺíčĺ číňĺđâŕëŕ
   DefineCoordsAndShowViewRange();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Îáđŕáîňęŕ ńîáűňč˙ ďĺđĺěĺůĺíč˙ îáúĺęňŕ                                                                                                                                                             |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   if(id!=CHARTEVENT_OBJECT_DRAG)
      return;

   if(sparam!=PREFIX+VIEW_RANGE)
      return;

// Ďĺđĺěĺůĺí îáúĺęň, óęŕçűâŕţůčé ăđŕíčöű číňĺđâŕëŕ îňîáđŕćĺíč˙ ăčńňîăđŕěěű
   ValidateDataAndSetRange();
   ShowNewData();

   ChartRedraw();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Custom indicator iteration function                                                                                                                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
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[])
  {
   if(!g_activate) // Ĺńëč číäčęŕňîđ íĺ ďđîřĺë číčöčŕëčçŕöčţ, ňî đŕáîňŕňü îí íĺ äîëćĺí
      return rates_total;

   int total;
   int limit=GetRecalcIndex(total,rates_total,prev_calculated);                                // Ń ęŕęîăî áŕđŕ íŕ÷číŕňü îáíîâëĺíčĺ?

   ShowViewRange(limit);                                                                           // Íŕ÷ŕëüíîĺ îňîáđŕćĺíčĺ č ďîääĺđćęŕ ďđŕâčëüíîăî îňîáđŕćĺíč˙ îáëŕńňč ďîęŕçŕ ăčńňîăđŕěěű
   ShowIndicatorData(limit, total);                                                                // Îňîáđŕćĺíčĺ äŕííűő číäčęŕňîđŕ
   ChartRedraw();

   return rates_total;
  }
//+------------------------------------------------------------------+
