Miscellaneous
2
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
Markdown Formatting Guide
# H1
## H2
### H3
**bold text**
*italicized text*
[title](https://www.example.com)

`code`
```
code block
```
> blockquote
- Item 1
- Item 2
1. First item
2. Second item
---