Скрипт профиля рынка (Market Profile) с разделением на TPO в Pine Script v5

Скрипт профиля рынка (Market Profile) с разделением на TPO в Pine Script v5 Pine Script
Пошаговое руководство по созданию индикатора профиля рынка (Market Profile) с разделением на TPO в Pine Script v5. Готовый оптимизированный код с отрисовкой POC.
Суть: Профиль рынка TPO (Time Price Opportunity) отображает распределение времени, проведенного ценой на определенных уровнях. В Pine Script v5 классическая отрисовка буквами часто упирается в лимиты графических объектов. Представленный скрипт решает эту проблему за счет агрегации данных в массивы и вывода профиля через единый динамический текстовый блок с автоматическим расчетом POC (Point of Control).

Исходный код

Ниже представлен оптимизированный скрипт на языке Pine Script v5. Он собирает ценовые уровни внутри заданной сессии, распределяет их по 30-минутным интервалам (каждому интервалу соответствует своя буква) и строит наглядный профиль TPO прямо на графике, выделяя линию POC.

//@version=5
indicator('Market Profile TPO - Finfluct', overlay=true, max_labels_limit=500, max_lines_limit=500)

// Входные параметры
tpo_step      = input.float(1.0, title='Шаг цены TPO (в пунктах)', minval=0.0001)
session_spec  = input.session('0900-1800:23456', title='Торговая сессия')
text_color    = input.color(color.white, title='Цвет текста TPO')
bg_color      = input.color(color.new(color.blue, 90), title='Цвет фона профиля')
poc_color     = input.color(color.orange, title='Цвет линии POC')

// Определение сессии
in_session  = not na(time(timeframe.period, session_spec))
new_session = in_session and not in_session[1]

// Массив букв TPO для 30-минутных интервалов
var string[] tpo_letters = array.from(
     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 
     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 
     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
 )

// Хранилище данных профиля
var float[] price_levels = array.new_float(0)
var string[] tpo_strings = array.new_string(0)
var int session_start_idx = na
var label profile_lbl = na
var line poc_ln = na

// Функция поиска или создания ценового уровня
get_level_index(float price) =>
    int idx = array.indexof(price_levels, price)
    if idx == -1
        array.push(price_levels, price)
        array.push(tpo_strings, '')
        idx := array.size(price_levels) - 1
    idx

// Сброс данных при старте новой сессии
if new_session
    array.clear(price_levels)
    array.clear(tpo_strings)
    session_start_idx := bar_index
    profile_lbl := label.new(
         x=bar_index, 
         y=close, 
         text='', 
         style=label.style_label_left, 
         textcolor=text_color, 
         color=bg_color, 
         textalign=text.align_left
     )
    if not na(poc_ln)
        line.delete(poc_ln)
    poc_ln := line.new(x1=bar_index, y1=close, x2=bar_index, y2=close, color=poc_color, width=2)

// Наполнение профиля внутри сессии
if in_session and not na(session_start_idx)
    // Вычисление индекса 30-минутного интервала
    int elapsed_ms = int(time - time[bar_index - session_start_idx])
    int interval_index = math.min(math.floor(elapsed_ms / 1800000), array.size(tpo_letters) - 1)
    string current_letter = array.get(tpo_letters, interval_index)

    // Округление границ текущего бара под шаг TPO
    float low_bound = math.floor(low / tpo_step) * tpo_step
    float high_bound = math.ceil(high / tpo_step) * tpo_step

    // Заполнение ценовых уровней буквами
    for price = low_bound to high_bound by tpo_step
        float rounded_price = math.round(price / tpo_step) * tpo_step
        int idx = get_level_index(rounded_price)
        string current_str = array.get(tpo_strings, idx)
        
        // Добавляем букву, если её еще нет для этого уровня в текущем интервале
        if str.pos(current_str, current_letter) == -1
            array.set(tpo_strings, idx, current_str + current_letter)

    // Отрисовка профиля на каждом баре для интерактивности
    if array.size(price_levels) > 0
        // Сортировка уровней по убыванию цены
        int[] sorted_indices = array.sort_indices(price_levels, order.descending)
        
        string display_text = ''
        float poc_price = 0.0
        int max_tpo_len = 0
        
        for i = 0 to array.size(sorted_indices) - 1
            int orig_idx = array.get(sorted_indices, i)
            float price = array.get(price_levels, orig_idx)
            string tpos = array.get(tpo_strings, orig_idx)
            int tpo_len = str.length(tpos)
            
            if tpo_len > max_tpo_len
                max_tpo_len := tpo_len
                poc_price := price
            
            display_text := display_text + str.tostring(price, '#.##') + ' | ' + tpos + '\n'

        // Обновление метки профиля
        label.set_xy(profile_lbl, session_start_idx, poc_price)
        label.set_text(profile_lbl, display_text)
        
        // Обновление линии POC (Point of Control)
        line.set_xy1(poc_ln, session_start_idx, poc_price)
        line.set_xy2(poc_ln, bar_index, poc_price)

Разбор параметров

Для гибкой настройки индикатора под разные таймфреймы и инструменты мы вынесли ключевые переменные в панель настроек:

  • tpo_step: Шаг цены (размер строки TPO). Определяет чувствительность профиля. Для волатильных активов (например, BTCUSD) шаг следует увеличить, для акций или форекс-пар — уменьшить.
  • session_spec: Временные границы торговой сессии, внутри которой рассчитывается профиль. По умолчанию настроена дневная сессия.
  • text_color: Цвет букв TPO для кастомизации визуального стиля под темную или светлую тему графика.
  • bg_color: Цвет фона текстовой метки профиля с поддержкой прозрачности.
  • poc_color: Цвет горизонтальной линии Point of Control (уровня с максимальным скоплением TPO).

Как запустить

Чтобы запустить скрипт на платформе TradingView, выполните следующие шаги:

1. Откройте график нужного вам актива на TradingView (рекомендуется использовать таймфреймы от 1m до 5m для точного расчета внутри 30-минутных блоков).

2. В нижней панели выберите вкладку Pine Editor.

3. Скопируйте исходный код, представленный выше, и вставьте его в редактор, предварительно удалив стандартный шаблон.

4. Нажмите кнопку Add to Chart (Добавить на график).

5. При необходимости откройте настройки индикатора, чтобы скорректировать параметр tpo_step под текущую волатильность инструмента.

При разработке сложных торговых систем, использующих горизонтальные объемы и профили рынка, критически важно уметь вовремя фиксировать прибыль и ограничивать убытки. В этом вам поможет наш материал про динамический трейлинг-стоп по ATR в Pine Script v5: Инструкция.

Для институционального исполнения крупных ордеров внутри зон высокой ликвидности (POC), определенных профилем рынка, рекомендуется использовать скрипт TWAP на Pine Script v5: Алгоритмическое исполнение, который позволяет минимизировать рыночное проскальзывание.

Если вы хотите отслеживать трендовые развороты на множестве активов параллельно с анализом горизонтальных уровней TPO, изучите наш Pine Script v5: Скринер MACD кроссоверов для 40 тикеров для автоматизации рутинного сканирования рынка.

Оцените статью
FinFluct