#property copyright "VP: Volume Profile v4.0. Copyright © 2009-2016 FXcoder" #property link "http://fxcoder.net" #property strict #property indicator_chart_window #property indicator_plots 0 #define PUT_IN_RANGE(A, L, H) ((H) < (L) ? (A) : ((A) < (L) ? (L) : ((A) > (H) ? (H) : (A)))) #define COLOR_IS_NONE(C) (((C) >> 24) != 0) #define RGB_TO_COLOR(R, G, B) ((color)((((B) & 0x0000FF) << 16) + (((G) & 0x0000FF) << 8) + ((R) & 0x0000FF))) #define ROUND_PRICE(A, P) ((int)((A) / P + 0.5)) #define NORM_PRICE(A, P) (((int)((A) / P + 0.5)) * P) enum ENUM_APPLIED_VOLUME { VOLUME_TICK, // Tick volume VOLUME_REAL // Real volume }; enum ENUM_POINT_SCALE { POINT_SCALE_1 = 1, // *1 POINT_SCALE_5 = 5, // *5 POINT_SCALE_10 = 10, // *10 POINT_SCALE_15 = 15, // *15 POINT_SCALE_25 = 20, // *20 POINT_SCALE_50 = 50, // *50 POINT_SCALE_100 = 100, // *100 }; enum ENUM_VP_BAR_STYLE { VP_BAR_STYLE_LINE, // Line VP_BAR_STYLE_BAR, // Empty bar VP_BAR_STYLE_BAR_FILLED, // Filled bar VP_BAR_STYLE_OUTLINE, // Outline VP_BAR_STYLE_COLOR // Color }; enum ENUM_HG_DIRECTION { HG_DIRECTION_LEFT = 0, // Right to left HG_DIRECTION_RIGHT = 1, // Left to right }; /* Calculation */ input ENUM_TIMEFRAMES RangePeriod = PERIOD_D1; // Range period input int RangeCount = 20; // Range count input int ModeStep = 100; // Mode step (points) input ENUM_APPLIED_VOLUME VolumeType = VOLUME_TICK; // Volume type ENUM_TIMEFRAMES DataPeriod = PERIOD_M1; // Data period int PriceStep = 0; // Price step /* Histogram */ input ENUM_HG_DIRECTION DrawDirection = HG_DIRECTION_RIGHT; // Draw direction input color HgColor = SteelBlue/*C'128,160,192'*/; // Color 1 input color HgColor2 = SteelBlue/*C'128,160,192'*/; // Color 2 input ENUM_VP_BAR_STYLE HgBarStyle = VP_BAR_STYLE_BAR; // Bar style input int HgLineWidth = 1; // Line width /* Levels */ input color ModeColor = DodgerBlue; // Mode color input color MaxColor = Red; // Maximum color input color MedianColor = clrLimeGreen; // Median color input color VwapColor = clrNONE; // VWAP color input int ModeLineWidth = 1; // Mode line width input ENUM_LINE_STYLE StatLineStyle = STYLE_DOT; // Median & VWAP line style /* Service */ input ENUM_POINT_SCALE HgPointScale = POINT_SCALE_10; // Point scale input string Id = "+vp"; // Identifier bool ShowHorizon = false; // Show data horizon double Zoom = 0; // Zoom (0=auto) int WaitMilliseconds = 250; // Wait milliseconds, select value < 1000 (1s) void OnInit() { _prefix = Id + " " + IntegerToString(RangePeriod) + " "; _rangeCount = RangeCount > 0 ? RangeCount : 1; _hgPoint = _Point * HgPointScale; _modeStep = ModeStep / HgPointScale; ArrayFree(_drawHistory); // íàñòðîéêè îòîáðàæåíèÿ _hgBarStyle = HgBarStyle; _hgPointDigits = GetPointDigits(_hgPoint); _defaultHgColor1 = HgColor; _defaultHgColor2 = HgColor2; _hgLineWidth = HgLineWidth; _modeColor = ModeColor; _maxColor = MaxColor; _medianColor = MedianColor; _vwapColor = VwapColor; _modeLineWidth = ModeLineWidth; _statLineStyle = StatLineStyle; _showHg = !(ColorIsNone(_hgColor1) && ColorIsNone(_hgColor2)); _showModes = !ColorIsNone(_modeColor); _showMax = !ColorIsNone(_maxColor); _showMedian = !ColorIsNone(_medianColor); _showVwap = !ColorIsNone(_vwapColor); _zoom = MathAbs(Zoom); _updateTimer = new MillisecondTimer(WaitMilliseconds, false); } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_CHART_CHANGE) { // åñëè öâåò ôîíà èçìåíèëñÿ, ïåðåðèñîâàòü âñå ãèñòîãðàììû if (UpdateAutoColors()) { ArrayFree(_drawHistory); CheckTimer(); } } } int OnCalculate(const int ratesTotal, const int prevCalculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tickVolume[], const long &volume[], const int &spread[]) { // åñëè öâåò ôîíà èçìåíèëñÿ, ïåðåðèñîâàòü âñå ãèñòîãðàììû if (UpdateAutoColors()) ArrayFree(_drawHistory); CheckTimer(); return(0); } void OnTimer() { CheckTimer(); } void OnDeinit(const int reason) { ObjectsDeleteAll(0, _prefix); delete(_updateTimer); } void CheckTimer() { // Âûêëþ÷èòü ðåçåðâíûé òàéìåð EventKillTimer(); // Åñëè òàéìåð ñðàáîòàë, íàðèñîâàòü êàðòèíêó. Ëèáî ñðàçó, åñëè â ïðîøëûé ðàç áûëà ïðîáëåìà. if (_updateTimer.Check() || !_lastOK) { // Îáíîâèòü.  ñëó÷àå íåóäà÷è ïîñòàâèòü òàéìåð íà 3 ñåêóíäû, ÷òîáû ïîïðîáîâàòü ñíîâà åù¸ ðàç. // 3 ñåêóíäû äîëæíî áûòü äîñòàòî÷íî äëÿ ïîäãðóçêè ïîñëåäíåé èñòîðèè. Èíà÷å âñ¸ ïðîñòî ïîâòîðèòñÿ åù¸ ÷åðåç 3. _lastOK = Update(); if (!_lastOK) EventSetTimer(3); ChartRedraw(); // ðàñ÷¸ò è ðèñîâàíèå ìîãóò áûòü äëèòåëüíûìè, ëó÷øå ïåðåçàïóñòèòü òàéìåð _updateTimer.Reset(); } else { // Íà ñëó÷àé, åñëè ñâîé òàéìåð áîëüøå íå áóäåò ïðîâåðÿòüñÿ, äîáàâèòü ïðèíóäèòåëüíóþ ïðîâåðêó ÷åðåç ñåêóíäó (ìåíüøå MQL íå óìååò) EventSetTimer(1); } } bool Update() { // Ñîñòàâèòü ñïèñîê äèàïàçîíîâ datetime ranges[]; ArraySetAsSeries(ranges, true); ArrayResize(ranges, _rangeCount); if (CopyTime(_Symbol, RangePeriod, 0, _rangeCount, ranges) != _rangeCount) return(false); /* Ïðîâåðèòü íàëè÷èå íåîáõîäèìûõ êîòèðîâîê. */ datetime dataRates[]; datetime rangesStart = ranges[_rangeCount - 1]; datetime rangesEnd = ranges[0] + PeriodSeconds(RangePeriod) - 1; int dataCount = CopyTime(_Symbol, DataPeriod, rangesStart, rangesEnd, dataRates); if (dataCount <= 0) return(false); if (ShowHorizon) DrawHorizon(_prefix + "hz", iTime(_Symbol, DataPeriod, Bars(_Symbol, DataPeriod) - 1)); int modes[]; double volumes[]; double lowPrice; bool totalResult = true; for (int i = 0; i < _rangeCount; i++) { /* Ðàñ÷¸ò */ // Ãðàíèöû äèàïàçîíà datetime rangeStart = ranges[i]; // Åñëè ãèñòîãðàììà óæå áûëà óñïåøíî íàðèñîâàíà, ïðîïóñòèòü. Êðîìå êðàéíåé ïðàâîé. if ((i != 0) && (ArrayIndexOf(_drawHistory, rangeStart) != -1)) { continue; } datetime rangeEnd = rangeStart + PeriodSeconds(RangePeriod) - 1; int barFrom, barTo; if (!GetRangeBars(rangeStart, rangeEnd, barFrom, barTo)) { totalResult = false; // â ñëó÷àå îøèáêè ðèñîâàíèÿ îäíîé ãèñòîãðàììû, ïðîäîëæèòü ðèñîâàòü äðóãèå continue; } int count = GetHgByRates(rangeStart, rangeEnd, _hgPoint, DataPeriod, VolumeType, lowPrice, volumes); if (count <= 0) { totalResult = false; // â ñëó÷àå îøèáêè ðèñîâàíèÿ îäíîé ãèñòîãðàììû, ïðîäîëæèòü ðèñîâàòü äðóãèå continue; } // äîáàâèòü ãèñòîãðàììó â ñïèñîê âûïîëíåííûõ if (i != 0) ArrayAdd(_drawHistory, rangeStart, true); /* Îòîáðàæåíèå */ // Óðîâíè int modeCount = _showModes ? HgModes_old(volumes, _modeStep, modes) : -1; int maxPos = _showMax ? ArrayMax(volumes) : -1; int medianPos = _showMedian ? ArrayMedian(volumes) : -1; int vwapPos = _showVwap ? HgVwap(volumes, lowPrice, _hgPoint) : -1; // ïðåôèêñ äëÿ êàæäîé ãèñòîãðàììû ñâîé string prefix = _prefix + (string)((int)rangeStart / PeriodSeconds(RangePeriod)) + " "; // îïðåäåëèòü ìàñøòàá è íàïðàâëåíèå double zoom = _zoom > 0 ? _zoom : (barFrom - barTo) / volumes[ArrayMax(volumes)]; if (DrawDirection == HG_DIRECTION_LEFT) Swap(barFrom, barTo); // Óäàëèòü ñòàðûå ëèíèè ObjectsDeleteAll(0, prefix); // Îòîáðàçèòü ãèñòîãðàììó DrawHg(prefix, lowPrice, volumes, barFrom, barTo, zoom, modes, maxPos, medianPos, vwapPos); } return(totalResult); } double MathRound(const double value, const double error) { return(error == 0 ? value : MathRound(value / error) * error); } bool ColorToRGB(const color c, int &r, int &g, int &b) { // Åñëè öâåò çàäàí íåâåðíûé, ëèáî çàäàí êàê îòñóòñòâóþùèé, âåðíóòü false if (COLOR_IS_NONE(c)) return(false); b = (c & 0xFF0000) >> 16; g = (c & 0x00FF00) >> 8; r = (c & 0x0000FF); return(true); } color MixColors(const color color1, const color color2, double mix, double step = 16) { // Êîððåêöèÿ íåâåðíûõ ïàðàìåòðîâ step = PUT_IN_RANGE(step, 1.0, 255.0); mix = PUT_IN_RANGE(mix, 0.0, 1.0); int r1, g1, b1; int r2, g2, b2; // Ðàçáèòü íà êîìïîíåíòû ColorToRGB(color1, r1, g1, b1); ColorToRGB(color2, r2, g2, b2); // âû÷èñëèòü int r = PUT_IN_RANGE((int)MathRound(r1 + mix * (r2 - r1), step), 0, 255); int g = PUT_IN_RANGE((int)MathRound(g1 + mix * (g2 - g1), step), 0, 255); int b = PUT_IN_RANGE((int)MathRound(b1 + mix * (b2 - b1), step), 0, 255); return(RGB_TO_COLOR(r, g, b)); } bool ColorIsNone(const color c) { return(COLOR_IS_NONE(c)); } int ArrayIndexOf(const int &arr[], const int value, const int startingFrom = 0) { int count = ArraySize(arr); for (int i = startingFrom; i < count; i++) { if (arr[i] == value) return(i); } return(-1); } int ArrayIndexOf(const datetime &arr[], const datetime value, const int startingFrom = 0) { int count = ArraySize(arr); for (int i = startingFrom; i < count; i++) { if (arr[i] == value) return(i); } return(-1); } int ArrayAdd(datetime &arr[], const datetime value, const bool checkUnique = false, const int reserveSize = 100) { int i; // Íàéòè ñóùåñòâóþùèé, åñëè íåîáõîäèìî if (checkUnique) { i = ArrayIndexOf(arr, value); if (i != -1) return(i); } // Äîáàâèòü íîâûé ýëåìåíò â ìàññèâ i = ArrayResize(arr, ArraySize(arr) + 1, reserveSize); if (i == -1) return(-1); i--; arr[i] = value; return(i); } double ArraySum(const double &arr[]) { double sum = 0; for (int i = 0, size = ArraySize(arr); i < size; i++) sum += arr[i]; return(sum); } int ArrayMedian(const double &values[]) { int size = ArraySize(values); double halfVolume = ArraySum(values) / 2.0; // èä¸ì ïî ãèñòîãðàììå è îñòàíàâëèâàåìñÿ íà ñåðåäèíå ïî îáú¸ìó double v = 0; for (int i = 0; i < size; i++) { v += values[i]; if (v >= halfVolume) return(i); } return(-1); } string TrimRight(string s, const ushort ch) { int len = StringLen(s); // Íàéòè íà÷àëî âûðåçàåìîãî äî êîíöà ó÷àñòêà int cut = len; for (int i = len - 1; i >= 0; i--) { if (StringGetCharacter(s, i) == ch) cut--; else break; } if (cut != len) { if (cut == 0) s = ""; else s = StringSubstr(s, 0, cut); } return(s); } string DoubleToString(const double d, const uint digits, const uchar separator) { string s = DoubleToString(d, digits) + ""; //HACK: áåç +"" ôóíêöèÿ ìîæåò âåðíóòü ïóñòîå çíà÷åíèå (áèëä 697) if (separator != '.') { int p = StringFind(s, "."); if (p != -1) StringSetCharacter(s, p, separator); } return(s); } string DoubleToCompactString(const double d, const uint digits = 8, const uchar separator = '.') { string s = DoubleToString(d, digits, separator); // óáðàòü íóëè â êîíöå äðîáíîé ÷àñòè if (StringFind(s, CharToString(separator)) != -1) { s = TrimRight(s, '0'); s = TrimRight(s, '.'); } return(s); } int GetPointDigits(const double point) { if (point == 0) return(_Digits); return(GetPointDigits(point, _Digits)); } int GetPointDigits(const double point, const int maxDigits) { if (point == 0) return(maxDigits); string pointString = DoubleToCompactString(point, maxDigits); int pointStringLen = StringLen(pointString); int dotPos = StringFind(pointString, "."); // pointString => result: // 1230 => -1 // 123 => 0 // 12.3 => 1 // 1.23 => 2 // 0.123 => 3 // .123 => 3 return(dotPos < 0 ? StringLen(TrimRight(pointString, '0')) - pointStringLen : pointStringLen - dotPos - 1); } template int ArrayMax(const T &array[], const int start = 0, const int count = WHOLE_ARRAY) { return(ArrayMaximum(array, count, start)); } int HgModes_old(const double &values[], const int modeStep, int &modes[]) { int modeCount = 0; ArrayFree(modes); // èùåì ìàêñèìóìû ïî ó÷àñòêàì for (int i = modeStep, count = ArraySize(values) - modeStep; i < count; i++) { int maxFrom = i - modeStep; int maxRange = 2 * modeStep + 1; int maxTo = maxFrom + maxRange - 1; int k = ArrayMax(values, maxFrom, maxRange); if (k != i) continue; for (int j = i - modeStep; j <= i + modeStep; j++) { if (values[j] != values[k]) continue; modeCount++; ArrayResize(modes, modeCount, count); modes[modeCount - 1] = j; } } return(modeCount); } int HgVwap(const double &values[], const double low, const double step) { if (step == 0) return(-1); double vwapPrice = 0; double totalVolume = 0; int size = ArraySize(values); for (int i = 0; i < size; i++) { double price = low + i * step; double volume = values[i]; vwapPrice += price * volume; totalVolume += volume; } if (totalVolume == 0) return(-1); vwapPrice /= totalVolume; return((int)((vwapPrice - low) / step + 0.5)); } class MillisecondTimer { private: int _milliseconds; private: uint _lastTick; public: void MillisecondTimer(const int milliseconds, const bool reset = true) { _milliseconds = milliseconds; if (reset) Reset(); else _lastTick = 0; } public: bool Check() { // ïðîâåðèòü îæèäàíèå uint now = getCurrentTick(); bool stop = now >= _lastTick + _milliseconds; // ñáðàñûâàåì òàéìåð if (stop) _lastTick = now; return(stop); } public: void Reset() { _lastTick = getCurrentTick(); } private: uint getCurrentTick() const { return(GetTickCount()); } }; void ObjectDisable(const long chartId, const string name) { ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true); ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false); } template void Swap(T &value1, T &value2) { T tmp = value1; value1 = value2; value2 = tmp; } int GetTimeBarRight(datetime time, ENUM_TIMEFRAMES period = PERIOD_CURRENT) { int bar = iBarShift(_Symbol, period, time); datetime t = iTime(_Symbol, period, bar); if ((t != time) && (bar == 0)) { // âðåìÿ çà ïðåäåëàìè äèàïàçîíà bar = (int)((iTime(_Symbol, period, 0) - time) / PeriodSeconds(period)); } else { // ïðîâåðèòü, ÷òîáû áàð áûë íå ñëåâà ïî âðåìåíè if (t < time) bar--; } return(bar); } // ïîëó÷èòü âðåìÿ ïî íîìåðó áàðà ñ ó÷åòîì âîçìîæíîãî âûõîäà çà äèàïàçîí áàðîâ (íîìåð áàðà ìåíüøå 0) datetime GetBarTime(const int shift, ENUM_TIMEFRAMES period = PERIOD_CURRENT) { if (shift >= 0) return(iTime(_Symbol, period, shift)); else return(iTime(_Symbol, period, 0) - shift * PeriodSeconds(period)); } void DrawHorizon(const string lineName, const datetime time) { DrawVLine(lineName, time, Red, 1, STYLE_DOT, false); ObjectDisable(0, lineName); } void DrawVLine(const string name, const datetime time1, const color lineColor, const int width, const int style, const bool back) { if (ObjectFind(0, name) >= 0) ObjectDelete(0, name); ObjectCreate(0, name, OBJ_VLINE, 0, time1, 0); ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, name, OBJPROP_BACK, back); ObjectSetInteger(0, name, OBJPROP_STYLE, style); ObjectSetInteger(0, name, OBJPROP_WIDTH, width); } void DrawBar(const string name, const datetime time1, const datetime time2, const double price, const color lineColor, const int width, const ENUM_VP_BAR_STYLE barStyle, const ENUM_LINE_STYLE lineStyle, bool back) { ObjectDelete(0, name); if ((barStyle == VP_BAR_STYLE_BAR) || (barStyle == VP_BAR_STYLE_BAR_FILLED) || (barStyle == VP_BAR_STYLE_COLOR)) ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price - _hgPoint / 2.0, time2, price + _hgPoint / 2.0); else if (barStyle == VP_BAR_STYLE_OUTLINE) ObjectCreate(0, name, OBJ_TREND, 0, time1, price, time2, price + _hgPoint); else ObjectCreate(0, name, OBJ_TREND, 0, time1, price, time2, price); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor); ObjectSetInteger(0, name, OBJPROP_STYLE, lineStyle); ObjectSetInteger(0, name, OBJPROP_WIDTH, lineStyle == STYLE_SOLID ? width : 1); ObjectSetInteger(0, name, OBJPROP_RAY, false); ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false); if (barStyle == VP_BAR_STYLE_BAR) back = false; else if ((barStyle == VP_BAR_STYLE_BAR_FILLED) || (barStyle == VP_BAR_STYLE_COLOR)) back = true; ObjectSetInteger(0, name, OBJPROP_BACK, back); } void DrawLevel(const string name, const double price) { ObjectDelete(0, name); ObjectCreate(0, name, OBJ_HLINE, 0, 0, price); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_COLOR, _modeLevelColor); ObjectSetInteger(0, name, OBJPROP_STYLE, _modeLevelStyle); ObjectSetInteger(0, name, OBJPROP_WIDTH, _modeLevelStyle== STYLE_SOLID ? _modeLevelWidth : 1); // íå äîëæåí áûòü ôîíîì, èíà÷å íå áóäåò îòîáðàæåíà öåíà ñïðàâà ObjectSetInteger(0, name, OBJPROP_BACK, false); } void DrawHg(const string prefix, const double lowPrice, double &volumes[], int barFrom, int barTo, double zoom, int &modes[], const int max = -1, const int median = -1, const int vwap = -1) { if (ArraySize(volumes) == 0) { return; } if (barFrom > barTo) zoom = -zoom; color cl = _hgColor1; double maxValue = volumes[ArrayMax(volumes)]; double volume; double nextVolume = 0; bool isOutline = _hgBarStyle == VP_BAR_STYLE_OUTLINE; bool isRectangle = (_hgBarStyle == VP_BAR_STYLE_BAR) || (_hgBarStyle == VP_BAR_STYLE_BAR_FILLED) || (_hgBarStyle == VP_BAR_STYLE_COLOR); int bar1 = barFrom; int bar2 = barTo; int modeBar2 = barTo; for (int i = 0, size = ArraySize(volumes); i < size; i++) { double price = NormalizeDouble(lowPrice + i * _hgPoint, _hgPointDigits); string priceString = DoubleToString(price, _hgPointDigits); string name = prefix + priceString; volume = volumes[i]; if (isOutline) { if (i < size - 1) { nextVolume = volumes[i + 1]; bar1 = (int)(barFrom + volume * zoom); bar2 = (int)(barFrom + nextVolume * zoom); modeBar2 = bar1; } } else if (_hgBarStyle != VP_BAR_STYLE_COLOR) { bar2 = (int)(barFrom + volume * zoom); modeBar2 = bar2; } datetime timeFrom = GetBarTime(barFrom); datetime timeTo = GetBarTime(barTo); datetime t1 = GetBarTime(bar1); datetime t2 = GetBarTime(bar2); datetime mt2 = GetBarTime(modeBar2); // Ïðè ñîâïàäåíèè íåñêîëüêèõ óðîâíåé ðèñîâàòü òîëüêî îäèí â ïðèîðèòåòå: max, median, vwap, mode. // Åñëè íè÷åãî íå ñîâïàäàåò, íàðèñîâàòü îáû÷íûé áàð. if (_showModeLevel && (ArrayIndexOf(modes, i) != -1)) DrawLevel(name + " level", price); //  ðåæèìå êîíòóðà ïîñëåäíèé áàð íå ðèñóåòñÿ if (_showHg && !(isOutline && (i == size - 1))) { if (_hgColor1 != _hgColor2) cl = MixColors(_hgColor1, _hgColor2, (isOutline ? MathMax(volume, nextVolume) : volume) / maxValue, 8); DrawBar(name, t1, t2, price, cl, _hgLineWidth, _hgBarStyle, STYLE_SOLID, true); } if (_showMedian && (i == median)) { DrawBar(name + " median", timeFrom, timeTo, price, _medianColor, _modeLineWidth, VP_BAR_STYLE_LINE, _statLineStyle, false); } else if (_showVwap && (i == vwap)) { DrawBar(name + " vwap", timeFrom, timeTo, price, _vwapColor, _modeLineWidth, VP_BAR_STYLE_LINE, _statLineStyle, false); } else if ((_showMax && (i == max)) || (_showModes && (ArrayIndexOf(modes, i) != -1))) { color modeColor = (_showMax && (i == max)) ? _maxColor : _modeColor; if (_hgBarStyle == VP_BAR_STYLE_LINE) DrawBar(name, timeFrom, mt2, price, modeColor, _modeLineWidth, VP_BAR_STYLE_LINE, STYLE_SOLID, false); else if (_hgBarStyle == VP_BAR_STYLE_BAR) DrawBar(name, timeFrom, mt2, price, modeColor, _modeLineWidth, VP_BAR_STYLE_BAR, STYLE_SOLID, false); else if (_hgBarStyle == VP_BAR_STYLE_BAR_FILLED) DrawBar(name, timeFrom, mt2, price, modeColor, _modeLineWidth, VP_BAR_STYLE_BAR_FILLED, STYLE_SOLID, false); else if (_hgBarStyle == VP_BAR_STYLE_OUTLINE) DrawBar(name + "+", timeFrom, mt2, price, modeColor, _modeLineWidth, VP_BAR_STYLE_LINE, STYLE_SOLID, false); else if (_hgBarStyle == VP_BAR_STYLE_COLOR) DrawBar(name, timeFrom, mt2, price, modeColor, _modeLineWidth, VP_BAR_STYLE_BAR_FILLED, STYLE_SOLID, false); } } } // ïîëó÷èòü äèàïàçîí áàðîâ â òåêóùåì ÒÔ (äëÿ ðèñîâàíèÿ) bool GetRangeBars(const datetime timeFrom, const datetime timeTo, int &barFrom, int &barTo) { barFrom = GetTimeBarRight(timeFrom); barTo = GetTimeBarRight(timeTo); return(true); } int GetHgByRates(const datetime timeFrom, const datetime timeTo, const double point, const ENUM_TIMEFRAMES dataPeriod, const ENUM_APPLIED_VOLUME appliedVolume, double &low, double &volumes[]) { // Ïîëó÷èòü ìèíóòêè MqlRates rates[]; int rateCount = CopyRates(_Symbol, dataPeriod, timeFrom, timeTo, rates); if (rateCount <= 0) return(0); MqlRates rate = rates[0]; low = NORM_PRICE(rate.low, point); double high = NORM_PRICE(rate.high, point); for (int i = 1; i < rateCount; i++) { rate = rates[i]; double rateHigh = NORM_PRICE(rate.high, point); double rateLow = NORM_PRICE(rate.low, point); if (rateLow < low) low = rateLow; if (rateHigh > high) high = rateHigh; } int lowIndex = ROUND_PRICE(low, point); int highIndex = ROUND_PRICE(high, point); int hgSize = highIndex - lowIndex + 1; // êîëè÷åñòâî öåí â ãèñòîãðàììå ArrayResize(volumes, hgSize); ArrayInitialize(volumes, 0); int pri, oi, hi, li, ci; double dv, v; for (int j = 0; j < rateCount; j++) { rate = rates[j]; oi = ROUND_PRICE(rate.open, point) - lowIndex; hi = ROUND_PRICE(rate.high, point) - lowIndex; li = ROUND_PRICE(rate.low, point) - lowIndex; ci = ROUND_PRICE(rate.close, point) - lowIndex; v = appliedVolume == VOLUME_REAL ? (double)rate.real_volume : (double)rate.tick_volume; if (v == 0) return(0); // èìèòàöèÿ òèêîâ if (ci >= oi) { // áû÷üÿ ñâå÷à dv = v / (oi - li + hi - li + hi - ci + 1.0); // open --> low for (pri = oi; pri >= li; pri--) volumes[pri] += dv; // low+1 ++> high for (pri = li + 1; pri <= hi; pri++) volumes[pri] += dv; // high-1 --> close for (pri = hi - 1; pri >= ci; pri--) volumes[pri] += dv; } else { // ìåäâåæüÿ ñâå÷à dv = v / (hi - oi + hi - li + ci - li + 1.0); // open ++> high for (pri = oi; pri <= hi; pri++) volumes[pri] += dv; // high-1 --> low for (pri = hi - 1; pri >= li; pri--) volumes[pri] += dv; // low+1 ++> close for (pri = li + 1; pri <= ci; pri++) volumes[pri] += dv; } } return(hgSize); } // Îáíîâèòü öâåòà, âû÷èñëÿåìûå àâòîìàòè÷åñêè. Åñëè îáíîâëåíèå ïðîèçîøëî, âåðíóòü true, èíà÷å false bool UpdateAutoColors() { if (!_showHg) return(false); bool isNone1 = ColorIsNone(_defaultHgColor1); bool isNone2 = ColorIsNone(_defaultHgColor2); if (isNone1 && isNone2) return(false); color newBgColor = (color)ChartGetInteger(0, CHART_COLOR_BACKGROUND); if (newBgColor == _prevBackgroundColor) return(false); _hgColor1 = isNone1 ? newBgColor : _defaultHgColor1; _hgColor2 = isNone2 ? newBgColor : _defaultHgColor2; _prevBackgroundColor = newBgColor; return(true); } string _prefix; string _tfn; string _ttn; // èñòîðèÿ ðèñîâàíèÿ datetime _drawHistory[]; // ïîñëåäíèé çàïóñê óñïåøíûé bool _lastOK = false; // ìèíèìàëüíîå èçìåíåíèå öåíû äëÿ îòîáðàæåíèÿ ãã int _modeStep = 0; color _prevBackgroundColor = clrNONE; int _rangeCount; ENUM_VP_BAR_STYLE _hgBarStyle; double _hgPoint; int _hgPointDigits; color _defaultHgColor1; color _defaultHgColor2; color _hgColor1; color _hgColor2; int _hgLineWidth; color _modeColor; color _maxColor; color _medianColor; color _vwapColor; int _modeLineWidth; ENUM_LINE_STYLE _statLineStyle; color _modeLevelColor; ENUM_LINE_STYLE _modeLevelStyle; int _modeLevelWidth; bool _showHg; bool _showModes; bool _showMax; bool _showMedian; bool _showVwap; bool _showModeLevel; double _zoom; int _firstVisibleBar = 0; int _lastVisibleBar = 0; MillisecondTimer *_updateTimer; // 2016-01-12 15:32:57 UTC // MQLMake 1.30. Copyright © FXcoder, 2011-2016. http://fxcoder.net