Volume Profile
Сообщите нам, если считаете, что материал размещён без разрешения.
Сообщить о материале
Обращение по товару «volume profile source code.mq5» отправится на рассмотрение. Укажите контакт для ответа и опишите причину.
О программе
Расчёт выполняется для каждого диапазона с возможностью сдвига по времени и настройки масштаба точки. Данные могут отображаться в различных стилях линий, заливки и направлениях рисования. Цветовая схема автоматически адаптируется к фону графика при изменении настроек чарта.
Настройки программы
| Настройка | Описание |
|---|---|
| Range period (RangePeriod) | Период диапазона — Таймфрейм, на котором определяются границы анализируемых диапазонов баров. |
| Range count (RangeCount) | Количество диапазонов — Число диапазонов, используемых для расчёта профиля объёма. |
| Time shift (TimeShift) | Сдвиг времени — Смещение начала диапазона в минутах относительно стандартного времени. |
| Mode step (points) (ModeStep) | Шаг моды — Размер шага в пунктах для определения зон моды распределения объёма. |
| Point scale (HgPointScale) | Масштаб точки — Множитель для базовой цены пункта при построении профиля. |
| Volume type (VolumeType) | Тип объёма — Тип объёма, используемый при расчёте: тиковый или реальный. |
| Data source (DataSource) | Источник данных — Источник данных для расчёта: тики или бары указанного периода (M1, M5, M15, M30). |
| Bar style (HgBarStyle) | Стиль столбцов — Визуальный стиль отображения столбцов гистограммы объёма. |
| Draw direction (DrawDirection) | Направление рисования — Направление построения столбцов гистограммы: справа налево или слева направо. |
| Color 1 (HgColor) | Цвет столбцов 1 — Основной цвет столбцов гистограммы объёма. |
| Color 2 (HgColor2) | Цвет столбцов 2 — Вторичный цвет для градиентного заполнения столбцов гистограммы. |
| Line width (HgLineWidth) | Толщина линии столбцов — Толщина линии столбцов гистограммы. |
| Mode color (ModeColor) | Цвет моды — Цвет линии, обозначающей зону моды объёма. |
| Maximum color (MaxColor) | Цвет максимума — Цвет линии максимального объёма. |
| Median color (MedianColor) | Цвет медианы — Цвет линии медианного уровня объёма. |
| VWAP color (VwapColor) | Цвет VWAP — Цвет линии взвешенного по объёму среднего цены. |
| Mode line width (ModeLineWidth) | Толщина линий уровней — Толщина линий для уровней моды, максимума, медианы и VWAP. |
| Median & VWAP line style (StatLineStyle) | Стиль линий медианы и VWAP — Стиль отображения линий медианного уровня и VWAP. |
| Identifier (Id) | Идентификатор — Префикс идентификатора для именования графических объектов индикатора. |
Поиск по коду файла
#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_POINT_SCALE
{
POINT_SCALE_1 = 1, // *1
POINT_SCALE_10 = 10, // *10
POINT_SCALE_100 = 100, // *100
};
enum ENUM_VP_BAR_STYLE
{
VP_BAR_STYLE_LINE, // Line
VP_BAR_STYLE_BAR, // Empty bar
VP_BAR_STYLE_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
};
enum ENUM_VP_SOURCE
{
VP_SOURCE_TICKS = 0, // Ticks
VP_SOURCE_M1 = 1, // M1 bars
VP_SOURCE_M5 = 5, // M5 bars
VP_SOURCE_M15 = 15, // M15 bars
VP_SOURCE_M30 = 30, // M30 bars
};
enum ENUM_TIME_SHIFT
{
TIME_SHIFT_PLUS_720 = 720, // +12:00
TIME_SHIFT_PLUS_660 = 660, // +11:00
TIME_SHIFT_PLUS_600 = 600, // +10:00
TIME_SHIFT_PLUS_540 = 540, // +9:00
TIME_SHIFT_PLUS_480 = 480, // +8:00
TIME_SHIFT_PLUS_420 = 420, // +7:00
TIME_SHIFT_PLUS_360 = 360, // +6:00
TIME_SHIFT_PLUS_300 = 300, // +5:00
TIME_SHIFT_PLUS_240 = 240, // +4:00
TIME_SHIFT_PLUS_180 = 180, // +3:00
TIME_SHIFT_PLUS_120 = 120, // +2:00
TIME_SHIFT_PLUS_60 = 60, // +1:00
TIME_SHIFT_0 = 0, // 0:00 (no shift)
TIME_SHIFT_MINUS_60 = -60, // -1:00
TIME_SHIFT_MINUS_120 = -120, // -2:00
TIME_SHIFT_MINUS_180 = -180, // -3:00
TIME_SHIFT_MINUS_240 = -240, // -4:00
TIME_SHIFT_MINUS_300 = -300, // -5:00
TIME_SHIFT_MINUS_360 = -360, // -6:00
TIME_SHIFT_MINUS_420 = -420, // -7:00
TIME_SHIFT_MINUS_480 = -480, // -8:00
TIME_SHIFT_MINUS_540 = -540, // -9:00
TIME_SHIFT_MINUS_600 = -600, // -10:00
TIME_SHIFT_MINUS_660 = -660, // -11:00
TIME_SHIFT_MINUS_720 = -720, // -12:00
};
/* Calculation */
input ENUM_TIMEFRAMES RangePeriod = PERIOD_D1; // Range period
input int RangeCount = 20; // Range count
input ENUM_TIME_SHIFT TimeShift = TIME_SHIFT_0; // Time shift
input int ModeStep = 100; // Mode step (points)
input ENUM_POINT_SCALE HgPointScale = POINT_SCALE_10; // Point scale
input ENUM_APPLIED_VOLUME VolumeType = VOLUME_TICK; // Volume type
input ENUM_VP_SOURCE DataSource = VP_SOURCE_M1; // Data source
/* Histogram */
input ENUM_VP_BAR_STYLE HgBarStyle = VP_BAR_STYLE_LINE; // Bar style
input ENUM_HG_DIRECTION DrawDirection = HG_DIRECTION_RIGHT; // Draw direction
input color HgColor = C'128,160,192'; // Color 1
input color HgColor2 = C'128,160,192'; // Color 2
input int HgLineWidth = 1; // Line width
/* Levels */
input color ModeColor = clrBlue; // Mode color
input color MaxColor = clrNONE; // Maximum color
input color MedianColor = clrNONE; // 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 string Id = "+vp"; // Identifier
bool ShowHorizon = true; // Show data horizon
double Zoom = 0; // Zoom (0=auto)
int WaitMilliseconds = 1000; // Wait milliseconds
uint RangeLength = 0; // Range length (0=Range period) // �� �����������
void OnInit()
{
// код доступен только после оплаты
}
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[])
{
// код доступен только после оплаты
}
void OnTimer()
{
CheckTimer();
}
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, _prefix);
delete(_updateTimer);
}
void CheckTimer()
{
EventKillTimer();
if (_updateTimer.Check() || !_lastOK)
{
_lastOK = Update();
if (!_lastOK)
EventSetTimer(3);
ChartRedraw();
_updateTimer.Reset();
}
else
{
EventSetTimer(3);
}
}
bool Update()
{
datetime ranges[];
ArraySetAsSeries(ranges, true);
ArrayResize(ranges, _rangeCount);
if (CopyTime(_Symbol, RangePeriod, 0, _rangeCount, ranges) != _rangeCount)
return(false);
if (RangePeriod == PERIOD_W1)
{
for (int i = 0; i < _rangeCount; i++)
ranges[i] += 1440 * 60;
}
/* ��������� ������� ����������� ���������. */
int rangeLengthSeconds = RangeLength == 0 ? PeriodSeconds(RangePeriod) : (int)RangeLength * 60;
datetime dataRates[];
datetime rangesStart = ranges[_rangeCount - 1] + _timeShiftSeconds;
datetime rangesEnd = ranges[0] + rangeLengthSeconds - 1 + _timeShiftSeconds;
if (CopyTime(_Symbol, _dataPeriod, rangesStart, rangesEnd, dataRates) <= 0)
return(false);
MqlTick tick;
if (!SymbolInfoTick(_Symbol, tick))
return(false);
datetime lastTickTime = tick.time;
if (ShowHorizon)
{
datetime horizon = GetHorizon(DataSource, _dataPeriod);
DrawHorizon(_prefix + "hz", horizon);
}
int modes[];
double volumes[];
double lowPrice;
bool totalResult = true;
for (int i = 0; i < _rangeCount; i++)
{
/* ������ */
datetime rangeStart = ranges[i] + _timeShiftSeconds;
if (TimeDayOfWeek(rangeStart) == SUNDAY)
rangeStart -= 2 * 1440 * 60;
if ((i != 0) && (ArrayIndexOf(_drawHistory, rangeStart) != -1))
continue;
datetime rangeEnd;
if (i == 0)
{
rangeEnd = ranges[i] + _timeShiftSeconds + rangeLengthSeconds - 1;
}
else
{
rangeEnd = ranges[i - 1] + _timeShiftSeconds - 1;
if (TimeDayOfWeek(rangeEnd) == SUNDAY)
rangeEnd -= 2 * 1440 * 60;
}
int barFrom, barTo;
if (!GetRangeBars(rangeStart, rangeEnd, barFrom, barTo))
{
totalResult = false;
continue;
}
int count;
if (DataSource == VP_SOURCE_TICKS)
count = GetHgByTicks(rangeStart, rangeEnd, _hgPoint, _dataPeriod, VolumeType, lowPrice, volumes);
else
count = GetHg(rangeStart, rangeEnd, _hgPoint, _dataPeriod, VolumeType, lowPrice, volumes);
if (count <= 0)
{
totalResult = false;
continue;
}
if (rangeEnd < lastTickTime)
ArrayAdd(_drawHistory, rangeStart, true);
/* ����������� */
int modeCount = _showModes ? HgModes(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 maxVolume = volumes[ArrayMaximum(volumes)];
if (maxVolume == 0)
maxVolume = 1;
double zoom = _zoom > 0 ? _zoom : (barFrom - barTo) / maxVolume;
if (DrawDirection == HG_DIRECTION_LEFT)
Swap(barFrom, barTo);
ObjectsDeleteAll(0, prefix);
DrawHg(prefix, lowPrice, volumes, barFrom, barTo, zoom, modes, maxPos, medianPos, vwapPos);
}
return(totalResult);
}
ENUM_DAY_OF_WEEK TimeDayOfWeek(const datetime time)
{
MqlDateTime timeStruct;
TimeToStruct(time, timeStruct);
return (ENUM_DAY_OF_WEEK)timeStruct.day_of_week;
}
template <typename T>
int ArrayIndexOf(const T &arr[], const T value, const int startingFrom = 0)
{
int size = ArraySize(arr);
for (int i = startingFrom; i < size; i++)
{
if (arr[i] == value)
return(i);
}
return(-1);
}
template <typename T>
int ArrayAdd(T &arr[], T 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);
}
template <typename T>
bool ArrayCheckRange(const T &arr[], int &start, int &count)
{
int size = ArraySize(arr);
if (size <= 0)
return(false);
if (count == 0)
return(false);
if ((start > size - 1) || (start < 0))
return(false);
if (count < 0)
{
count = size - start;
}
else if (count > size - start)
{
count = size - start;
}
return(true);
}
int ArrayMedian(const double &values[])
{
int size = ArraySize(values);
double halfVolume = Sum(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);
}
double MathRound(const double value, const double error)
{
return(error == 0 ? value : MathRound(value / error) * error);
}
template <typename T>
void Swap(T &value1, T &value2)
{
T tmp = value1;
value1 = value2;
value2 = tmp;
}
template <typename T>
T Sum(const T &arr[], int start = 0, int count = -1)
{
if (!ArrayCheckRange(arr, start, count))
return((T)NULL);
T sum = (T)NULL;
for (int i = start, end = start + count; i < end; i++)
sum += arr[i];
return(sum);
}
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, ".");
return(dotPos < 0
? StringLen(TrimRight(pointString, '0')) - pointStringLen
: pointStringLen - dotPos - 1);
}
template <typename T>
int ArrayMax(const T &array[], const int start = 0, const int count = WHOLE_ARRAY)
{
return(ArrayMaximum(array, start, count));
}
int HgModes(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 &volumes[], const double low, const double step)
{
if (step == 0)
return(-1);
double vwap = 0;
double totalVolume = 0;
int size = ArraySize(volumes);
for (int i = 0; i < size; i++)
{
double price = low + i * step;
double volume = volumes[i];
vwap += price * volume;
totalVolume += volume;
}
if (totalVolume == 0)
return(-1);
vwap /= totalVolume;
return((int)((vwap - low) / step + 0.5));
}
int _iBarShift(string symbol, ENUM_TIMEFRAMES timeframe, datetime time, bool exact = false)
{
if (time < 0)
return(-1);
datetime arr[];
datetime time1;
CopyTime(symbol, timeframe, 0, 1, arr);
time1 = arr[0];
if (CopyTime(symbol, timeframe, time, time1, arr) <= 0)
return(-1);
if (ArraySize(arr) > 2)
return(ArraySize(arr) - 1);
return(time < time1 ? 1 : 0);
}
datetime _iTime(string symbol, ENUM_TIMEFRAMES timeframe, int index)
{
if (index < 0)
return(-1);
datetime arr[];
if (CopyTime(symbol, timeframe, index, 1, arr)<= 0)
return(-1);
return(arr[0]);
}
int GetHgByTicks(const datetime timeFrom, const datetime timeTo, const double point, const ENUM_TIMEFRAMES dataPeriod, const ENUM_APPLIED_VOLUME appliedVolume, double &low, double &volumes[])
{
long tickVolumes[];
int tickVolumeCount = CopyTickVolume(_Symbol, dataPeriod, timeFrom, timeTo, tickVolumes);
if (tickVolumeCount <= 0)
return(0);
long tickVolumesTotal = Sum(tickVolumes);
MqlTick ticks[];
int tickCount = CopyTicks(_Symbol, ticks, COPY_TICKS_TRADE, timeFrom * 1000, (uint)tickVolumesTotal);
if (tickCount <= 0)
{
return(0);
}
MqlTick tick = ticks[0];
low = NORM_PRICE(tick.last, point);
double high = low;
long timeToMs = timeTo * 1000;
for (int i = 1; i < tickCount; i++)
{
tick = ticks[i];
if (tick.time_msc > timeToMs)
{
tickCount = i;
break;
}
double tickLast = NORM_PRICE(tick.last, point);
if (tickLast < low)
low = tickLast;
if (tickLast > high)
high = tickLast;
}
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;
for (int j = 0; j < tickCount; j++)
{
tick = ticks[j];
pri = ROUND_PRICE(tick.last, point) - lowIndex;
volumes[pri] += (appliedVolume == VOLUME_REAL) ? (double)tick.volume : 1;
}
return(hgSize);
}
int GetHg(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 (ci >= oi)
{
/* ����� ����� */
dv = v / (oi - li + hi - li + hi - ci + 1.0);
for (pri = oi; pri >= li; pri--)
volumes[pri] += dv;
for (pri = li + 1; pri <= hi; pri++)
volumes[pri] += dv;
for (pri = hi - 1; pri >= ci; pri--)
volumes[pri] += dv;
}
else
{
/* �������� ����� */
dv = v / (hi - oi + hi - li + ci - li + 1.0);
for (pri = oi; pri <= hi; pri++)
volumes[pri] += dv;
for (pri = hi - 1; pri >= li; pri--)
volumes[pri] += dv;
for (pri = li + 1; pri <= ci; pri++)
volumes[pri] += dv;
}
}
return(hgSize);
}
datetime GetHorizon(ENUM_VP_SOURCE dataSource, ENUM_TIMEFRAMES dataPeriod)
{
if (dataSource == VP_SOURCE_TICKS)
{
MqlTick ticks[];
int tickCount = CopyTicks(_Symbol, ticks, COPY_TICKS_INFO, 1, 1);
if (tickCount <= 0)
return ((datetime)(SymbolInfoInteger(_Symbol, SYMBOL_TIME) + 1));
return(ticks[0].time);
}
return((datetime)(_iTime(_Symbol, dataPeriod, Bars(_Symbol, dataPeriod) - 1)));
}
ENUM_TIMEFRAMES GetDataPeriod(ENUM_VP_SOURCE dataSource)
{
switch (dataSource)
{
case VP_SOURCE_TICKS: return(PERIOD_M1); // ��� ��������� ����� ����������� ��� �������� �����
case VP_SOURCE_M1: return(PERIOD_M1);
case VP_SOURCE_M5: return(PERIOD_M5);
case VP_SOURCE_M15: return(PERIOD_M15);
case VP_SOURCE_M30: return(PERIOD_M30);
default: return(PERIOD_M1);
Показано первые 50% кода (символов: 29061)
Открыть по тарифу
Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.
Разовая покупка файла
На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.
Зачем нужен email? После подтверждения оплаты файл сохранится в кабинете на этот email. Если аккаунта ещё нет, мы создадим его и пришлём ссылку для задания пароля. Если аккаунт уже есть, покупка добавится в него. Укажите адрес, к которому у вас есть доступ.
Чтобы оформить заказ, введите email и перейдите к оплате.