<img src="https://s3.tradingview.com/e/E8byEL6g_big.png?v=1777283943" style="width:100%; border-radius:15px; margin-bottom:20px;" alt="Adaptive Support and Resistance Zones [BigBeluga]">
<h1>Unlocking Market Structure: Adaptive Support and Resistance Zones [BigBeluga]</h1>
In the realm of technical analysis, identifying and managing key supply and demand areas is crucial for traders seeking to gain a competitive edge. The Adaptive Support and Resistance Zones [BigBeluga] tool is a high-performance solution designed to detect, visualize, and manage these critical levels. By leveraging volatility-adjusted logic and machine learning algorithms, this innovative tool provides traders with a dynamic roadmap to navigate the ever-changing landscape of market volatility.
Introduction to Adaptive Support and Resistance Zones
Unlike traditional pivot indicators that clutter charts with minor highs and lows, the Adaptive Support and Resistance Zones [BigBeluga] script employs ATR-based filtering to qualify pivot points. This approach ensures that only the most significant structural levels are maintained, providing a clearer picture of where institutional interest lies. By treating support and resistance as dynamic zones rather than thin lines, this tool accounts for market "noise" and offers a more realistic representation of supply and demand.
Detailed Strategy: How to Utilize Adaptive Support and Resistance Zones
The Adaptive Support and Resistance Zones [BigBeluga] tool operates on three primary principles:
- Advanced Swing Detection: The indicator scans for pivot highs and lows based on a user-defined pivot length, applying a "Min ATR Strength" check to filter out "fake" pivots during low-volume consolidation.
- Adaptive Level Management: The script merges levels that are too close to one another, prevents "line spaghetti," and identifies high-confluence zones. Levels remain "Active" as long as price respects them, and once price closes beyond the level, the level is moved to the "Broken" category.
- The S/R Dashboard: A dedicated on-screen table provides a birds-eye view of the current structural state, displaying the nearest resistance/support, last break, and active counter.
Why Use Adaptive Support and Resistance Zones?
The Adaptive Support and Resistance Zones [BigBeluga] tool offers a range of benefits, including:
- Improved market structure analysis: By automating the detection and management of key levels, traders can focus on execution rather than manual charting.
- Enhanced risk management: The tool's ATR-based zone width and customizable break sensitivity enable traders to set mathematically sound stop-losses and entry buffers.
- Increased trading opportunities: The S/R Flip feature allows traders to identify structural shifts in the market, while the Volatility Buffers feature helps traders determine optimal no-trade zones and stop-loss placements.
Key Features of Adaptive Support and Resistance Zones
The Adaptive Support and Resistance Zones [BigBeluga] tool boasts an array of features, including:
- ATR-Based Zone Width: Zones expand and contract based on market volatility, ensuring stop-losses and 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: Define how much "daylight" price needs to show above or below a level before a breakout is confirmed.
- Historical Record: Retain a specific number of recently broken levels to identify long-term historical confluence.
- Clean Visuals: High-contrast colors for Support (Cyan) and Resistance (Orange), with fully customizable transparency.
By incorporating the Adaptive Support and Resistance Zones [BigBeluga] tool into their trading strategy, traders can gain a deeper understanding of market structure, improve their risk management, and increase their trading opportunities. With its advanced features and intuitive interface, this tool is an essential addition to any trader's arsenal.
<br><hr><br>
<h2>Get the Source Code</h2>
<p>You can use the script below directly in your TradingView Pine Editor:</p>
<div style="margin: 30px 0; border: 2px solid #38bdf8; border-radius: 12px; background: #0f172a; overflow: hidden; font-family: sans-serif;">
<div style="background: #1e293b; padding: 10px 20px; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #334155;">
<span style="color: #38bdf8; font-weight: bold; font-size: 14px;">PRO PINE SCRIPT CODE</span>
<button onclick="copyPineCode()" style="background: #38bdf8; color: white; border: none; padding: 6px 15px; border-radius: 6px; cursor: pointer; font-weight: 600; font-size: 12px; transition: 0.3s;">Copy Code</button>
</div>
<div style="padding: 20px; position: relative;">
<pre id="pine_code_area" style="margin: 0; color: #94a3b8; font-family: 'Courier New', monospace; font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-all;">// 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
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)
// }