0% found this document useful (0 votes)
226 views12 pages

Supply & Demand Zones in Pine Script

This document contains a Pine Script™ code for a Supply and Demand indicator used in trading analysis. It defines various parameters and configurations for rendering supply and demand zones on a chart, including zone sizes, colors, and timeframes. The script includes functions for creating, rendering, and managing these zones, as well as handling overlaps and combining zones based on specific conditions.

Uploaded by

asgraphics010
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
226 views12 pages

Supply & Demand Zones in Pine Script

This document contains a Pine Script™ code for a Supply and Demand indicator used in trading analysis. It defines various parameters and configurations for rendering supply and demand zones on a chart, including zone sizes, colors, and timeframes. The script includes functions for creating, rendering, and managing these zones, as well as handling overlaps and combining zones based on specific conditions.

Uploaded by

asgraphics010
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.

0
at [Link]
// © fluxchart

//@version=5
const bool DEBUG = false
const int maxBoxesCount = 500
const float overlapThresholdPercentage = 0.0
int maxDistanceToLastBar = 1250 // Affects Running Time
const int maxSDZones = 30
const int minZoneSize = 10
const int RETEST_COOLDOWN = 5
const int minDistanceBetweenZones = 5
const float maxZoneSizeATR = 1.5

indicator(title = 'Supply & Demand (MTF) | Flux Charts', shorttitle = "Supply and
Demand (MTF) | Flux Charts", overlay = true, max_boxes_count = maxBoxesCount,
max_labels_count = maxBoxesCount, max_lines_count = maxBoxesCount, max_bars_back =
2000, dynamic_requests = true)

maxDistanceString = [Link]("Normal", "Max Distance To Last Bar", options =


["High", "Normal", "Low"], group = "General Configuration", display =
[Link])
sdEndMethod = [Link]("Close", "Zone Invalidation", options = ["Wick",
"Close"], group = "General Configuration", display = [Link])
combineSDs = DEBUG ? [Link](true, "Combine Zones", group = "General
Configuration", display = [Link]) : true
momentumBodyMult = DEBUG ? [Link](0.5, "Momentum Body Mult", step = 0.1, group
= "General Configuration") : 0.5
momentumCount = DEBUG ? [Link](4,"Momentum Count", group = "General
Configuration") : 4
momentumSpan = DEBUG ? [Link](4, "Momentum Span", group = "General
Configuration") : 4
//zoneCount = [Link]("High", 'Zone Count', options = ["High", "Medium",
"Low", "One"], tooltip = "Number of S&D Zones to be rendered. Higher options will
result in older S&Ds shown.", group = "General Configuration", display =
[Link])
zoneCount = "High"
retestsEnabled = [Link](true, "Retests", inline = "rb", group = "General
Configuration", display = [Link])
breaksEnabled = [Link](false, "Breaks", inline = "rb", group = "General
Configuration", display = [Link])
showInvalidated = [Link](true, "Show Historic Zones", group = "General
Configuration", display = [Link])
bullSDZoneColor = input(#08998180, 'Demand', inline = 'sdColor', group = 'General
Configuration', display = [Link])
bearSDZoneColor = input(#f2364680, 'Supply', inline = 'sdColor', group = 'General
Configuration', display = [Link])

demandZones = zoneCount == "One" ? 1 : zoneCount == "Low" ? 3 : zoneCount ==


"Medium" ? 5 : 30
supplyZones = zoneCount == "One" ? 1 : zoneCount == "Low" ? 3 : zoneCount ==
"Medium" ? 5 : 30

timeframe1Enabled = [Link](true, title = "", group = "Timeframes", inline =


"timeframe1", display = [Link])
timeframe1 = [Link]("", title = "", group = "Timeframes", inline =
"timeframe1", display = [Link])
timeframe2Enabled = [Link](false, title = "", group = "Timeframes", inline =
"timeframe2", display = [Link])
timeframe2 = [Link]("15", title = "", group = "Timeframes", inline =
"timeframe2", display = [Link])
timeframe3Enabled = [Link](false, title = "", group = "Timeframes", inline =
"timeframe3", display = [Link])
timeframe3 = [Link]("30", title = "", group = "Timeframes", inline =
"timeframe3", display = [Link])

textColor = [Link](#ffffffcc, "Text Color", group = "Style")


labelsAtSameLevel = DEBUG ? [Link](true, "[DBG] Place Labels At Same Level",
group = "Style") : true
labelsAtSameLevelBreak = false

atr = [Link](20)
averageBodySize = [Link]([Link](close - open), 20)

maxDistanceToLastBar := maxDistanceString == "Low" ? 150 : maxDistanceString ==


"Normal" ? 500 : 1250

type sdZoneInfo
float top
float bottom
string sdType
int startTime
int breakTime
int guid
string timeframeStr
bool disabled = false
string combinedTimeframesStr = na
bool combined = false

type sdZone
sdZoneInfo info
bool isRendered = false

box sdBox = na

line sdBoxLineTop = na
line sdBoxLineMiddle = na
line sdBoxLineBottom = na
//
box sdBoxText = na

type retestLabelContainer
int guid
array<label> labels

createSDZone (sdZoneInfo sdZoneInfoF) =>


sdZone newSDZone = [Link](sdZoneInfoF)
newSDZone

safeDeleteSDZone (sdZone sdZoneF) =>


[Link] := false

[Link]([Link])
[Link]([Link])

[Link]([Link])
[Link]([Link])
[Link]([Link])

type timeframeInfo
int index = na
string timeframeStr = na
bool isEnabled = false

sdZoneInfo[] demandZonesList = na
sdZoneInfo[] supplyZonesList = na

newTimeframeInfo (index, timeframeStr, isEnabled) =>


newTFInfo = [Link]()
[Link] := index
[Link] := isEnabled
[Link] := timeframeStr

newTFInfo

// ____ TYPES END ____

var timeframeInfo[] timeframeInfos = [Link](newTimeframeInfo(1, timeframe1,


timeframe1Enabled), newTimeframeInfo(2, timeframe2, timeframe2Enabled),
newTimeframeInfo(3, timeframe3, timeframe3Enabled))
var demandZonesList = [Link]<sdZoneInfo>(0)
var supplyZonesList = [Link]<sdZoneInfo>(0)
var breakLabels = [Link]<int, label>()
var retestLabels = [Link]<int, retestLabelContainer>()

var int oldestBarTime = na


if bar_index == last_bar_index - maxDistanceToLastBar
oldestBarTime := time

var allSDZonesList = [Link]<sdZone>(0)

moveLine(_line, _x, _y, _x2) =>


line.set_xy1(_line, _x, _y)
line.set_xy2(_line, _x2, _y)

moveBox (_box, _topLeftX, _topLeftY, _bottomRightX, _bottomRightY) =>


box.set_lefttop(_box, _topLeftX, _topLeftY)
box.set_rightbottom(_box, _bottomRightX, _bottomRightY)

isTimeframeLower (timeframe1F, timeframe2F) =>


timeframe.in_seconds(timeframe1F) < timeframe.in_seconds(timeframe2F)

getMinTimeframe (timeframe1F, timeframe2F) =>


if isTimeframeLower(timeframe1F, timeframe2F)
timeframe1F
else
timeframe2F

getMaxTimeframe (timeframe1F, timeframe2F) =>


if isTimeframeLower(timeframe1F, timeframe2F)
timeframe2F
else
timeframe1F

formatTimeframeString (formatTimeframe) =>


timeframeF = formatTimeframe == "" ? [Link] : formatTimeframe

if [Link](timeframeF, "D") or [Link](timeframeF, "W") or


[Link](timeframeF, "S") or [Link](timeframeF, "M")
timeframeF
else
seconds = timeframe.in_seconds(timeframeF)
if seconds >= 3600
hourCount = int(seconds / 3600)
[Link](hourCount) + " Hour" + (hourCount > 1 ? "s" : "")
else
timeframeF + " Min"

colorWithTransparency (colorF, transparencyX) =>


[Link](colorF, color.t(colorF) * transparencyX)

createSDBox (boxColor, transparencyX = 1.0, xlocType = xloc.bar_time) =>


[Link](na, na, na, na, xloc = xlocType, extend = [Link], bgcolor =
colorWithTransparency(boxColor, transparencyX), text_color = textColor, text_halign
= text.align_right, text_valign = text.align_bottom, text_size = [Link],
border_color = boxColor)

renderSDZone (sdZone sd) =>


sdZoneInfo info = [Link]

[Link] := true

sdColor = [Link] == "Demand" ? bullSDZoneColor : bearSDZoneColor

int zoneSize = na
if na([Link])
zoneSize := (time + 1) - [Link]
else
zoneSize := ([Link] - [Link])

render = true
if zoneSize < timeframe.in_seconds([Link]) * minZoneSize * 1000
render := false
if [Link] < nz(oldestBarTime, time)
render := false

if render and (showInvalidated or (na([Link])))


[Link] := createSDBox(sdColor, 1.5)
if [Link]
[Link].set_bgcolor(colorWithTransparency(sdColor, 1.1))

startX = [Link]
maxEndX = [Link] + zoneSize / 2

float middlePoint = ([Link] + [Link]) / 2


moveBox([Link], [Link], [Link], [Link] + zoneSize,
[Link])

[Link] := [Link]([Link], middlePoint, [Link]


+ zoneSize, middlePoint, xloc = xloc.bar_time, color = textColor, style =
line.style_dashed)

[Link] := createSDBox([Link]([Link], 100))


moveBox([Link], maxEndX, middlePoint, [Link] + zoneSize,
[Link])
SDText = (na([Link]) ?
formatTimeframeString([Link]) : [Link]) + " "
+ [Link]
//box.set_text([Link], SDText)
boxText = na([Link]) ?
formatTimeframeString([Link]) : [Link]
if DEBUG
boxText += " | " + [Link]([Link])
box.set_text([Link], boxText)

areaOfSD (sdZoneInfo SDInfoF) =>


float XA1 = [Link]
float XA2 = na([Link]) ? time + 1 : [Link]
float YA1 = [Link]
float YA2 = [Link]
float edge1 = [Link]((XA2 - XA1) * (XA2 - XA1) + (YA2 - YA2) * (YA2 - YA2))
float edge2 = [Link]((XA2 - XA2) * (XA2 - XA2) + (YA2 - YA1) * (YA2 - YA1))
float totalArea = edge1 * edge2
totalArea

doSDsTouch (sdZoneInfo SDInfo1, sdZoneInfo SDInfo2) =>


float XA1 = [Link]
float XA2 = na([Link]) ? (time + 1) : [Link]
float YA1 = [Link] + atr / 100
float YA2 = [Link] - atr / 100

float XB1 = [Link]


float XB2 = na([Link]) ? (time + 1) : [Link]
float YB1 = [Link] + atr / 100
float YB2 = [Link] - atr / 100
float intersectionArea = [Link](0, [Link](XA2, XB2) - [Link](XA1, XB1)) *
[Link](0, [Link](YA1, YB1) - [Link](YA2, YB2))
float unionArea = areaOfSD(SDInfo1) + areaOfSD(SDInfo2) - intersectionArea

float overlapPercentage = (intersectionArea / unionArea) * 100.0

if overlapPercentage > overlapThresholdPercentage


true
else
false

isSDValid (sdZoneInfo SDInfo) =>


valid = true
if [Link]
valid := false
valid

clampSDZone (sdZoneInfo sdZoneF) =>


sdZoneSize = [Link] - [Link]
if sdZoneSize > atr * maxZoneSizeATR
diff = sdZoneSize - (atr * maxZoneSizeATR)
[Link] -= diff / 2
[Link] += diff / 2

combineSDsFunc () =>
if [Link]() > 0
lastCombinations = 999
while lastCombinations > 0
lastCombinations := 0
for i = 0 to [Link]() - 1
curSD1 = [Link](i)
for j = 0 to [Link]() - 1
curSD2 = [Link](j)
if i == j
continue
if not isSDValid([Link]) or not isSDValid([Link])
continue
if [Link] != [Link]
continue
if doSDsTouch([Link], [Link])
[Link] := true
[Link] := true

sdZone newSD =
createSDZone([Link]([Link]([Link], [Link]),
[Link]([Link], [Link]), [Link]))
[Link] := [Link]([Link],
[Link])
[Link] := [Link](nz([Link]),
nz([Link]))
[Link] := [Link] == 0 ? na :
[Link]
[Link] := [Link]
[Link] := [Link]
clampSDZone([Link])

[Link] := true
if timeframe.in_seconds([Link]) !=
timeframe.in_seconds([Link])
[Link] :=
(na([Link]) ?
formatTimeframeString([Link]) :
[Link]) + " & " + (na([Link])
? formatTimeframeString([Link]) :
[Link])
[Link](newSD)
lastCombinations += 1

reqSeq (timeframeStr) =>


if timeframe.in_seconds(timeframeStr) == timeframe.in_seconds()
[demandZonesList, supplyZonesList]
else
[demandZonesListF, supplyZonesListF] = [Link]([Link],
timeframeStr, [demandZonesList, supplyZonesList])
[demandZonesListF, supplyZonesListF]

getTFData (timeframeInfo timeframeInfoF, timeframeStr) =>


if [Link]
[demandZonesListF, supplyZonesListF] = reqSeq(timeframeStr)
[demandZonesListF, supplyZonesListF]
else
[na, na]

handleTimeframeInfo (timeframeInfo timeframeInfoF, demandZonesListF,


supplyZonesListF) =>
if [Link]
[Link] := demandZonesListF
[Link] := supplyZonesListF

handleSDZonesFinal () =>
if DEBUG
[Link]("Demand Count " + [Link]([Link]()))
[Link]("Supply Count " + [Link]([Link]()))
[Link]("All " + [Link]([Link]()))
[Link]("Max " + [Link](demandZones))

if [Link]() > 0
for i = 0 to [Link]() - 1
safeDeleteSDZone([Link](i))
[Link]()

for i = 0 to [Link]() - 1
curTimeframe = [Link](i)
if not [Link]
continue
if [Link]() > 0
for j = 0 to [Link]([Link]() - 1,
demandZones - 1)
sdZoneInfoF = [Link](j)
[Link] := [Link]
[Link](createSDZone([Link](sdZoneInfoF)))

if [Link]() > 0
for j = 0 to [Link]([Link]() - 1,
supplyZones - 1)
sdZoneInfoF = [Link](j)
[Link] := [Link]
[Link](createSDZone([Link](sdZoneInfoF)))

if combineSDs
combineSDsFunc()

if [Link]() > 0
for i = 0 to [Link]() - 1
curSD = [Link](i)
if isSDValid([Link])
renderSDZone(curSD)

bodySize = [Link](close - open)


getMomentumCandleCount (lastBars, reqMult) =>
bearishCnt = 0
bullishCnt = 0
for i = 0 to lastBars - 1
if bodySize[i] >= averageBodySize * reqMult
if close[i] > open[i]
bullishCnt += 1
else
bearishCnt += 1
[bullishCnt, bearishCnt]

[bullishMomentum, bearishMomentum] = getMomentumCandleCount(momentumSpan,


momentumBodyMult)
var int lastDemandZone = 0
var int lastSupplyZone = 0
// Find Supply & Demand
if bar_index > last_bar_index - maxDistanceToLastBar
if bullishMomentum >= momentumCount and bar_index - lastDemandZone >
minDistanceBetweenZones
lastDemandZone := bar_index
newSDZone = [Link](high[momentumSpan + 1], low[momentumSpan + 1],
"Demand", time[momentumSpan + 1], na, time[momentumSpan + 1])
clampSDZone(newSDZone)
[Link](newSDZone)
if [Link]() > maxSDZones
[Link]()
if bearishMomentum >= momentumCount and bar_index - lastSupplyZone >
minDistanceBetweenZones
lastSupplyZone := bar_index
newSDZone = [Link](high[momentumSpan + 1], low[momentumSpan + 1],
"Supply", time[momentumSpan + 1], na, time[momentumSpan + 1])
clampSDZone(newSDZone)
[Link](newSDZone)
if [Link]() > maxSDZones
[Link]()

// Invalidation
if [Link]() > 0
for i = [Link]() - 1 to 0
currentSD = [Link](i)

if na([Link])
if (sdEndMethod == "Wick" ? low : [Link](open, close)) <
[Link]
[Link] := time

if [Link]() > 0
for i = [Link]() - 1 to 0
currentSD = [Link](i)

if na([Link])
if (sdEndMethod == "Wick" ? high : [Link](open, close)) >
[Link]
[Link] := time

[demandZonesListTimeframe1, supplyZonesListTimeframe1] =
getTFData([Link](0), timeframe1)
[demandZonesListTimeframe2, supplyZonesListTimeframe2] =
getTFData([Link](1), timeframe2)
[demandZonesListTimeframe3, supplyZonesListTimeframe3] =
getTFData([Link](2), timeframe3)

var lastRetestIndexSupply = 0
var lastRetestIndexDemand = 0

float renderRetestLabelBuyside = na
int renderRetestLabelBuysideGUID = na

float renderRetestLabelSellside = na
int renderRetestLabelSellsideGUID = na

float renderBreakLabelBuyside = na
int renderBreakLabelBuysideGUID = na

float renderBreakLabelSellside = na
int renderBreakLabelSellsideGUID = na

var disabledDuplicateTF = false


// Disable Duplicate Timeframes
if not disabledDuplicateTF
disabledDuplicateTF := true
for i = 0 to [Link]() - 1
for j = 0 to [Link]() - 1
if i == j
continue
timeframeInfo1 = [Link](i)
timeframeInfo2 = [Link](j)
if [Link] and [Link] and
timeframe.in_seconds([Link]) ==
timeframe.in_seconds([Link])
[Link] := false

if [Link] and bar_index > last_bar_index - maxDistanceToLastBar


handleTimeframeInfo([Link](0), demandZonesListTimeframe1,
supplyZonesListTimeframe1)
handleTimeframeInfo([Link](1), demandZonesListTimeframe2,
supplyZonesListTimeframe2)
handleTimeframeInfo([Link](2), demandZonesListTimeframe3,
supplyZonesListTimeframe3)
handleSDZonesFinal()

// Breaks

if [Link]() > 0
for i = 0 to [Link]() - 1
curZone = [Link](i)
if [Link]
continue
if not showInvalidated and not na([Link])
continue
if na([Link])
continue
if time - [Link] < minZoneSize *
timeframe.in_seconds([Link]) * 1000
continue
if [Link] < nz(oldestBarTime, time)
continue

if time == [Link]
if [Link] == "Supply"
if [Link] - [Link] >
minZoneSize * timeframe.in_seconds() * 1000
renderBreakLabelBuyside := [Link]
renderBreakLabelBuysideGUID := [Link]
else
if [Link] - [Link] >
minZoneSize * timeframe.in_seconds() * 1000
renderBreakLabelSellside := [Link]
renderBreakLabelSellsideGUID := [Link]

// Retests
if [Link]() > 0
for i = 0 to [Link]() - 1
curZone = [Link](i)

if [Link]
continue
if not showInvalidated and not na([Link])
continue
if not na([Link])
continue
if time - [Link] < minZoneSize *
timeframe.in_seconds([Link]) * 1000
continue
if [Link] < nz(oldestBarTime, time)
continue

middleLine = ([Link] + [Link]) / 2.0


if [Link] == "Supply" and bar_index -
lastRetestIndexSupply > RETEST_COOLDOWN
if high > [Link]
renderRetestLabelBuyside := [Link]
renderRetestLabelBuysideGUID := [Link]
lastRetestIndexSupply := bar_index
else if [Link] == "Demand" and bar_index -
lastRetestIndexDemand > RETEST_COOLDOWN
if low < [Link]
renderRetestLabelSellside := [Link]
renderRetestLabelSellsideGUID := [Link]
lastRetestIndexDemand := bar_index

//plotshape(not na(renderRetestLabelBuyside) and retestsEnabled ?


renderRetestLabelBuyside : na, "", [Link], color = bearSDZoneColor, text =
"R", location = labelsAtSameLevel ? [Link] : [Link],
textcolor = [Link], size = [Link])
//plotshape(not na(renderRetestLabelSellside) and retestsEnabled ?
renderRetestLabelSellside : na, "", [Link], color = bullSDZoneColor, text =
"R", location = labelsAtSameLevel ? [Link] : [Link],
textcolor = [Link], size = [Link])

// Retests

if not na(renderRetestLabelBuyside) and retestsEnabled


newLabel = [Link](bar_index, renderRetestLabelBuyside, style =
label.style_label_down, color = bearSDZoneColor, text = "R", textcolor =
[Link], size = [Link])
//[Link](bar_index, renderRetestLabelSellside, style = label.style_label_up,
color = bullSDZoneColor, text = "R", textcolor = [Link], size = [Link])
if na([Link](renderRetestLabelBuysideGUID))
newContainer = [Link](renderRetestLabelBuysideGUID)
[Link] := [Link]<label>()
[Link](newLabel)
[Link](renderRetestLabelBuysideGUID, newContainer)
else
[Link](renderRetestLabelBuysideGUID).[Link](newLabel)

if not na(renderRetestLabelSellside) and retestsEnabled


newLabel = [Link](bar_index, renderRetestLabelSellside, style =
label.style_label_up, color = bullSDZoneColor, text = "R", textcolor = [Link],
size = [Link])
if na([Link](renderRetestLabelSellsideGUID))
newContainer = [Link](renderRetestLabelSellsideGUID)
[Link] := [Link]<label>()
[Link](newLabel)
[Link](renderRetestLabelSellsideGUID, newContainer)
else
[Link](renderRetestLabelSellsideGUID).[Link](newLabel)

if [Link]().size() > 0
for i = 0 to [Link]().size() - 1
curKey = [Link]().get(i)
foundKey = false
if [Link]() > 0
for j = 0 to [Link]() - 1
if [Link](j).[Link] == curKey
if [Link](j).[Link]
continue
if not showInvalidated and not
na([Link](j).[Link])
continue
if time - [Link](j).[Link] < minZoneSize *
timeframe.in_seconds([Link](j).[Link]) * 1000
continue
if [Link](j).[Link] < nz(oldestBarTime,
time)
continue
foundKey := true
break
if not foundKey
for j = 0 to [Link](curKey).[Link]() - 1
[Link]([Link](curKey).[Link](j))

// Breaks
if not na(renderBreakLabelBuyside) and breaksEnabled
[Link](renderBreakLabelBuysideGUID, [Link](bar_index,
renderBreakLabelBuyside, style = label.style_label_up, color = [Link], text =
"B", textcolor = [Link], size = [Link]))

if not na(renderBreakLabelSellside) and breaksEnabled


[Link](renderBreakLabelSellsideGUID, [Link](bar_index,
renderBreakLabelSellside, style = label.style_label_down, color = [Link], text
= "B", textcolor = [Link], size = [Link]))

if [Link]().size() > 0
for i = 0 to [Link]().size() - 1
curKey = [Link]().get(i)
foundKey = false
if [Link]() > 0
for j = 0 to [Link]() - 1
if [Link](j).[Link] == curKey
if [Link](j).[Link]
continue
foundKey := true
break
if not foundKey
[Link]([Link](curKey))

alertcondition(not na(renderRetestLabelBuyside) and [Link], "Supply


Zone Retest @ {{ticker}}", "Supply Zone Retest @ {{ticker}}")
alertcondition(not na(renderRetestLabelSellside) and [Link], "Demand
Zone Retest @ {{ticker}}", "Demand Zone Retest @ {{ticker}}")

alertcondition(not na(renderBreakLabelBuyside) and [Link], "Supply


Zone Break @ {{ticker}}", "Supply Zone Break @ {{ticker}}")
alertcondition(not na(renderBreakLabelSellside) and [Link], "Demand
Zone Break @ {{ticker}}", "Demand Zone Break @ {{ticker}}")

Common questions

Powered by AI

The script supports multi-timeframe visualization by enabling up to three different timeframes. Zones are collected and processed separately for each active timeframe. By formatting and rendering these zones using a function that can distinguish between timeframes through labels and colors, the script ensures that users can see how zones overlap or differ across timelines. This enhances traders' ability to detect long-term vs. short-term trading opportunities .

The algorithm manages changing market data by continuously recalculating and updating the supply and demand zones with each new bar. It uses variables like 'maxDistanceToLastBar' to limit historical data processing, and attributes like 'breakTime' to dynamically invalidate zones when prices breach defined boundaries. This ensures that the visualization remains relevant to current market conditions and aids traders in making timely decisions .

ATR is utilized to scale the size and buffer of supply and demand zones. It determines the maximum allowable size of a zone through 'maxZoneSizeATR', ensuring that zones do not become disproportionately large relative to market volatility. Additionally, ATR influences the 'doSDsTouch' function, which checks zone overlap by using ATR to adjust zone boundaries for more accurate detection of interactions between overlapping zones .

The document suggests using a 'breakTime' attribute to mark zones as invalidated. If a zone's price breaks a defined boundary (top for supply, bottom for demand), 'breakTime' is set to the current time, invalidating the zone. Invalidated zones may not be rendered if the 'showInvalidated' option is false, affecting how traders visualize potential supply and demand areas on the chart .

The area of a supply or demand zone is calculated using the function 'areaOfSD', which computes the area as the product of the differences in time (X-axis) and price levels (Y-axis) between the zone's start and end points. This calculation implies that zones extending over longer periods or price ranges are considered more significant. This is crucial for traders as it quantifies the zone's impact potential on price movement .

The document describes a function 'combineSDsFunc()' that combines supply and demand zones if they are of the same type, either both supply or both demand, and have an overlap greater than the defined 'overlapThresholdPercentage'. The function iterates through all zones and checks if zones touch or overlap using the 'doSDsTouch' function, which calculates the overlap percentage. If the overlapping percentage exceeds the threshold, the zones are combined, and attributes like startTime and breakTime are recalibrated to encompass both zones .

The document integrates momentum indicators into zone creation by using 'momentumBodyMult' and 'momentumCount' parameters to determine the presence of significant bullish or bearish momentum before creating new zones. If the number of consecutive momentum candles exceeds 'momentumCount', a new zone is created, indicating either demand or supply, depending on the direction of the momentum. This approach helps identify zones with likely price reactions .

The running time of the Pine Script™ code is affected by parameters such as 'maxDistanceToLastBar', 'maxSDZones', and 'minZoneSize'. These parameters determine the number of zones and bars to be processed, which directly impacts the execution time. For example, 'maxDistanceToLastBar' is set to 1250, which limits how far back in the data the script will analyze .

The 'DEBUG' variable is used to enable or disable additional diagnostic features within the script. When 'DEBUG' is set to true, it allows the script to collect and display extra debugging information, such as detailed zone data and function execution feedback. When set to false, these additional features are turned off, leading to a cleaner and more concise output, which may result in better performance .

Using labels in supply and demand zones effectively enhances a trader's ability to quickly identify important areas on a chart. Labels can provide critical information such as zone type and timeframe, indicated through colors and text. They serve as visual anchors that highlight crucial market levels, helping traders make informed decisions based on historical price action. However, excessive labeling, especially if not managed by features like 'labelsAtSameLevel', can lead to clutter, detracting from their utility .

You might also like