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

Liquidity Gravity Map

indicator liquidity gravity map for tradingview.pine
Вы автор или правообладатель?

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

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

О программе

Liquidity Gravity Map — это индикатор для TradingView, написанный на Pine Script v6. Он отображает на графике зоны ликвидности, формируемые на основе подтверждённых свинг-хаев и свинг-лоу, а также зон стоп-хант (длинные хвосты свечей за предыдущими максимумами или минимумами). Каждая зона получает комплексную оценку по нескольким факторам.

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

Параметры пользователя позволяют настроить период обзора, чувствительность зон, лимит памяти, скорость затухания оценок, тип VWAP-сессии, цветовую тему и видимость полос и меток.

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

НастройкаОписание
lookback_period Период обзора — Количество баров, используемых для определения устаревших и неактивных зон.
zone_sensitivity Чувствительность зон — Параметр, влияющий на ширину зон и допуск при слиянии близких уровней.
max_zones Максимум зон — Максимальное количество зон, хранимых в памяти индикатора.
max_visible_zones Максимум видимых зон — Максимальное количество зон, отображаемых на графике одновременно.
score_decay_rate Скорость затухания оценки — Скорость экспоненциального уменьшения оценки у неприкасаемых зон со временем.
vwap_session_type Тип сессии VWAP — Тип сессии для расчёта VWAP: RTH, день, неделя или месяц.
rth_session Сессия RTH — Временной диапазон обычной торговой сессии для расчёта VWAP в режиме RTH.
show_vwap_bands Показывать полосы VWAP — Включает или отключает отображение линий VWAP и полос стандартных отклонений.
color_theme Цветовая тема — Цветовая схема отображения зон: Classic, Neon или Monochrome.
show_labels Показывать метки зон — Включает или отключает отображение текстовых меток на зонах.
Получить полный код

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

indicator("Liquidity Gravity Map", shorttitle="LGM", overlay=true, max_boxes_count=300, max_labels_count=300)

groupCore  = "Core"
groupVWAP  = "VWAP Acceptance"
groupVis   = "Visuals"

lookback_period   = input.int(120, "Lookback Period", minval=30, maxval=500, group=groupCore)
zone_sensitivity  = input.float(4.0, "Zone Sensitivity", minval=0.5, maxval=10.0, step=0.25, group=groupCore)
max_zones         = input.int(40, "Max Zones (Memory Cap)", minval=10, maxval=150, group=groupCore)
max_visible_zones = input.int(4, "Max Visible Zones", minval=1, maxval=20, group=groupCore)
score_decay_rate  = input.float(0.010, "Score Decay Rate", minval=0.001, maxval=0.050, step=0.001, group=groupCore)

vwap_session_type = input.string("Day", "VWAP Session Type", options=["RTH", "Day", "Week", "Month"], group=groupVWAP)
rth_session       = input.session("0930-1600", "RTH Session", group=groupVWAP)
show_vwap_bands   = input.bool(true, "Show VWAP Bands", group=groupVWAP)

color_theme       = input.string("Classic", "Color Theme", options=["Classic", "Neon", "Monochrome"], group=groupVis)
show_labels       = input.bool(true, "Show Zone Labels", group=groupVis)

var zonePrice      = array.new_float()
var zoneTop        = array.new_float()
var zoneBottom     = array.new_float()
var zoneDir        = array.new_int()      //  1 = bullish support, -1 = bearish resistance
var zoneBirthBar   = array.new_int()
var zoneLastTouch  = array.new_int()
var zoneRevisits   = array.new_int()

var zoneStructSum  = array.new_float()    // structural event intensity accumulator
var zoneStructObs  = array.new_int()      // structural observations
var zoneWickSum    = array.new_float()    // relevant wick ratio accumulator
var zoneWickObs    = array.new_int()      // wick observations
var zoneAbsorbSum  = array.new_float()    // absorption / defended retest accumulator
var zoneBreakSum   = array.new_float()    // clean break accumulator
var zoneScore      = array.new_float()    // live composite score 0-100
var zoneProxScore  = array.new_float()    // live proximity score 0-100

var zoneBoxes      = array.new_box()
var zoneLabels     = array.new_label()

var recentHighPivots = array.new_float()
var recentLowPivots  = array.new_float()

f_clamp(float x, float lo, float hi) =>
    math.max(lo, math.min(hi, x))

f_safe_div(float a, float b) =>
    b != 0.0 ? a / b : 0.0

f_zone_halfwidth(float atrv) =>

    math.max(syminfo.mintick * (2.0 + zone_sensitivity * 2.0), atrv * (0.035 + zone_sensitivity * 0.012))

f_gradient(bool bull, float score, bool border) =>
    float t = f_clamp(score / 100.0, 0.0, 1.0)

    color cool = na
    color warm = na

    if color_theme == "Classic"
        cool := bull ? color.rgb(32, 166, 179) : color.rgb(111, 89, 224)
        warm := bull ? color.rgb(255, 193, 7) : color.rgb(255, 82, 82)
    else if color_theme == "Neon"
        cool := bull ? color.rgb(0, 255, 170) : color.rgb(180, 90, 255)
        warm := bull ? color.rgb(255, 235, 59) : color.rgb(255, 23, 68)
    else
        cool := bull ? color.rgb(115, 145, 155) : color.rgb(125, 125, 140)
        warm := bull ? color.rgb(235, 235, 235) : color.rgb(245, 210, 210)

    int r = int(math.round(color.r(cool) + (color.r(warm) - color.r(cool)) * t))
    int g = int(math.round(color.g(cool) + (color.g(warm) - color.g(cool)) * t))
    int b = int(math.round(color.b(cool) + (color.b(warm) - color.b(cool)) * t))

    int alpha = border ? int(math.round(40.0 - 30.0 * t)) : int(math.round(88.0 - 58.0 * t))
    color.rgb(r, g, b, f_clamp(alpha, 0, 100))

f_delete_zone_objects(int idx) =>
    box bx = array.get(zoneBoxes, idx)
    label lb = array.get(zoneLabels, idx)
    if not na(bx)
        box.delete(bx)
    if not na(lb)
        label.delete(lb)
    array.set(zoneBoxes, idx, na)
    array.set(zoneLabels, idx, na)

f_remove_zone(int idx) =>
    f_delete_zone_objects(idx)
    array.remove(zonePrice, idx)
    array.remove(zoneTop, idx)
    array.remove(zoneBottom, idx)
    array.remove(zoneDir, idx)
    array.remove(zoneBirthBar, idx)
    array.remove(zoneLastTouch, idx)
    array.remove(zoneRevisits, idx)
    array.remove(zoneStructSum, idx)
    array.remove(zoneStructObs, idx)
    array.remove(zoneWickSum, idx)
    array.remove(zoneWickObs, idx)
    array.remove(zoneAbsorbSum, idx)
    array.remove(zoneBreakSum, idx)
    array.remove(zoneScore, idx)
    array.remove(zoneProxScore, idx)
    array.remove(zoneBoxes, idx)
    array.remove(zoneLabels, idx)

f_prune_one() =>
    if array.size(zonePrice) > 0
        int worstIdx = 0
        float worstMetric = 1e10
        for i = 0 to array.size(zonePrice) - 1

            float metric = array.get(zoneScore, i) - (bar_index - array.get(zoneBirthBar, i)) * 0.02
            if metric < worstMetric
                worstMetric := metric
                worstIdx := i
        f_remove_zone(worstIdx)

f_add_or_merge_zone(float price, int dir, int eventBar, float halfWidth, float structBoost, float wickBoost) =>
    int found = -1
    float mergeTol = math.max(halfWidth * 1.25, syminfo.mintick * zone_sensitivity * 2.0)

    if array.size(zonePrice) > 0
        for i = 0 to array.size(zonePrice) - 1
            if array.get(zoneDir, i) == dir and math.abs(array.get(zonePrice, i) - price) <= mergeTol
                found := i
                break

    if found != -1
        float oldPrice = array.get(zonePrice, found)
        float oldTop = array.get(zoneTop, found)
        float oldBot = array.get(zoneBottom, found)
        float oldStructSum = array.get(zoneStructSum, found)

        float weightOld = math.max(oldStructSum, 1.0)
        float weightNew = math.max(structBoost, 1.0)
        float mergedPrice = (oldPrice * weightOld + price * weightNew) / (weightOld + weightNew)
        float mergedHalf = math.max((oldTop - oldBot) * 0.5, halfWidth)

        array.set(zonePrice, found, mergedPrice)
        array.set(zoneTop, found, mergedPrice + mergedHalf)
        array.set(zoneBottom, found, mergedPrice - mergedHalf)
        array.set(zoneBirthBar, found, math.min(array.get(zoneBirthBar, found), eventBar))
        array.set(zoneStructSum, found, array.get(zoneStructSum, found) + structBoost)
        array.set(zoneStructObs, found, array.get(zoneStructObs, found) + 1)

        if wickBoost > 0
            array.set(zoneWickSum, found, array.get(zoneWickSum, found) + wickBoost)
            array.set(zoneWickObs, found, array.get(zoneWickObs, found) + 1)
    else
        if array.size(zonePrice) >= max_zones
            f_prune_one()

        array.push(zonePrice, price)
        array.push(zoneTop, price + halfWidth)
        array.push(zoneBottom, price - halfWidth)
        array.push(zoneDir, dir)
        array.push(zoneBirthBar, eventBar)
        array.push(zoneLastTouch, na)
        array.push(zoneRevisits, 0)

        array.push(zoneStructSum, structBoost)
        array.push(zoneStructObs, 1)
        array.push(zoneWickSum, math.max(wickBoost, 0.0))
        array.push(zoneWickObs, wickBoost > 0 ? 1 : 0)
        array.push(zoneAbsorbSum, 0.0)
        array.push(zoneBreakSum, 0.0)
        array.push(zoneScore, 0.0)
        array.push(zoneProxScore, 0.0)

        array.push(zoneBoxes, na)
        array.push(zoneLabels, na)

float atrv = ta.atr(14)
float volSma = ta.sma(volume, 20)
float barRange = math.max(high - low, syminfo.mintick)
float bodyRatio = math.abs(close - open) / barRange
float upperWickRatio = (high - math.max(open, close)) / barRange
float lowerWickRatio = (math.min(open, close) - low) / barRange

int swing_len = int(math.round(math.max(2.0, zone_sensitivity + 1.0)))
int pivot_memory = 20
int sweep_window = int(math.max(5.0, math.round(lookback_period * 0.25)))

var float cumPV  = 0.0
var float cumV   = 0.0
var float cumPV2 = 0.0
var float sessVWAP = na
var float sessSD   = na

var int barsFarBelow = 0
var int barsBelow1   = 0
var int barsMid      = 0
var int barsAbove1   = 0
var int barsFarAbove = 0
var int sessionBars  = 0

var int bullReclaims = 0
var int bearRejects  = 0

bool inRth = not na(time(timeframe.period, rth_session))
bool prevInRth = bar_index > 0 ? inRth[1] : false
bool vwapActive = vwap_session_type == "RTH" ? inRth : true
bool newAnchor =
     vwap_session_type == "RTH"  ? (inRth and not prevInRth) :
     vwap_session_type == "Week" ? timeframe.change("W") :
     vwap_session_type == "Month"? timeframe.change("M") :
                                   timeframe.change("D")

if barstate.isconfirmed
    if newAnchor and vwapActive
        cumPV := hlc3 * volume
        cumV := volume
        cumPV2 := hlc3 * hlc3 * volume

        barsFarBelow := 0
        barsBelow1 := 0
        barsMid := 0
        barsAbove1 := 0
        barsFarAbove := 0
        sessionBars := 0
        bullReclaims := 0
        bearRejects := 0
    else if vwapActive
        cumPV += hlc3 * volume
        cumV += volume
        cumPV2 += hlc3 * hlc3 * volume

    if vwapActive and cumV > 0
        sessVWAP := cumPV / cumV
        float variance = math.max(cumPV2 / cumV - sessVWAP * sessVWAP, 0.0)
        sessSD := math.sqrt(variance)

        sessionBars += 1

        float zClose = sessSD > 0 ? (close - sessVWAP) / sessSD : 0.0

        if zClose <= -2.0
            barsFarBelow += 1
        else if zClose < -1.0
            barsBelow1 += 1
        else if zClose <= 1.0
            barsMid += 1
        else if zClose < 2.0
            barsAbove1 += 1
        else
            barsFarAbove += 1

        bool bullReclaimEvent = not na(sessVWAP[1]) and close > sessVWAP and close[1] <= sessVWAP[1]

        bool bearRejectEvent = close < sessVWAP and high >= sessVWAP

        if bullReclaimEvent
            bullReclaims += 1
        if bearRejectEvent
            bearRejects += 1

if barstate.isconfirmed

    float ph = ta.pivothigh(high, swing_len, swing_len)
    if not na(ph)
        float atrAtPivot = nz(atrv[swing_len], atrv)
        float tol = math.max(syminfo.mintick * zone_sensitivity * 2.0, atrAtPivot * zone_sensitivity * 0.08)
        int eqCount = 0

        if array.size(recentHighPivots) > 0
            int startIdx = math.max(0, array.size(recentHighPivots) - pivot_memory)
            for i = startIdx to array.size(recentHighPivots) - 1
                if math.abs(array.get(recentHighPivots, i) - ph) <= tol
                    eqCount += 1

        float pivotRange = math.max(high[swing_len] - low[swing_len], syminfo.mintick)
        float pivotUpperWick = high[swing_len] - math.max(open[swing_len], close[swing_len])
        float pivotWickRatio = pivotUpperWick / pivotRange

        float structBoost = eqCount > 0 ? math.min(95.0, 60.0 + eqCount * 12.0) : 52.0
        f_add_or_merge_zone(ph, -1, bar_index - swing_len, f_zone_halfwidth(atrAtPivot), structBoost, pivotWickRatio)

        array.push(recentHighPivots, ph)
        if array.size(recentHighPivots) > pivot_memory
            array.shift(recentHighPivots)

    float pl = ta.pivotlow(low, swing_len, swing_len)
    if not na(pl)
        float atrAtPivot = nz(atrv[swing_len], atrv)
        float tol = math.max(syminfo.mintick * zone_sensitivity * 2.0, atrAtPivot * zone_sensitivity * 0.08)
        int eqCount = 0

        if array.size(recentLowPivots) > 0
            int startIdx = math.max(0, array.size

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

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

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

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

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

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

Стоимость полного кода
1 619,80₽ ≈ $19.80