Indicator · Pine Script v5 · On the chart

Pivot Trendlines

by g-moe· code credited to goodgains

The Pivot Trendlines indicator identifies swing highs and lows on the chart to form support and resistance levels.

View on GitHub

GitHub stars3on the repository
Pine versionv5runs as is
Lines of code220
Settings6inputs
LicenceNone statedfile: MPL-2.0
Last update5 months ago27 May 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

220 lines of Pine Script v5 from Tradingview/pivot-trendlines-v6.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

pivot-trendlines-v6.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © goodgains


//@version=5
indicator("Pivot Trendlines", overlay = true, max_labels_count = 500)

// @keywords: pivot-swing-levels, trendline-connector, buy-sell-signals, percent-from-level, max-signals-cap, bars-back-limit, swing-high-low, level-rejection, signal-clustering, overlay-arrows, pivot-length-input, support-resistance-lines, dynamic-trendlines, level-touch-filter, intraday-reversals, breakout-confirmation, signal-spacing, level-memory-array, price-action-pivots, directional-bias

// inputs
buySignals              = input.bool(true, title = 'Buy Signals', group = 'Settings', inline = 'buy')
sellSignals             = input.bool(false, title = 'Sell Signals', group = 'Settings', inline = 'sell')
sd_length               = input.int(3, title = 'Length', group = 'Settings', minval = 2, maxval = 50, inline = '0')
percent_required        = input.float(0.50, step = 0.25, title = '% Required', group = 'Settings', inline = '1')
max_signals_for_level   = input.int(5, title = 'Max Signals from Level', group = 'Settings', inline = '2', minval = 1)
max_barsBack_for_level  = input.int(500, title = 'Max Bars Back from Level', group = 'Settings', inline = '3')


// functions
f_array_add_pop(array, new_value_to_add) =>
    array.unshift(array, new_value_to_add)



// calc levels
var swing_high_values = array.new_float(1, na)
var swing_low_values  = array.new_float(1, na)
 
swing_high = ta.pivothigh(high, sd_length, sd_length)
swing_low = ta.pivotlow(low, sd_length, sd_length)

if not na(swing_high)
    f_array_add_pop(swing_high_values, swing_high)

if not na(swing_low)
    f_array_add_pop(swing_low_values, swing_low)


plotchar(not na(swing_high), title = 'Swing High', char = 'X', location = location.abovebar, color = chart.fg_color,
 offset = -sd_length, size = size.auto)

plotchar(not na(swing_low), title = 'Swing Low', char = 'X', location = location.belowbar, color = chart.fg_color,
 offset = -sd_length, size = size.auto)



// calc breaks
var bool haveBase               = false
var bool baseExpired            = false
var float currentBase           = 0.00
var int currentBaseType         = 0

var int lastBreak_numSignals    = 0
var int lastBreak_BN            = 0

var bool buySignal              = false
var bool sellSignal             = false
var bool retraceComplete        = false


f_findHighBreaks(highLevels) =>
    var bool newBase        = false
    var float newBaseLevel  = 0.00
    
    array_size = array.size(highLevels)
    if array_size > 0 and sellSignals
        for i = 0 to array_size - 1
            highLevel = array.get(highLevels, i)

            if (high-highLevel)/highLevel*100 >= (percent_required)
                newBase := true
                newBaseLevel := highLevel
                array.clear(highLevels)
                break
            else
                newBase := false
                newBaseLevel := 0.00

    else
        newBase := false
        newBaseLevel := 0.00
    
    [newBase, newBaseLevel]
            



f_findLowBreaks(lowLevels) =>
    var bool newBase        = false
    var float newBaseLevel  = 0.00
    
    array_size = array.size(lowLevels)
    if array_size > 0 and buySignals
        for i = 0 to array_size - 1
            lowLevel = array.get(lowLevels, i)

            if (low-lowLevel)/lowLevel*100 <= (-percent_required)
                newBase := true
                newBaseLevel := lowLevel
                array.clear(lowLevels)
                break
            else
                newBase := false
                newBaseLevel := 0.00

    else
        newBase := false
        newBaseLevel := 0.00
    
    [newBase, newBaseLevel]



f_invalidateHighs(highLevels) =>
    array_size = array.size(highLevels)
    if array_size > 0 and barstate.isconfirmed
        for i = 0 to array_size - 1
            highLevel = array.get(highLevels, i)
            if low[1] > highLevel and low < highLevel
                array.set(highLevels, i, na)



f_invalidateLows(lowLevels) =>
    array_size = array.size(lowLevels)
    if array_size > 0 and barstate.isconfirmed
        for i = 0 to array_size - 1
            lowLevel = array.get(lowLevels, i)
            if high[1] < lowLevel and high > lowLevel
                array.set(lowLevels, i, na)



// f_invalidateHighs(swing_high_values)
f_invalidateLows(swing_low_values)
[f_newSellBase, f_newSellBaseLevel] = f_findHighBreaks(swing_high_values)
[f_newBuyBase, f_newBuyBaseLevel]   = f_findLowBreaks(swing_low_values)

haveBase := not haveBase[1] and (f_newBuyBase or f_newSellBase) ? true : haveBase[1]
baseExpired := haveBase[1] and (bar_index - lastBreak_BN >= max_barsBack_for_level)

if haveBase

    if not haveBase[1]
        currentBase         := f_newBuyBase ? f_newBuyBaseLevel : f_newSellBaseLevel
        currentBaseType     := f_newBuyBase ? 1 : -1
        lastBreak_numSignals:= 2
        lastBreak_BN        := bar_index
        buySignal           := f_newBuyBase
        sellSignal          := f_newSellBase
        retraceComplete     := false

    else if currentBaseType == 1
        buySignal           := (low-currentBase)/currentBase*100 <= (-percent_required*lastBreak_numSignals) and lastBreak_numSignals <= max_signals_for_level
        retraceComplete     := lastBreak_numSignals >= 2 and high >= currentBase
        lastBreak_numSignals:= buySignal ? lastBreak_numSignals[1] + 1 : lastBreak_numSignals

    else if currentBaseType == -1
        sellSignal          := (high-currentBase)/currentBase*100 >= (percent_required*lastBreak_numSignals) and lastBreak_numSignals <= max_signals_for_level
        retraceComplete     := lastBreak_numSignals >= 2 and low <= currentBase
        lastBreak_numSignals:= sellSignal ? lastBreak_numSignals[1] + 1 : lastBreak_numSignals


    if retraceComplete or baseExpired
        currentBase     := na
        currentBaseType := 0
        haveBase        := false

else
    buySignal   := false
    sellSignal  := false



// visualize
plot(currentBase, title = 'Current Base', color = color.blue, style = plot.style_circles)

plot(currentBaseType == 1 ? currentBase - (currentBase*(percent_required*1/100))
 : currentBase + (currentBase*(percent_required*1/100)), title = 'Entry 1',
 color = currentBaseType == 1 ? color.green : color.red, style = plot.style_circles)

plot(currentBaseType == 1 ? currentBase - (currentBase*(percent_required*2/100))
 : currentBase + (currentBase*(percent_required*2/100)), title = 'Entry 2',
 color = currentBaseType == 1 ? color.green : color.red, style = plot.style_circles)

plot(currentBaseType == 1 ? currentBase - (currentBase*(percent_required*3/100))
 : currentBase + (currentBase*(percent_required*3/100)), title = 'Entry 3',
 color = currentBaseType == 1 ? color.green : color.red, style = plot.style_circles)

plot(currentBaseType == 1 ? currentBase - (currentBase*(percent_required*4/100))
 : currentBase + (currentBase*(percent_required*4/100)), title = 'Entry 4',
 color = currentBaseType == 1 ? color.green : color.red, style = plot.style_circles)

plot(currentBaseType == 1 ? currentBase - (currentBase*(percent_required*5/100))
 : currentBase + (currentBase*(percent_required*5/100)), title = 'Entry 5',
 color = currentBaseType == 1 ? color.green : color.red, style = plot.style_circles)


bgcolor(currentBaseType == 1 ? color.new(color.green, 90) : currentBaseType == -1 ? color.new(color.red, 90) : na)
// plot((low-currentBase)/currentBase*100, color = color.yellow)
// plot(lastBreak_numSignals, color = color.yellow)


plotshape(buySignal, style=shape.labelup, editable=true, title = 'Buy',
 text= "BUY", textcolor=color.white, location= location.belowbar, color=color.new(color.green, 30), size=size.tiny)

plotshape(sellSignal, style=shape.labeldown, editable=true, title = 'Sell',
 text='SELL', textcolor=color.white, location=location.abovebar, color=color.new(color.red, 30), size=size.tiny)

plotshape(retraceComplete and currentBaseType[1] == 1, style=shape.labeldown, editable=true, title = 'Long Exit',
 text='EXIT', textcolor=color.white, location=location.abovebar, color=color.new(color.gray, 30), size=size.tiny)

plotshape(retraceComplete and currentBaseType[1] == -1, style=shape.labelup, editable=true, title = 'Short Exit',
 text='EXIT', textcolor=color.white, location=location.belowbar, color=color.new(color.gray, 30), size=size.tiny)

plotshape(baseExpired and currentBaseType[1] == 1, style=shape.labeldown, editable=true, title = 'Long T_Exit',
 text='T_Exit', textcolor=color.white, location=location.abovebar, color=color.new(color.gray, 30), size=size.tiny)

plotshape(baseExpired and currentBaseType[1] == -1, style=shape.labelup, editable=true, title = 'Short T_Exit',
 text='T_Exit', textcolor=color.white, location=location.belowbar, color=color.new(color.gray, 30), size=size.tiny)

Overview

Pivot Trendlines plots these levels as markers and draws trendlines connecting them. Buy and sell signals activate when the price breaks beyond a set percentage from these levels. Users can enable or disable buy and sell signals separately. Settings include the pivot length, minimum percentage required for breaks, maximum signals per level, and maximum bars back to consider for levels. The script draws all elements on the price chart as an overlay. Levels are stored in arrays and signals can be filtered by clustering or time limits. It does not include automated exit rules or risk management tools.

Details

Published by

g-moe on GitHub

Code credit

goodgains, as written in the script's header

Draws

On the price chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Buy SignalsbooltruebuySignals
Sell SignalsboolfalsesellSignals
Lengthint3sd_length
% Requiredfloat0.50percent_required
Max Signals from Levelint5max_signals_for_level
Max Bars Back from Levelint500max_barsBack_for_level
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

Sideway Zones Live

by dearvn
257 stars

Sideway Zones Live is an overlay indicator that estimates inner and outer sideways bands from recent highs and lows with a rational quadratic kernel. It tracks swing pivots over a loopback period and counts bars that remain between the outer high and low. Afte

Indicator v5 TrendSupport & resistance
Updated 7 weeks ago · None stated GitHub repository of Sideway Zones Live
56 stars

This indicator calculates dynamic upper and lower trendlines from pivot highs and pivot lows across a specified bar length. Trendline slopes are derived using ATR, standard deviation, or linear regression methods. It plots trendlines and breakout signal labels

Indicator v5 TrendSupport & resistance Repaints
Updated 2 months ago · None stated GitHub repository of Trendlines With Breaks [LUX]

Reversal Breakout System

by TamaraKGreen
46 stars

This indicator detects inside candles inside larger parent candles on the price chart. It plots colored boxes around inside and parent candles, fills them with user-adjustable transparency, draws Fibonacci retracement lines and mother candle range lines, and d

Indicator v6 Candlestick patternsBreakout
Updated 8 weeks ago · None stated GitHub repository of Reversal Breakout System
24 stars

This indicator maps Smart Money Concepts (SMC) market structure directly onto the price chart. It detects internal and swing structure breaks (BOS and CHoCH), tracks bullish and bearish order blocks, identifies fair value gaps (FVG), highlights equal highs and

Indicator v5 SMC / ICT / price actionSupport & resistance Repaints
Updated 12 days ago · Custom licence GitHub repository of Smart Money Concepts [LuxAlgo] Test B

The Market Tradability Engine calculates multi-factor tradability, balance, compression, and direction scores to evaluate market regime quality. It classifies market conditions into eight distinct states, including Balance, Compression, Ready, Breakout, Trend,

Indicator v6 TrendVolatility & bands
Updated 3 days ago · MIT GitHub repository of Market Tradability Engine [WavesUnchained]

This indicator tracks swing highs and swing lows to generate trend-following trailing stop levels on the price chart. When the closing price breaks above the previous swing high, the system establishes a bullish state using the recent swing low as a trailing s

Indicator v4 TrendBreakout
Updated 4 years ago · None stated GitHub repository of Accurate Swing Trading System

More Support & resistance scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers