Also Like

IZAKI 0.618 TRADING ZONE
Advertisement

Adaptive Support and Resistance Zones [BigBeluga]

Adaptive Support and Resistance Zones: A Cutting-Edge Technical Analysis Tool

The Adaptive Support and Resistance Zones [BigBeluga] is a revolutionary technical analysis tool designed to identify, manage, and visualize key supply and demand areas in the financial markets. This innovative script employs volatility-adjusted logic (ATR) to ensure that only the most significant structural levels are maintained, providing traders with a clearer picture of where institutional interest lies.

Key Concepts and Features

The Adaptive Support and Resistance Zones [BigBeluga] is built around several key concepts, including:

  • Volatility-Aware Detection: This feature uses ATR-based filtering to qualify pivot points, ensuring that only significant price rejection is considered.
  • Smart Level Merging: This function automatically consolidates levels that are too close to one another, preventing "line spaghetti" and identifying high-confluence zones.
  • Dynamic Zone Rendering: This feature visualizes support and resistance as shaded boxes, with the width of these zones adapting to market volatility.
  • Real-Time Breakout Tracking: The indicator monitors price action in real-time, detecting when a level is definitively breached and switching its status from "Active" to "Broken".

How it Works: An In-Depth Look

The Adaptive Support and Resistance Zones [BigBeluga] works by scanning for pivot highs and lows based on a user-defined pivot length. The strength filter applies a "Min ATR Strength" check to ensure that only significant pivots are considered. The script then merges levels that are too close to one another, effectively treating the existing zone as the dominant area of interest.

The indicator also features a dedicated on-screen table, known as the S/R Dashboard, which provides a birds-eye view of the current structural state. This dashboard displays the exact price of the closest active levels, the direction of the most recent volatility-confirmed breakout, and the number of structural levels being monitored by the system.

Key Features and Benefits

The Adaptive Support and Resistance Zones [BigBeluga] offers a range of key features and benefits, including:

  • ATR-Based Zone Width: Zones expand and contract based on market volatility, ensuring that stop-loss or entry buffers are mathematically sound.
  • Price Labels: Optional labels at the end of active lines provide the exact price for quick order entry.
  • Customizable Break Sensitivity: Traders can define how much "daylight" price needs to show above or below a level before a breakout is confirmed.
  • Historical Record: The indicator retains a specific number of recently broken levels to identify long-term historical confluence.

Using the Adaptive Support and Resistance Zones

The Adaptive Support and Resistance Zones [BigBeluga] can be used in a variety of ways, including:

  • Trading the Rejection: Look for price to enter a shaded Support or Resistance Zone, and wait for a reversal candle within the zone for a high-probability entry back toward the mean.
  • Trading the Breakout: When the "< Break" label appears, it confirms that price has closed beyond the zone with enough momentum to overcome the "Break Sensitivity" threshold.
  • The S/R Flip: Monitor "Broken" (dotted) levels, and look for price to return to a dotted Resistance line and treat it as Support, confirming a structural shift in the market.

Conclusion

The Adaptive Support and Resistance Zones [BigBeluga] is a powerful technical analysis tool that transforms raw price action into an organized, data-driven roadmap. By automating the detection and management of key levels, and accounting for the ever-changing nature of market volatility, this indicator allows traders to focus on execution rather than manual charting. Whether you're a seasoned trader or just starting out, the Adaptive Support and Resistance Zones [BigBeluga] is an essential tool for anyone looking to improve their trading performance.

Source Code

PINE SCRIPT
// This work is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International  
// https://creativecommons.org/licenses/by-nc-sa/4.0/
// © BigBeluga 

//@version=6
indicator("Adaptive S/R Zones [BigBeluga]", shorttitle="Adaptive S/R [BigBeluga]", overlay=true, max_lines_count=500, max_labels_count=200, max_boxes_count=200)

// INPUTS ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{

var grpSwing = "Swing Detection"
pivotLen     = input.int(5,   "Pivot Length",      minval=2, maxval=50,   group=grpSwing, tooltip="The number of bars on each side of a high or low to confirm a pivot point.")
minStrength  = input.float(0.1, "Min ATR Strength", minval=0.0, maxval=5.0, step=0.05, group=grpSwing, tooltip="Minimum distance required between the pivot and its neighbors.")
maxAgeBars   = input.int(300, "Max Level Age (bars)", minval=20, maxval=2000, group=grpSwing, tooltip="Maximum bars a level exists before removal. Also used to calculate longevity scaling.")

var grpLevels = "Levels"
showSupport  = input.bool(true,  "Show Support Levels",    group=grpLevels)
showResist   = input.bool(true,  "Show Resistance Levels", group=grpLevels)
maxLevels    = input.int(5,      "Max Active Levels Each", minval=1, maxval=20, group=grpLevels)
mergeThresh  = input.float(0.5,  "Merge Threshold (ATR x)", minval=0.0, maxval=3.0, step=0.05, group=grpLevels)
showZones    = input.bool(true,  "Show Level Zones",       group=grpLevels)
zoneWidth    = input.float(0.25, "Zone Width (ATR x)",     minval=0.05, maxval=2.0, step=0.05, group=grpLevels)

var grpBreak = "Breakouts"
showBroken   = input.bool(true,  "Show Broken Levels",         group=grpBreak)
breakSens    = input.float(0.1,  "Break Sensitivity (ATR x)",  minval=0.0, maxval=2.0, step=0.05, group=grpBreak)
showBreakLbl = input.bool(true,  "Show Break Labels",          group=grpBreak)
maxBroken    = input.int(4,      "Max Broken Levels Shown",    minval=0, maxval=20, group=grpBreak)

var grpVis = "Visuals"
supColor     = input.color(color.new(#22bac5, 0),  "Support Color",         group=grpVis)
resColor     = input.color(color.new(#ff6f43, 0),  "Resistance Color",      group=grpVis)
brokenColor  = input.color(color.new(#94a3b8, 0),  "Broken Level Color",    group=grpVis)
lineWidth    = input.int(2, "Base Line Width",     minval=1, maxval=5,      group=grpVis, tooltip="Used when Longevity Scaling is OFF.")

//  NEW LONGEVITY INPUTS 
useDynamicWidth = input.bool(true, "Enable Longevity Width", group=grpVis, tooltip="When enabled, older levels become thicker over time.")
maxLineWidth    = input.int(7, "Max Longevity Width", minval=1, maxval=10, group=grpVis, tooltip="The maximum thickness an old level can reach.")

showDash     = input.bool(true, "Show Dashboard",   group=grpVis)
showPriceLbl = input.bool(true, "Show Price Labels on Active Levels", group=grpVis)

var grpDash = "Dashboard"
dashPos      = input.string("Bottom Right", "Dashboard Position", options=["Top Right","Bottom Right","Top Left","Bottom Left"], group=grpDash)

// }
// CALCULATIONS――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{

type SRLevel
    float  price
    int    barStart
    int    levelType
    bool   active
    bool   broken
    int    breakBar
    bool   retested
    line   mainLine
    box    zoneBox
    label  breakLabel
    label  priceLabel

var array activeLevels = array.new()
var array brokenLevels = array.new()
var string         lastBreakDir = "—"
var int            lastBreakBar = na

atrVal  = ta.atr(14)
atrSafe = na(atrVal) or atrVal == 0 ? syminfo.mintick * 10 : atrVal

ph = ta.pivothigh(high, pivotLen, pivotLen)
pl = ta.pivotlow(low,   pivotLen, pivotLen)

f_isTooClose(_price, _type) =>
    bool tooClose = false
    int  sz = array.size(activeLevels)
    if sz > 0
        for i = 0 to sz - 1
            lvl = array.get(activeLevels, i)
            if lvl.levelType == _type and lvl.active
                if math.abs(lvl.price - _price) < mergeThresh * atrSafe
                    tooClose := true
                    break
    tooClose

f_addLevel(_price, _type, _barIdx) =>
    if not f_isTooClose(_price, _type)
        int sz  = array.size(activeLevels)
        int cnt = 0
        if sz > 0
            for i = 0 to sz - 1
                lvl = array.get(activeLevels, i)
                if lvl.levelType == _type and lvl.active
                    cnt += 1

        if cnt < maxLevels
            _baseColor = _type == 1 ? resColor : supColor
            _zoneTop   = _price + zoneWidth * atrSafe * 0.5
            _zoneBot   = _price - zoneWidth * atrSafe * 0.5

            newLine = line.new(
                 x1     = _barIdx,
                 y1     = _price,
                 x2     = _barIdx + 1,
                 y2     = _price,
                 extend = extend.right,
                 color  = color.new(_baseColor, 0),
                 width  = lineWidth,
                 style  = line.style_solid
             )

            newBox = showZones ? box.new(
                 left         = _barIdx,
                 top          = _zoneTop,
                 right        = _barIdx + 1,
                 bottom       = _zoneBot,
                 border_color = color.new(_baseColor, 90),
                 bgcolor      = color.new(_baseColor, 88),
                 extend       = extend.right
             ) : na

            newPriceLbl = showPriceLbl ? label.new(
                 x         = bar_index + 20,
                 y         = _price,
                 text      = str.tostring(_price, format.mintick),
                 style     = label.style_label_center,
                 textcolor = _baseColor,
                 color     = color.new(chart.bg_color, 0),
                 size      = size.small
             ) : na

            array.push(activeLevels, SRLevel.new(
                 price      = _price,
                 barStart   = _barIdx,
                 levelType  = _type,
                 active     = true,
                 broken     = false,
                 breakBar   = na,
                 retested   = false,
                 mainLine   = newLine,
                 zoneBox    = newBox,
                 breakLabel = na,
                 priceLabel = newPriceLbl
             ))

f_pivotStrong(_price, _type) =>
    bool strong = true
    if minStrength > 0
        if _type == 1
            nearHigh = math.max(high[pivotLen - 1], high[pivotLen + 1])
            if (_price - nearHigh) < minStrength * atrSafe
                strong := false
        else
            nearLow = math.min(low[pivotLen - 1], low[pivotLen + 1])
            if (nearLow - _price) < minStrength * atrSafe
                strong := false
    strong

// Prune old levels
int pruneSize = array.size(activeLevels)
if pruneSize > 0
    for i = pruneSize - 1 to 0
        if i < array.size(activeLevels)
            lvl = array.get(activeLevels, i)
            if lvl.active and (bar_index - lvl.barStart) > maxAgeBars
                line.delete(lvl.mainLine)
                if not na(lvl.zoneBox)
                    box.delete(lvl.zoneBox)
                if not na(lvl.priceLabel)
                    label.delete(lvl.priceLabel)
                array.remove(activeLevels, i)

// Add new pivots
if not na(ph) and showResist
    if f_pivotStrong(ph, 1)
        f_addLevel(ph, 1, bar_index - pivotLen)

if not na(pl) and showSupport
    if f_pivotStrong(pl, -1)
        f_addLevel(pl, -1, bar_index - pivotLen)

// Breakout logic
int activeSize = array.size(activeLevels)
if activeSize > 0
    for i = activeSize - 1 to 0
        if i >= array.size(activeLevels)
            continue
        lvl = array.get(activeLevels, i)
        if not lvl.active
            continue

        breakBuffer = breakSens * atrSafe

        if lvl.levelType == 1 and close > lvl.price + breakBuffer
            lvl.active   := false
            lvl.broken   := true
            lvl.breakBar := bar_index
            lastBreakDir := "Bullish"
            lastBreakBar := bar_index

            if not na(lvl.priceLabel)
                label.delete(lvl.priceLabel)
                lvl.priceLabel := na

            line.set_color(lvl.mainLine,  color.new(brokenColor, 0))
            line.set_style(lvl.mainLine,  line.style_dotted)
            line.set_width(lvl.mainLine,  1)
            line.set_extend(lvl.mainLine, extend.none)
            line.set_x2(lvl.mainLine,     bar_index)

            if not na(lvl.zoneBox)
                box.set_bgcolor(lvl.zoneBox,       color.new(brokenColor, 93))
                box.set_border_color(lvl.zoneBox,  color.new(brokenColor, 100))
                box.set_extend(lvl.zoneBox,        extend.none)
                box.set_right(lvl.zoneBox,         bar_index)
                mid = math.avg(lvl.zoneBox.get_top(), lvl.zoneBox.get_bottom())
                lvl.zoneBox.set_top(mid + breakBuffer)
                lvl.zoneBox.set_bottom(mid - breakBuffer)
                
            if showBreakLbl
                lvl.breakLabel := label.new(
                     x         = bar_index,
                     y         = lvl.price,
                     text      = "< Break",
                     style     = label.style_label_left,
                     textcolor = supColor,
                     color     = color.new(#22c55e, 100),
                     size      = size.small
                 )

            if showBroken
                array.push(brokenLevels, lvl)
                if array.size(brokenLevels) > maxBroken and array.size(brokenLevels) > 0
                    old = array.shift(brokenLevels)
                    if not na(old.mainLine)
                        line.delete(old.mainLine)
                    if not na(old.zoneBox)
                        box.delete(old.zoneBox)
                    if not na(old.breakLabel)
                        label.delete(old.breakLabel)
            else
                line.delete(lvl.mainLine)
                
                if not na(lvl.zoneBox)
                    box.delete(lvl.zoneBox)

            array.remove(activeLevels, i)

        else if lvl.levelType == -1 and close < lvl.price - breakBuffer
            lvl.active   := false
            lvl.broken   := true
            lvl.breakBar := bar_index
            lastBreakDir := "Bearish"
            lastBreakBar := bar_index

            if not na(lvl.priceLabel)
                label.delete(lvl.priceLabel)
                lvl.priceLabel := na

            line.set_color(lvl.mainLine,  color.new(brokenColor, 0))
            line.set_style(lvl.mainLine,  line.style_dotted)
            line.set_width(lvl.mainLine,  1)
            line.set_extend(lvl.mainLine, extend.none)
            line.set_x2(lvl.mainLine,     bar_index)

            if not na(lvl.zoneBox)
                box.set_bgcolor(lvl.zoneBox,       color.new(brokenColor, 93))
                box.set_border_color(lvl.zoneBox,  color.new(brokenColor, 100))
                box.set_extend(lvl.zoneBox,        extend.none)
                box.set_right(lvl.zoneBox,         bar_index)
                mid = math.avg(lvl.zoneBox.get_top(), lvl.zoneBox.get_bottom())
                lvl.zoneBox.set_top(mid + breakBuffer)
                lvl.zoneBox.set_bottom(mid - breakBuffer)
                
            if showBreakLbl
                lvl.breakLabel := label.new(
                     x         = bar_index,
                     y         = lvl.price,
                     text      = "< Break",
                     style     = label.style_label_left,
                     textcolor = resColor,
                     color     = color.new(#ef4444, 100),
                     size      = size.small
                 )

            if showBroken
                array.push(brokenLevels, lvl)
                if array.size(brokenLevels) > maxBroken and array.size(brokenLevels) > 0
                    old = array.shift(brokenLevels)
                    if not na(old.mainLine)
                        line.delete(old.mainLine)
                    if not na(old.zoneBox)
                        box.delete(old.zoneBox)
                    if not na(old.breakLabel)
                        label.delete(old.breakLabel)
            else
                line.delete(lvl.mainLine)
                if not na(lvl.zoneBox)
                    box.delete(lvl.zoneBox)

            array.remove(activeLevels, i)

// }
// PLOT ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――{

// Extend visuals on active levels
int extSize = array.size(activeLevels)
if extSize > 0
    for i = 0 to extSize - 1
        lvl = array.get(activeLevels, i)
        if lvl.active
            //  DYNAMIC LONGEVITY WIDTH CALCULATION 
            if useDynamicWidth
                age = bar_index - lvl.barStart
                // Scale width from 1 to maxLineWidth based on maxAgeBars
                calcWidth = math.min(maxLineWidth, 1 + math.floor((age / maxAgeBars) * (maxLineWidth - 1)))
                line.set_width(lvl.mainLine, int(calcWidth))
            else
                line.set_width(lvl.mainLine, lineWidth)

            line.set_x2(lvl.mainLine, bar_index + 1)
            if not na(lvl.zoneBox)
                box.set_right(lvl.zoneBox, bar_index + 1)
            if showPriceLbl and not na(lvl.priceLabel)
                label.set_x(lvl.priceLabel, bar_index + 10)

var float nearestSup = na
var float nearestRes = na

nearestSup := na
nearestRes := na

// Dashboard scanning
int dashScanSize = array.size(activeLevels)
if dashScanSize > 0
    for i = 0 to dashScanSize - 1
        lvl = array.get(activeLevels, i)
        if not lvl.active
            continue
        if lvl.levelType == -1 and lvl.price < close
            if na(nearestSup) or lvl.price > nearestSup
                nearestSup := lvl.price
        if lvl.levelType == 1 and lvl.price > close
            if na(nearestRes) or lvl.price < nearestRes
                nearestRes := lvl.price

// Draw Dashboard
var table dashTable = na

if showDash
    tablePos = switch dashPos
        "Top Right"    => position.top_right
        "Bottom Right" => position.bottom_right
        "Top Left"     => position.top_left
        "Bottom Left"  => position.bottom_left
        => position.bottom_right

    if barstate.isfirst
        dashTable := table.new(
             position     = tablePos,
             columns      = 2,
             rows         = 5,
             bgcolor      = color.new(#0d1117, 5),
             border_color = color.new(#30363d, 40),
             border_width = 1,
             frame_color  = color.new(#30363d, 20),
             frame_width  = 1
         )

    if barstate.islast and not na(dashTable)
        table.cell(dashTable, 0, 0, "S/R Dashboard", text_color=color.new(#f0f6fc, 0), text_size=size.normal, bgcolor=color.new(#161b22, 0), text_halign=text.align_center)
        table.merge_cells(dashTable, 0, 0, 1, 0)

        table.cell(dashTable, 0, 1, "Resistance", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
        table.cell(dashTable, 1, 1,
             na(nearestRes) ? "—" : str.tostring(nearestRes, format.mintick),
             text_color  = na(nearestRes) ? color.new(#484f58, 0) : resColor,
             text_size   = size.normal,
             bgcolor     = color.new(#0d1117, 10),
             text_halign = text.align_right
         )

        table.cell(dashTable, 0, 2, "Support", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
        table.cell(dashTable, 1, 2,
             na(nearestSup) ? "—" : str.tostring(nearestSup, format.mintick),
             text_color  = na(nearestSup) ? color.new(#484f58, 0) : supColor,
             text_size   = size.normal,
             bgcolor     = color.new(#0d1117, 10),
             text_halign = text.align_right
         )

        table.cell(dashTable, 0, 3, "Last Break", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
        breakDirColor = lastBreakDir == "Bullish" ? supColor : lastBreakDir == "Bearish" ? resColor : color.new(#484f58, 0)
        table.cell(dashTable, 1, 3, lastBreakDir, text_color=breakDirColor, text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_right)

        activeCnt = array.size(activeLevels)
        table.cell(dashTable, 0, 4, "Active Levels", text_color=color.new(#8b949e, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_left)
        table.cell(dashTable, 1, 4, str.tostring(activeCnt), text_color=color.new(#f0f6fc, 0), text_size=size.normal, bgcolor=color.new(#0d1117, 10), text_halign=text.align_right)

// }

Source: TradingView