clusterbox_histogramm_ad

Author: Scriptong
clusterbox_histogramm_ad

This script is a specialized visual tool for MetaTrader 4 designed to help traders visualize high-frequency price activity by creating "Cluster Histograms." Unlike standard volume indicators that show total volume over a candle, this tool breaks down price action into specific zones to reveal where the most significant trading activity occurred.

Core Functionality

The primary purpose of this script is to group individual price ticks into "clusters." It identifies specific price levels where trading activity is concentrated and represents this data as a histogram on your chart. By doing this, it allows you to see not just that volume happened, but exactly at what price it occurred.

Key Features and Logic:

1. Dynamic View Range (The Selection Box) One of the most unique aspects of this tool is the interactive rectangle on the chart. This box defines the specific time area you want to analyze. You can move or resize this area, and the script will automatically recalculate the cluster data only for the price action contained within those boundaries.

2. Cluster Grouping and Scaling The script takes every individual "tick" (the smallest move in price) and assigns it to a price cluster based on a user-defined point range. For example, if you set the cluster size to 50 points, all ticks occurring within that 50-point window are grouped together as part of the same horizontal bar in the histogram.

3. Multi-Level Visual Feedback To make the data easy to read at a glance, the tool features a tiered coloring system:

  • Volume Thresholds: You can set different minimum volume levels (e.g., Level 1, Level 2, etc.).
  • Color Coding: Each level is assigned a specific color. As a price cluster becomes more active (reaching higher tick counts), it changes color, allowing you to instantly identify the "hot zones" of highest liquidity or heavy trading.

4. Delta Tracking (Bull vs. Bear Activity) Beyond just showing total volume, the script can be configured to show the "Delta." This tracks the direction of the price movement within each cluster:

  • It counts how many ticks moved upward (Bulls) versus how many moved downward (Bears).
  • These are displayed as separate lines/histograms above and below the main cluster price, providing a clearer picture of whether aggressive buying or selling was driving the volume in that specific zone.

5. Data Persistence and Memory Management Because tick data is very dense and can be heavy for a computer to process all at once, the script includes an intelligent data handling system:

  • Temporary Storage: It saves and loads tick data from temporary files, ensuring that information isn't lost when the indicator is restarted.
  • Buffer Management: It manages memory efficiently by only processing ticks relevant to your active view range, keeping the platform running smoothly even during high volatility.

Summary of User Experience

From a user's perspective, this tool transforms raw, messy tick data into an organized visual map. By looking at the resulting histogram, you can see "walls" or "pools" of activity. You can identify where large orders are likely sitting based on historical cluster density and see whether those clusters were formed by aggressive buyers (bullish delta) or sellers (bearish delta).

Miscellaneous
It issuies visual alerts to the screenUses files from the file system
11 Views
0 Downloads
0 Favorites
clusterbox_histogramm_ad
//+------------------------------------------------------------------+
//|                                     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

#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=WindowExpertName();

   int period= Period();
   if(period == 0)
     {
      Alert(name,": ôàòàëüíàÿ îøèáêà òåðìèíàëà - ïåðèîä 0 ìèíóò. Èíäèêàòîð îòêëþ÷åí.");
      return (false);
     }

   g_point=Point;
   if(g_point==0)
     {
      Alert(name,": ôàòàëüíàÿ îøèáêà òåðìèíàëà - âåëè÷èíà ïóíêòà ðàâíà íóëþ. Èíäèêàòîð îòêëþ÷åí.");
      return (false);
     }

   g_tickSize=MarketInfo(Symbol(),MODE_TICKSIZE);
   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)
     {
      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(WindowExpertName(),": íå óäàëîñü ðàñïðåäåëèòü ïàìÿòü äëÿ ïîäêà÷êè äàííûõ èç âðåìåííîãî ôàéëà òèêîâ. Èíäèêàòîð îòêëþ÷åí.");
      FileClose(hTicksFile);
      return false;
     }

// ×òåíèå ôàéëà
   int i=0;
   while(i<recSize)
     {
      if(FileReadStruct(hTicksFile,g_ticks[i])==0)
        {
         Alert(WindowExpertName(),": îøèáêà ÷òåíèÿ äàííûõ èç âðåìåííîãî ôàéëà. Èíäèêàòîð îòêëþ÷åí.");
         return false;
        }

      i++;
     }

   FileClose(hTicksFile);
   return true;
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Èíèöèàëèçàöèÿ äàííûõ èíòåðâàëà îòîáðàæåíèÿ ãèñòîãðàììû                                                                                                                                            |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void InitViewRange()
  {
   g_viewRange.rightTime= Time[0]+PeriodSeconds();
   g_viewRange.leftTime = Time[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()-1; i>=0; i--)
      if(StringSubstr(ObjectName(i),0,StringLen(PREFIX))==PREFIX)
         ObjectDelete(ObjectName(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(WindowExpertName(),": èíäèêàòîðó íå õâàòàåò ïàìÿòè äëÿ ñîõðàíåíèÿ äàííûõ îá î÷åðåäíîì òèêå.");
      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(WindowExpertName(),": èíäèêàòîðó íå õâàòàåò ïàìÿòè äëÿ êîððåêòíîé ðàáîòû.");
      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()-1; i>=0; i--)
     {
      string name=ObjectName(i);
      if(StringSubstr(name,0,StringLen(PREFIX+"LINE_"))==PREFIX+"LINE_" ||
         StringSubstr(name,0,StringLen(PREFIX+"TEXT_"))==PREFIX+"TEXT_")
         ObjectDelete(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)
      return g_viewRange.rightTime;

   return Time[barsIndex];
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ïîääåðæêà èíòåðâàëà îòîáðàæåíèÿ ãèñòîãðàììû îáúåìîâ                                                                                                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void ShowViewRange(int limit)
  {
// Åñëè ïðîèçîøåë ïåðåõîä ê íîâîìó áàðó, íî èíòåðâàë ïîçèöèîíèðóåòñÿ íà áàðàõ 0 è âûøå
   if(limit>0 && g_viewRange.rightIndex>=0)
     {
      if(g_viewRange.rightTime != Time[g_viewRange.rightIndex])
         g_viewRange.rightIndex = iBarShift(NULL, 0, g_viewRange.rightTime);
     }
   else
// Âîçìîæíî, ïðîèçîøåë ïåðåõîä ê ñëåäóþùåìó áàðó ïðè ïîçèöèîíèðîâàíèè èíòåðâàëà íà íóëåâîì áàðå
   if(g_viewRange.rightIndex==-1 && g_viewRange.rightTime!=Time[0]+PeriodSeconds())
                                                           MoveRangeToNullBar();

   DefineCoordsAndShowViewRange();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| Ïåðåìåùåíèå èíòåðâàëà îòîáðàæåíèÿ ãèñòîãðàììû íà íîâûé "íóëåâîé" áàð                                                                                                                              |
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void MoveRangeToNullBar()
  {
   g_viewRange.rightTime=Time[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-1);
   g_viewRange.rangeDuration = (int)MathMax(MathMin(g_viewRange.rangeDuration, Bars - g_viewRange.rightIndex - 2), 1);
   if(g_viewRange.rightIndex == -1)
     {
      g_viewRange.rangeDuration=(int)MathMax(g_viewRange.rangeDuration,2);
      rightPrice= CastPriceToCluster(High[iHighest(NULL,0,MODE_HIGH,g_viewRange.rangeDuration-1)])+2 * g_pointMultiply * Point;
      leftPrice = CastPriceToCluster(Low[iLowest(NULL,0,MODE_LOW,g_viewRange.rangeDuration-1)]);
     }
   else
     {
      rightPrice= CastPriceToCluster(High[iHighest(NULL,0,MODE_HIGH,g_viewRange.rangeDuration,g_viewRange.rightIndex)])+2 * g_pointMultiply * Point;
      leftPrice = CastPriceToCluster(Low[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 = Ask;
   tick.bid = 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_TIME1);
   datetime leftTime =(datetime)ObjectGetInteger(0,PREFIX+VIEW_RANGE,OBJPROP_TIME2);
   if(rightTime<leftTime)
     {
      leftTime=rightTime;
      rightTime=(datetime)ObjectGetInteger(0,PREFIX+VIEW_RANGE,OBJPROP_TIME2);
     }

// Ïðîâåðêà ïðàâèëüíîñòè óñòàíîâêè îáúåêòà
   if(rightTime>Time[0]+PeriodSeconds())
     {
      rightTime=Time[0]+PeriodSeconds();

      if(leftTime>Time[0])
         leftTime=Time[VIEWRANGE_STARTBAR];
     }

// Óñòàíîâêà íîâûõ êîîðäèíàò
   g_viewRange.rightTime= rightTime;
   g_viewRange.leftTime = leftTime;
   if(g_viewRange.rightTime <= Time[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();

   WindowRedraw();
  }
//+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//| 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);                                                                // Îòîáðàæåíèå äàííûõ èíäèêàòîðà
   WindowRedraw();

   return rates_total;
  }
//+------------------------------------------------------------------+

Comments