суббота, 30 января 2016 г.

Использование индикатора VP в своём коде

Индикатор Volume Profile не имеет обычных линий, поэтому нельзя получить его значения через стандартный механизм получения данных другого индикатора. Кроме того, количество интересующих параметров может быть произвольным, так как количество мод, локальных максимумов, заранее не может быть известно. Посмотрим, как такой индикатор можно использовать в своём коде.

Для простоты изложения проверки на ошибки в результатах функций будут опущены. В реальной работе нужно проверять всё, хотя иногда достаточно и голого варианта, например чтобы быстро прогнать новую идею в тестере.

Самый оптимальный способ использования VP в роботе (например) - взять из него функции расчёта гистограммы и статистических параметров, отбросив всё рисование и вспомогательные функции.

Если интересуют все параметры, понадобятся следующие функции:
  • GetHg или GetHgByTicks для получения гистограммы
  • HgModes - моды
  • ArrayMax - максимум (также требуется для HgModes)
  • ArrayMedian и Sum - медиана
  • HgVwap - VWAP
Ещё необходимо скопировать два определения (#define), для ROUND_PRICE и NORM_PRICE, а также перечисление enum ENUM_APPLIED_VOLUME, если ваш код для MT4.

ArrayMax - это просто обёртка для стандартной функции ArrayMaximum, она отличается в вариантах индикатора для MT4 и MT5. Подобные отличия для совместимости могут быть или появиться и в других функциях, поэтому для MT4 копируем функции из VP.mq4, а для MT5 - из VP.mq5 (VP-Range тоже можно использовать, эти функции идентичны в обоих индикаторах).

Рассмотрим все функции подробнее. Начнём с главной - GetHg (у GetHgByTicks параметры идентичны).

int GetHg(
    const datetime timeFrom, 
    const datetime timeTo, 
    const double point, 
    const ENUM_TIMEFRAMES dataPeriod, 
    const ENUM_APPLIED_VOLUME appliedVolume, 
    double &low, 
    double &volumes[])


У функции 5 входных параметров:
  • timeFrom и timeTo указывают период времени, для которого нужно рассчитать гистограмму, период включает обе указанные границы.
  • point указывает шаг цены в гистограмме. Для пятизнаковых инструментов обычно можно указывать _Point * 10.
  • dataPeriod - таймфрейм для исходных данных, в большинстве случаев лучше использовать PERIOD_M1. Для очень больших периодов расчёта можно поднять до PERIOD_M5 или даже выше. Больше таймфрейм - быстрее работа, но грубее результат. В функции GetHgByTicks следует использовать PERIOD_M1.
  • appliedVolume - реальный или тиковый объём.
И три выходных параметра:
  • результат функции - количество элементов в гистограмме
  • low - нижняя цена гистограммы. Так как все линии гистограммы идут через одинаковый шаг (point), хранить каждую цену для каждого уровня не имеет большого смысла и только замедляет работу.
  • volumes[] - собственно гистограмма, распределение объёмов.
Например, получение гистограммы за последние 1000 минут по тиковым данным может выглядеть следующим образом.

Сначала получим временные рамки для этих 1000 минут:

    datetime timeTo = TimeCurrent();
    datetime timeArr[];
    
    if (CopyTime(_Symbol, PERIOD_M1, timeTo, 1000, timeArr) < 1)
        return;
        
    datetime timeFrom = timeArr[0];


Потом рассчитаем гистограмму:

    double lowPrice;
    double volumes[];
    int hgPointScale = 10;
    double point = _Point * hgPointScale;
    
    int count = GetHg(timeFrom, timeTo, point, PERIOD_M1, VOLUME_TICK, lowPrice, volumes);


Сама по себе гистограмма ничем не интересна, поэтому дальше займёмся поиском интересных уровней. Мод может быть несколько, поэтому их придётся хранить в массиве. Все функции поиска уровней возвращают индексы (позиции) уровней в массиве гистограммы (volumes). Параметры функций описывать не буду, они очевидны из кода.

    int modeStep = 100 / hgPointScale;
    int modes[];
    
    int modeCount = HgModes(volumes, modeStep, modes);
    int maxPos = ArrayMax(volumes);
    int medianPos = ArrayMedian(volumes);
    int vwapPos = HgVwap(volumes, lowPrice, point);


hgPointScale и modeStep можно вынести в параметры, как это сделано в индикаторах VP и VP-Range.

Получаем значения цены и объёма по индексу:

    double maxPosPrice = lowPrice + point * maxPos;
    double maxPosVolume = volumes[maxPos];


С модами так же, просто добавляется вложенность:

    for (int i = 0; i < modeCount; i++)
    {
        double modePrice = lowPrice + point * modes[i];
        double modeVolume = volumes[modes[i]];
        
        // делаем что-нибудь с модами...
    }

Вот и всё. Что делать с этими уровнями - решать вам.

Дополнение про максимумы

Может оказаться, что есть два и более уровней с одинаковым, максимальным, объёмом, но ни индикатор, ни, соответственно, пример выше этот случай не рассматривают.

Изменения в VP 5.5

Функция ArraySum переименована в Sum. Функция HgModes_old переименована в HgModes.

Изменения в VP 5.8

Функция GetHgByRates переименована в GetHg.

Изменения в VP 6.0

В версии 6.0 для MT5 появилась функция GetHgByTicks, вычисляющая гистограмму на основе тиков, получаемых от брокера. Параметры идентичны параметрам GetHg.

7 комментариев:

  1. Спасибо за статью, на половину просветился.

    ОтветитьУдалить
  2. Уважаемый разработчик, подскажите, пожалуйста, как можно получить суммарные данные по заданным уровням, содержащие : цену, объем и дату уровня.

    ОтветитьУдалить
    Ответы
    1. Опишите задачу подробнее.

      Удалить
    2. При работе индикатора отображается гистограмма объемов и , например, уровней мод, которых может быть несколько за выбранный период. Пересчет гистограммы происходит только за текущий период, прошлые остаются неизменными, вот и хочется понять как можно получить массив или несколько массивов, содержащих данные по модам или другим уровням. То есть, например, отображаются только моды за последние 3 дня. Соответственно за вчера - 3 моды с датой 20.12.2016 с ценами 1, 2, 3 и объемами 3, 4 ,5, позавчера 19.12.2016 цены : 2, 6, 3, объемы - 4, 1, 3 позавчера 18.12.2016, цены 5, 8, 10, объемы 4, 6, 11. На выходе получить бы массивы
      Modes_time[20.12.2016,20.12.2016,20.12.2016,19.12.2016,19.12.2016,19.12.2016,18.12.2016,18.12.2016,18.12.2016]
      Modes_prices[1,2,3,2,6,3,5,8,10]
      Modes_volumes[3,4,5,4,1,3,4,6,11]
      Как-то так :)

      Удалить
    3. Для программиста эта задача тривиальна. Нужно вычислить диапазоны времени для каждого отрезка (дня) и для каждого собрать данные, добавив их в общий массив.

      Боюсь, если начну это всё объяснять подробнее, то либо придётся учить вообще программированию, либо делать всё за вас :)

      Удалить
    4. Этот комментарий был удален автором.

      Удалить
    5. Задача действительно тривиальна, хоть я и не программист :) я рассчитывал что это уже решено где-то в коде индикатора, но я этого не увидел, значит правильно не увидел, так как нельзя увидеть то, чего нет :) Спасибо :)

      Удалить