Индикатор Volume Profile не имеет обычных линий, поэтому нельзя получить его значения через стандартный механизм получения данных другого индикатора. Кроме того, количество интересующих параметров может быть произвольным, так как количество мод и максимумов заранее не может быть известно.
В проекте индикатора VP на GitLab есть пример эксперта, который можно взять за основу для своих расчётов. Все необходимые для расчётов файлы идут с ним. Рядом с самим индикатором также есть набор включаемых файлов, но в нём много ненужных здесь файлов, например с функциями для отображения. Здесь приведён код из VPSimple 2.0.1.
Этот пример отображает на графике визуального тестера некоторые значения индикатора VP. Для этого используются мои индикаторы EA-Line.
Для начала следует определиться с диапазоном расчёта. Здесь возьмём 1000 последних баров, включая текущий.
Возможно, здесь есть возможность оптимизации по скорости. Однако не стоит использовать очевидную здесь функцию iTime, она очень медленная, даже в контексте такого простого примера.
Основная расчётная часть VP находится в классе CVPCalc. Вот пример создания экземпляра для расчёта с имитацией по M1 и масштабом 10. Параметры tick_price_type, tick_flags и quantiles здесь не рассматриваются, но их использование можно подглядеть в индикаторе VP или скрипте FindVL.
Теперь у нас есть диапазон расчёта и калькулятор, осталось применить их для расчёта гистограммы.
Гистограмму можно хранить разными способами, в VP используется способ с нижней ценой, шагом и набором объёмов. Такое представление предполагает непрерывность распределения, наличие значений для каждой цены от самой низкой до самой высокой. Шаг цены гистограммы определён в hg_point, нижняя цена - low_price, объёмы - volumes[].
Сама по себе гистограмма ничем не интересна, поэтому дальше займёмся поиском интересных уровней.
Мод может быть несколько, поэтому их придётся хранить в массиве. Все функции поиска уровней возвращают индексы (позиции) уровней в массиве гистограммы (volumes).
Далее на очереди максимум, медиана и VWAP. Может оказаться, что есть два и более уровней с одинаковым, максимальным, объёмом, но возьмём первый попавшийся. Логика в этом проста - если вас интересуют больше любого 1 максимума, то также могут интересовать и все локальные максимумы (моды).
Как выше уже писал, все вычисленные параметры представлены в виде индексов в массиве объёмов. Соответственно, цена (уровень) рассчитывается с использованием нижней цены (low_price), индекса и шага гистограммы (hg_point).
С модами так же, просто добавляется вложенность:
Вот и всё. Что делать с этими уровнями - решать вам.
В проекте индикатора VP на GitLab есть пример эксперта, который можно взять за основу для своих расчётов. Все необходимые для расчётов файлы идут с ним. Рядом с самим индикатором также есть набор включаемых файлов, но в нём много ненужных здесь файлов, например с функциями для отображения. Здесь приведён код из VPSimple 2.0.1.
Этот пример отображает на графике визуального тестера некоторые значения индикатора VP. Для этого используются мои индикаторы EA-Line.
Для начала следует определиться с диапазоном расчёта. Здесь возьмём 1000 последних баров, включая текущий.
datetime time_to = TimeCurrent(); datetime time_arr[]; if (CopyTime(_Symbol, PERIOD_M1, time_to, 1000, time_arr) < 1) return; datetime time_from = time_arr[0];
Возможно, здесь есть возможность оптимизации по скорости. Однако не стоит использовать очевидную здесь функцию iTime, она очень медленная, даже в контексте такого простого примера.
Основная расчётная часть VP находится в классе CVPCalc. Вот пример создания экземпляра для расчёта с имитацией по M1 и масштабом 10. Параметры tick_price_type, tick_flags и quantiles здесь не рассматриваются, но их использование можно подглядеть в индикаторе VP или скрипте FindVL.
int hg_point_scale = 10; double hg_point = _Point * hg_point_scale; CVPCalc vpcalc_(VP_SOURCE_M1, VOLUME_TICK, hg_point, VP_TICK_PRICE_LAST, 0, QUANTILE_NONE);
Теперь у нас есть диапазон расчёта и калькулятор, осталось применить их для расчёта гистограммы.
double low_price; double volumes[]; const int count = vpcalc_.get_hg(time_from, time_to, low_price, volumes); //const int count = vpcalc_.get_hg_by_ticks(time_from, time_to, low_price, volumes); if (count <= 0) return;
Гистограмму можно хранить разными способами, в VP используется способ с нижней ценой, шагом и набором объёмов. Такое представление предполагает непрерывность распределения, наличие значений для каждой цены от самой низкой до самой высокой. Шаг цены гистограммы определён в hg_point, нижняя цена - low_price, объёмы - volumes[].
Сама по себе гистограмма ничем не интересна, поэтому дальше займёмся поиском интересных уровней.
Мод может быть несколько, поэтому их придётся хранить в массиве. Все функции поиска уровней возвращают индексы (позиции) уровней в массиве гистограммы (volumes).
int mode_step = 100 / hg_point_scale; int modes[]; int mode_count = hg_modes(volumes, mode_step, modes);Здесь 100 - это Mode Step в индикаторе VP, определяющий минимальный зазор между соседними модами. Это значение используется в алгоритме по поиску мод (см. функцию hg_modes), который в VP довольно слабый, можно попробовать придумать что-нибудь самому.
Далее на очереди максимум, медиана и VWAP. Может оказаться, что есть два и более уровней с одинаковым, максимальным, объёмом, но возьмём первый попавшийся. Логика в этом проста - если вас интересуют больше любого 1 максимума, то также могут интересовать и все локальные максимумы (моды).
int max_pos = _arr.max_index(volumes); int median_pos = _math.median_index(volumes); int vwap_pos = hg_vwap_index(volumes, low_price, hg_point);
Как выше уже писал, все вычисленные параметры представлены в виде индексов в массиве объёмов. Соответственно, цена (уровень) рассчитывается с использованием нижней цены (low_price), индекса и шага гистограммы (hg_point).
double max_volume_price = low_price + hg_point * max_pos; double max_volume = volumes[max_pos];
С модами так же, просто добавляется вложенность:
for (int i = 0; i < mode_count; i++) { double mode_price = low_price + hg_point * modes[i]; double mode_volume = volumes[modes[i]]; // do something with the mode... }
Вот и всё. Что делать с этими уровнями - решать вам.