The script
Resistance from pivot highs and support from pivot lows, drawn as lines that extend to the right until a close breaks them, then turn dotted and stop. Paste it into a new indicator in the Pine Editor, then save and add it to the chart.
//@version=6
indicator("Pivot support and resistance", overlay = true, max_lines_count = 100)
leftBars = input.int(10, "Left bars", minval = 1)
rightBars = input.int(5, "Right bars", minval = 1)
maxLevels = input.int(6, "Unbroken levels to keep per side", minval = 1, maxval = 25)
ph = ta.pivothigh(high, leftBars, rightBars)
pl = ta.pivotlow(low, leftBars, rightBars)
// Unbroken levels, oldest first
var array<line> resLines = array.new<line>()
var array<line> supLines = array.new<line>()
// A new pivot: a line from the pivot bar, extended to the right
if not na(ph)
resLines.push(line.new(bar_index - rightBars, ph, bar_index, ph, color = color.red, width = 2, extend = extend.right))
if resLines.size() > maxLevels
resLines.shift().delete()
if not na(pl)
supLines.push(line.new(bar_index - rightBars, pl, bar_index, pl, color = color.teal, width = 2, extend = extend.right))
if supLines.size() > maxLevels
supLines.shift().delete()
// A level is broken when a bar closes beyond it: end the line there and stop tracking it.
// The loops go backwards so removing an element doesn't skip the next one.
if resLines.size() > 0
for i = resLines.size() - 1 to 0
line l = resLines.get(i)
if close > l.get_y1()
l.set_extend(extend.none)
l.set_x2(bar_index)
l.set_style(line.style_dotted)
resLines.remove(i)
if supLines.size() > 0
for i = supLines.size() - 1 to 0
line l = supLines.get(i)
if close < l.get_y1()
l.set_extend(extend.none)
l.set_x2(bar_index)
l.set_style(line.style_dotted)
supLines.remove(i)
plotshape(not na(ph), "Pivot high", shape.triangledown, location.abovebar, color.red, offset = -rightBars, size = size.tiny)
plotshape(not na(pl), "Pivot low", shape.triangleup, location.belowbar, color.teal, offset = -rightBars, size = size.tiny)How it works
ta.pivothigh(high, leftBars, rightBars). A pivot high is a bar whose high is above theleftBarsbars before it and therightBarsbars after it. Pine can only know thatrightBarsbars later, so the function returns the price on that later bar andnaeverywhere else.line.new(bar_index - rightBars, ph, bar_index, ph, ..., extend = extend.right)starts the line on the pivot bar itself and extends it to the right edge of the chart.- Two arrays of line IDs (
var, so they persist) hold the levels that are still unbroken. PastmaxLevels, the oldest is deleted from the chart. - Breaks. On every bar the loops check each unbroken level: a close above a resistance (or below a support) ends its line at the current bar, turns it dotted and removes it from the array. Broken lines stay visible until the
max_lines_countlimit retires them. - The
if size() > 0guards matter: with an empty array,for i = -1 to 0would count from -1 up to 0 andget(-1)would fail. offset = -rightBarsdraws the small triangles back on the pivot bars, for reading only (see the pitfalls).
Pitfalls
- Pivots are known late. The level exists
rightBarsbars after the pivot. The triangles drawn with a negative offset make it look as if the pivot was known on its own bar; a backtest or alert must only use it from the confirmation bar. See the pivots section of repainting explained. - Testing the pivot as a bool.
if phdoesn't compile in v6: a float isn't a condition (if condition must be bool). Testnot na(ph). - Calling ta.pivothigh() inside a block. Like every
ta.*function it keeps its own history, so it must run on every bar: call it at the top level and test the result in theif(should be called on each calculation). - Removing while looping forward. Removing element
ishifts the next one into positioni, so a forward loop skips it. Loop backwards, as here, or collect the indices first. - Too many lines. Each level is a line, and the default limit is about 50 per script. Set
max_lines_count(up to 500), and keep the number of tracked levels small.
Variations
The nearest unbroken level above and below the close. One loop per side finds the closest level, which can feed a plot, a table or an alert.
// Nearest unbroken resistance above the close and support below it
float nearestRes = na
float nearestSup = na
for l in resLines
float y = l.get_y1()
if y > close and (na(nearestRes) or y < nearestRes)
nearestRes := y
for l in supLines
float y = l.get_y1()
if y < close and (na(nearestSup) or y > nearestSup)
nearestSup := y
plot(nearestRes, "Nearest resistance", color.red, style = plot.style_linebr)
plot(nearestSup, "Nearest support", color.teal, style = plot.style_linebr)
Zones instead of lines. Replace line.new() with box.new(bar_index - rightBars, ph + 0.25 * atr, bar_index, ph - 0.25 * atr, extend = extend.right), with atr = ta.atr(14) calculated at the top level, to draw a band around each pivot, and raise max_boxes_count.
Questions
What do leftbars and rightbars mean in ta.pivothigh?
A pivot high must be higher than the leftbars bars before it and the rightbars bars after it. Larger values find fewer, more significant swings. rightbars is also the delay: the pivot is only confirmed that many bars later.
Does ta.pivothigh repaint?
Not after confirmation: once returned, the value doesn't change. But it arrives rightbars bars after the pivot, and drawing it back on the pivot bar with an offset makes the chart look earlier than it really was.
How do I get the last pivot high on every bar?
Use ta.valuewhen(not na(ph), ph, 0), with ph = ta.pivothigh(high, 10, 5) on its own line. It returns the most recent pivot high on every bar, and ta.valuewhen(not na(ph), ph, 1) the one before.
Are these the same as classic pivot points?
No. Classic pivot points are levels calculated from the previous day's (or week's) high, low and close. Pivot highs and lows are swing points found in the price itself. Both are on this site: pivot points have their own indicator guide.
Related pages
Every script on this page was checked with Edgoro Pine Check (Pine Script v6 rules). Pine Check is a static checker, not TradingView's compiler: TradingView compiles the script when you save it in the Pine Editor. The scripts are examples to learn from, not trading systems. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.