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

Volume Nodes & Value Migration [MQLSoftware]

volume nodes.pine
Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Это индикатор TradingView на Pine Script v6, который строит профили объёма по цене и отслеживает, как цена ведёт себя вокруг структуры этих профилей. Профили привязываются к якорным окнам (дневным, недельным, месячным, квартальным или годовым) и пересчитываются только по подтверждённым свечам. Индикатор отрисовывает гистограмму профилей, зоны ценности, линию точки контроля (POC), миграционные связи между окнами и состояние горизонтальных уровней-узлов. В нижней части графика выводится панель со статусом окна, текущими значениями и измеренными базовыми частотами повторных обращений к POC и разрешения узлов. Все события и расчёты привязаны к подтверждённым барам — живой профиль и панель обновляются как визуальный контекст, а не как сигналы.

Настройки программы

НастройкаОписание
anchorMode Якорный период — Выбор якорного окна для построения профилей: автоматический выбор по таймфрейму графика или фиксированный период (день, неделя, месяц, квартал).
keepProfiles Количество сохраняемых профилей — Сколько завершённых окон остаются нарисованными на графике; статистика и базовые частоты используют всю загруженную историю.
detail Детализация профиля — Задаёт целевую гранулярность построения профиля — грубую, сбалансированную или тонкую.
atrLen Длина ATR — Период расчёта ATR, используемый для определения высоты бинов и выражения расстояния миграции POC.
vaPct Процент зоны ценности — Доля объёма окна, которую охватывает зона ценности, строимая путём жадного расширения от бина POC.
trackNodes Отслеживание POC и HVN как узлов — Включает отслеживание возвратов цены к уровням POC и HVN с определением принятия или отклонения узла.
acceptN Количество подтверждённых закрытий для принятия — Сколько подтверждённых закрытий внутри зоны узла требуется для признания возврата принятым.
hvnMax Максимум HVN-узлов на окно — Сколько высоковолюмных узлов (кроме POC) активируется при фиксации окна.
showLvn Тонкие зоны (LVN) — Включает отображение тонких зон — участков бинов с низким объёмом относительно среднего.
marksKeep Количество сохраняемых меток — Сколько разрешённых меток узлов (принятых/отклонённых) остаются на графике.
showProf Зафиксированные профили — Отрисовка итоговой гистограммы каждого зафиксированного окна с затенённой зоной ценности.
showLive Живой формирующийся профиль — Отображение гистограммы текущего ещё не завершённого окна, перерисовываемого по мере роста.
profWidth Ширина профиля (% от окна) — Горизонтальная ширина гистограммы как доля от количества баров в окне.
showDev Формирующиеся POC и зона ценности — Отрисовка траектории развивающегося POC и полосы зоны ценности для активного окна.
showMig Связи миграции POC — Пунктирные линии и подписи расстояний между финальными POC последовательных окон.
glowOn Эффекты свечения — Включает мягкое свечение под линиями POC и узлов — чисто декоративная настройка.
colBody Цвет профиля — Основной цвет тела бинов профиля.
colPoc Цвет POC — Цвет линии точки контроля и её траектории миграции.
colAcc Цвет принятых — Цвет для узлов, чей возврат признан принятым.
colRej Цвет отклонённых — Цвет для узлов, чей возврат признан отклонённым.
showPanel Панель статистики — Включает отображение информационной панели со статусом окна, состоянием узлов и измеренными базовыми частотами.
panelPos Позиция панели — Угол графика, к которому привязана панель статистики.
panelSize Размер текста панели — Размер текста в информационной панели.
Получить полный код

Поиск по коду файла

indicator("Volume Nodes & Value Migration [MQLSoftware]", shorttitle="MQLSoftware - Volume Nodes & Value Migration", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500, max_polylines_count=10)

color NS_WHITE = color.rgb(225, 230, 240)
color NS_LBL   = color.rgb(170, 178, 195)
color NS_SEC   = color.rgb( 90,  98, 115)
color NS_BG    = color.new(color.rgb(  8, 11, 18),  4)
color NS_ROW   = color.new(color.rgb( 16, 20, 30),  6)
color NS_INK   = color.rgb( 10,  14,  22)

color VN_BODY_DEF = #A78BFA  // profile body — amethyst
color VN_POC_DEF  = #E8DEFF  // POC — near-white violet
color VN_ACC_DEF  = #FFAF14  // accepted — house amber token
color VN_REJ_DEF  = #FF4669  // rejected — house rose token

int BIN_CAP = 96

var string GRP_W  = "◆ Profile Window"
var string GRP_D  = "◆ Resolution & Distribution"
var string GRP_N  = "◆ Volume Nodes"
var string GRP_R  = "◆ Rendering"
var string GRP_ST = "◆ Statistics & Panel"

string anchorMode = input.string("Auto", "Anchor Period", group = GRP_W, options = ["Auto", "Day", "Week", "Month", "Quarter"], tooltip = "Each profile covers one anchor window. Auto picks Day for charts up to 30 minutes, Week for slower intraday charts, Month for Daily charts and Year above that. A manual pick at or below the chart timeframe escalates to the next valid period automatically.")
int keepProfiles  = input.int(3, "Committed Profiles to Keep", group = GRP_W, minval = 1, maxval = 4, tooltip = "How many completed windows keep their histogram drawn on the chart. Statistics and base rates always use the full loaded history.")

string detail = input.string("Balanced", "Profile Detail", group = GRP_D, options = ["Coarse", "Balanced", "Fine"], tooltip = "Sets the TARGET resolution, not a bin count. Bin height is derived from ATR at the window anchor — Coarse 0.50 ATR, Balanced 0.25 ATR, Fine 0.125 ATR per bin — so the number of bins follows the window's range-to-ATR ratio and adapts per symbol and timeframe. If a window's range outgrows the internal cap, bins merge 2:1 and the height doubles.")
int atrLen    = input.int(14, "ATR Length", group = GRP_D, minval = 5, maxval = 50, tooltip = "ATR lookback used to derive the bin height at each window anchor and to express POC migration distance.")
int vaPct     = input.int(70, "Value Area %", group = GRP_D, minval = 50, maxval = 90, tooltip = "Share of the window's volume the Value Area encloses. Built by greedy expansion from the POC bin, one bin at a time toward the heavier side.")

bool trackNodes = input.bool(true, "Track POC / HVN as Nodes", group = GRP_N, tooltip = "When a window commits, its POC and the strongest HVNs arm as horizontal levels. Every return is then tracked on confirmed bars: armed → accepted / rejected. Unresolved nodes expire when the next window commits.")
int acceptN     = input.int(2, "Acceptance Closes", group = GRP_N, minval = 1, maxval = 6, tooltip = "Confirmed closes inside the node zone (node center ± half an ATR, never thinner than one bin) required to call a retest ACCEPTED. A probe through the node center that closes outside the zone, or an entry that leaves before the required closes, is REJECTED. Edge grazes resolve nothing.")
int hvnMax      = input.int(2, "HVN Nodes per Window", group = GRP_N, minval = 0, maxval = 3, tooltip = "How many High Volume Nodes arm per committed window, besides the POC. An HVN is a local peak of the profile holding at least half of the POC volume.")
bool showLvn    = input.bool(true, "Thin Zones (LVN)", group = GRP_N, tooltip = "Shades the committed window's Thin Zones (LVN) — contiguous runs of bins holding 20% or less of the average bin volume. Context only: no state machine, no alerts.")
int marksKeep   = input.int(12, "Resolved Marks to Keep", group = GRP_N, minval = 4, maxval = 24, tooltip = "How many resolved ✓ / ✕ node marks (and their recolored level lines) stay on the chart. Older marks are removed to keep dense stretches readable; base-rate statistics are not affected.")

bool showProf  = input.bool(true, "Committed Profiles", group = GRP_R, tooltip = "Draws the final histogram of each committed window, with the Value Area shaded behind it.")
bool showLive  = input.bool(true, "Live Developing Profile", group = GRP_R, tooltip = "Histogram of the current, still-forming window. Redraws as the window grows — visual context, not a signal.")
int profWidth  = input.int(30, "Profile Width (% of window)", group = GRP_R, minval = 10, maxval = 60, tooltip = "Horizontal footprint of the histogram as a share of its window's bar count.")
bool showDev   = input.bool(true, "Developing POC / Value Area", group = GRP_R, tooltip = "Draws the developing POC step-trail and the developing Value Area band for the ACTIVE window, recomputed on every confirmed bar. Committed windows keep their final POC / VAH / VAL lines instead, so history stays clean.")
bool showMig   = input.bool(true, "POC Migration Links", group = GRP_R, tooltip = "Dotted link and distance label between the final POCs of consecutive windows.")
bool glowOn    = input.bool(true, "Glow Effects", group = GRP_R, tooltip = "Soft underglow beneath POC and node lines. Purely cosmetic.")
color colBody  = input.color(VN_BODY_DEF, "Profile", group = GRP_R, inline = "c1", tooltip = "Profile body — bin brightness follows volume share.")
color colPoc   = input.color(VN_POC_DEF, "POC", group = GRP_R, inline = "c1", tooltip = "Point of Control and its migration trail.")
color colAcc   = input.color(VN_ACC_DEF, "Accepted", group = GRP_R, inline = "c2", tooltip = "Node retest resolved as accepted.")
color colRej   = input.color(VN_REJ_DEF, "Rejected", group = GRP_R, inline = "c2", tooltip = "Node retest resolved as rejected.")

bool showPanel   = input.bool(true, "Statistics Panel", group = GRP_ST, tooltip = "Window status, developing value, node states and the measured base rates.")
string panelPos  = input.string("Top Right", "Position", group = GRP_ST, options = ["Top Right", "Top Left", "Bottom Right", "Bottom Left"], tooltip = "Corner of the chart the panel is pinned to.")
string panelSize = input.string("Small", "Text Size", group = GRP_ST, options = ["Tiny", "Small", "Normal"], tooltip = "Panel text size.")

int CHART_SEC = timeframe.in_seconds()
string anchorPick = anchorMode == "Auto" ? (timeframe.isintraday ? (CHART_SEC <= 1800 ? "D" : "W") : timeframe.isdaily ? "M" : "12M") : anchorMode == "Day" ? "D" : anchorMode == "Week" ? "W" : anchorMode == "Month" ? "M" : "3M"
string ANCHOR = anchorPick
if ANCHOR == "D" and timeframe.in_seconds("D") <= CHART_SEC
    ANCHOR := "W"
if ANCHOR == "W" and timeframe.in_seconds("W") <= CHART_SEC
    ANCHOR := "M"
if ANCHOR == "M" and timeframe.in_seconds("M") <= CHART_SEC
    ANCHOR := "3M"
if ANCHOR == "3M" and timeframe.in_seconds("3M") <= CHART_SEC
    ANCHOR := "12M"
string anchName = ANCHOR == "D" ? "Daily" : ANCHOR == "W" ? "Weekly" : ANCHOR == "M" ? "Monthly" : ANCHOR == "3M" ? "Quarterly" : "Yearly"
bool newWindow = timeframe.change(ANCHOR)

f_px(float v) =>
    na(v) ? "—" : str.tostring(v, format.mintick)

f_rate(int c, int n, int minN) =>
    n >= minN ? str.tostring(100.0 * c / n, "#") + "%" : "collecting"

f_trimBoxes(array<box> a, int maxN) =>
    while a.size() > maxN
        box.delete(a.shift())

f_trimLines(array<line> a, int maxN) =>
    while a.size() > maxN
        line.delete(a.shift())

f_trimLabels(array<label> a, int maxN) =>
    while a.size() > maxN
        label.delete(a.shift())

f_triCdf(float L, float H, float C, float x) =>
    float r = H - L
    float out = na
    if r <= 0
        out := x > H ? 1.0 : 0.0
    else if x <= L
        out := 0.0
    else if x >= H
        out := 1.0
    else if x <= C
        out := (x - L) * (x - L) / (r * (C - L))
    else
        out := 1.0 - (H - x) * (H - x) / (r * (H - C))
    out

f_stateTxt(int st) =>
    st == 2 ? "testing" : st == 3 ? "accepted" : st == 4 ? "rejected" : "armed"

type VNode
    string kind
    float  lvl
    float  zLo
    float  zHi
    int    state
    int    streak
    line   ln
    line   glow
    label  tag

var array<float> binVol = array.new<float>()
var float gridLo = na
var float binH   = na
var int   wStart = na
var float devPoc = na
var float devVah = na
var float devVal = na

var float priorPoc = na            // final POC of the previous committed window
var bool  fRevisit = false
var int   cRevisit = 0
var int   nRevisit = 0
var float lastPocPrice = na        // for migration links
var int   lastPocBar   = na
var bool  sawVol = false
var bool  everCommitted = false

var int cPocT = 0
var int cPocA = 0
var int cHvnT = 0
var int cHvnR = 0

var array<VNode> liveNodes  = array.new<VNode>()
var array<box>   profBoxes  = array.new<box>()
var array<int>   profCounts = array.new<int>()
var array<box>   lvnBoxes   = array.new<box>()
var array<box>   liveBoxes  = array.new<box>()
var array<line>  winLines   = array.new<line>()
var array<label> winLabels  = array.new<label>()
var array<line>  nodeLines  = array.new<line>()
var array<label> nodeLabels = array.new<label>()
var label tagVah = label(na)
var label tagVal = label(na)
var label tagPoc = label(na)

var array<chart.point> trailPts = array.new<chart.point>()
var float lastTrailPoc = na
var polyline trailPl = na
var box devVaBx = box(na)

var string TT_NODE = "Armed when its window committed. Returns are tracked on confirmed bars only: " + str.tostring(acceptN) + " confirmed close(s) inside the zone (center ± half an ATR, never thinner than one bin) = accepted · a probe through the node CENTER that closes outside the zone, or an entry that leaves before that, = rejected. A graze of the zone edge that neither trades the center nor closes inside resolves nothing. Unresolved nodes expire when the next window commits."

float atr = ta.atr(atrLen)
float detailK = detail == "Coarse" ? 0.5 : detail == "Balanced" ? 0.25 : 0.125

bool committedNow = false
bool accNow       = false
bool rejNow       = false
bool revisitNow   = false
string accTxt     = ""
string rejTxt     = ""

if newWindow and not na(wStart) and binVol.size() > 0 and not na(devPoc)
    committedNow  := true
    everCommitted := true
    int nB   = binVol.size()
    int wEnd = bar_index - 1

    int   pocI = 0
    float vMax = 0.0
    float vSum = 0.0
    int   nnz  = 0
    int i0 = 0
    while i0 < nB
        float v = binVol.get(i0)
        vSum += v
        if v > 0
            nnz += 1
        if v > vMax
            vMax := v
            pocI := i0
        i0 += 1

    if not na(priorPoc)
        nRevisit += 1
        if fRevisit
            cRevisit += 1

    float aRef = nz(atr, binH * 4)
    if showMig and not na(lastPocPrice) and aRef > 0
        string mGl  = devPoc > lastPocPrice ? "▲" : devPoc < lastPocPrice ? "▼" : "◆"
        string mTxt = "POC " + mGl + " " + str.tostring(math.abs(devPoc - lastPocPrice) / aRef, "#.##") + " ATR · " + str.tostring(100.0 * math.abs(devPoc - lastPocPrice) / lastPocPrice, "#.##") + "% vs prior"
        winLines.push(line.new(lastPocBar, lastPocPrice, wEnd, devPoc, color = color.new(colPoc, 50), style = line.style_dotted))
        winLabels.push(label.new(wEnd, (devPoc + lastPocPrice) / 2, mTxt, style = label.style_none, color = color.new(colPoc, 100), textcolor = color.new(colPoc, 30), size = size.small, tooltip = "How far the Point of Control migrated between the previous committed window and this one, in ATR units. Value building higher or lower is the window-to-window read of this profile."))

    int winBars = wEnd - wStart
    int rowSpan = math.max(4, int(math.round(winBars * profWidth / 100.0)))
    if showProf and vMax > 0
        int rows = 0
        profBoxes.push(box.new(wStart, devVah, wEnd, devVal, border_color = color.new(colBody, 100), bgcolor = color.new(colBody, 95)))
        rows += 1
        int i1 = 0
        while i1 < nB
            float v = binVol.get(i1)
            if v > 0
                int rowLen = math.max(1, int(math.round(rowSpan * v / vMax)))
                float yLo  = gridLo + i1 * binH
                bool isPoc = i1 == pocI
                int  rowTr = int(math.round(86.0 - 62.0 * v / vMax))
                profBoxes.push(box.new(wStart, yLo + binH, wStart + rowLen, yLo, border_color = color.new(colBody, 100), bgcolor = color.new(isPoc ? colPoc : colBody, isPoc ? 20 : rowTr)))
                rows += 1
            i1 += 1
        profCounts.push(rows)
        while profCounts.size() > keepProfiles
            int k0 = profCounts.shift()
            int j0 = 0
            while j0 < k0
                box.delete(profBoxes.shift())
                j0 += 1

    label.delete(tagVah)
    label.delete(tagVal)
    label.delete(tagPoc)
    winLines.push(line.new(wStart, devPoc, wEnd, devPoc, color = color.new(colPoc, 15), width = 2))
    if glowOn
        winLines.push(line.new(wStart, devPoc, wEnd, devPoc, color = color.new(colPoc, 86), width = 6))
    winLines.push(line.new(wStart, devVah, wEnd, devVah, color = color.new(colBody, 45), style = line.style_dashed))
    winLines.push(line.new(wStart, devVal, wEnd, devVal, color = color.new(colBody, 45), style = line.style_dashed))
    tagVah := label.new(wEnd, devVah, "VAH · Value Area High", style = label.style_label_right, color = color.new(colBody, 100), textcolor = color.new(colBody, 35), size = size.tiny, tooltip = "Upper edge of the price band holding " + str.tostring(vaPct) + "% of the committed window's volume.")
    tagVal := label.new(wEnd, devVal, "VAL · Value Area Low", style = label.style_label_right, color = color.new(colBody, 100), textcolor = color.new(colBody, 35), size = size.tiny, tooltip = "Lower edge of the price band holding " + str.tostring(vaPct) + "% of the committed window's volume.")
    if not trackNodes
        tagPoc := label.new(wEnd, devPoc, "POC · High Volume Node", style = label.style_label_right, color = color.new(colPoc, 100), textcolor = color.new(colPoc, 25), size = size.tiny, tooltip = "Point of Control — the single price bin that traded the most volume in the committed window.")

    if showLvn and nnz > 0
        float thrLvn = 0.2 * vSum / nnz
        int runS   = -1
        int bestS1 = -1
        int bestL1 = 0
        int bestS2 = -1
        int bestL2 = 0
        int i2 = 1
        while i2 < nB - 1
            bool thin = binVol.get(i2) <= thrLvn
            if thin and runS < 0
                runS := i2
            if runS >= 0 and (not thin or i2 == nB - 2)
                int runE = thin ? i2 : i2 - 1
                int rl = runE - runS + 1
                if rl > bestL1
                    bestS2 := bestS1
                    bestL2 := bestL1
                    bestS1 := runS
                    bestL1 := rl
                else if rl > bestL2
                    bestS2 := runS
                    bestL2 := rl
                runS := -1
            i2 += 1
        if bestL1 > 1
            lvnBoxes.push(box.new(wStart, gridLo + (bestS1 + bestL1) * binH, wEnd, gridLo + bestS1 * binH, border_color = color.new(colBody, 88), border_style = line.style_dashed, bgcolor = color.new(colBody, 96), text = "LVN · Thin Zone", text_size = size.tiny, text_color = color.new(colBody, 55), text_halign = text.align_left))
        if bestL2 > 1
            lvnBoxes.push(box.new(wStart, gridLo + (bestS2 + bestL2) * binH, wEnd, gridLo + bestS2 * binH, border_color = color.new(colBody, 88), border_style = line.style_dashed, bgcolor = color.new(colBody, 96), text = "LVN · Thin Zone", text_size = size.tiny, text_color = color.new(colBody, 55), text_halign = text.align_left))
        f_trimBoxes(lvnBoxes, keepProfiles * 2)

    while liveNodes.size() > 0
        VNode nd0 = liveNodes.pop()
        line l0 = nd0.ln
        line g0 = nd0.glow
        if not na(l0)
            l0.set_style(line.style_dotted)
            l0.set_color(color.new(colBody, 80))
            nodeLines.push(l0)
        if not na(g0)
            g0.set_color(color.new(colBody, 96))
            nodeLines.push(g0)
        label.delete(nd0.tag)

    if trackNodes
        float zHalf = math.max(binH, 0.5 * aRef)
        line pLn = line.new(bar_index, devPoc, bar_index + 1, devPoc, color = color.new(colPoc, 20), width = 2)
        line pGl = glowOn ? line.new(bar_index, devPoc, bar_index + 1, devPoc, color = color.new(colPoc, 84

Показано первые 50% кода (символов: 23409)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
2 340,90₽ ≈ $28.61