← К каталогу
Исходный код · ID 4352

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 и перейдите к оплате.

Стоимость полного кода
2 906,10₽ ≈ $35.52