Indicator · Pine Script v4 · On the chart

Support Resistance Channels

by webcrack4· code credited to LonesomeTheBlue

This overlay indicator builds support and resistance channels from confirmed pivot highs and lows.

View on GitHub

GitHub stars1on the repository
Pine versionv4older, still runs
Lines of code191
Settings17inputs
LicenceNone statedfile: MPL-2.0
Last update9 months ago10 Jan 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

191 lines of Pine Script v4 from 30SupportResistanceChannels.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

30SupportResistanceChannels.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © LonesomeTheBlue
 
//@version=4
study("Support Resistance Channels", "SRchannel", overlay = true, max_bars_back = 501)
sr_prd = input(defval = 10, title="Pivot Period", minval = 4, maxval = 30, group = "Settings 🔨", tooltip="Used while calculating Pivot Points, checks left&right bars")
ppsrc = input(defval = 'High/Low', title="Source", options = ['High/Low', 'Close/Open'], group = "Settings 🔨", tooltip="Source for Pivot Points")
ChannelW = input(defval = 5, title = "Maximum Channel Width %", minval = 1, maxval = 8, group = "Settings 🔨", tooltip="Calculated using Highest/Lowest levels in 300 bars")
minstrength = input(defval = 1, title = "Minimum Strength", minval = 1, group = "Settings 🔨", tooltip = "Channel must contain at least 2 Pivot Points")
maxnumsr = input(defval = 6, title = "Maximum Number of S/R", minval = 1, maxval = 10, group = "Settings 🔨", tooltip = "Maximum number of Support/Resistance Channels to Show") - 1
loopback = input(defval = 290, title = "Loopback Period", minval = 100, maxval = 400, group = "Settings 🔨", tooltip="While calculating S/R levels it checks Pivots in Loopback Period")
res_col = input(defval = color.new(color.red, 75), title = "Resistance Color", group = "Colors 🟡🟢🟣")
sup_col = input(defval = color.new(color.lime, 75), title = "Support Color", group = "Colors 🟡🟢🟣")
inch_col = input(defval = color.new(color.gray, 75), title = "Color When Price in Channel", group = "Colors 🟡🟢🟣")
showpp = input(defval = false, title = "Show Pivot Points", group = "Extras ⏶⏷")
showsrbroken = input(defval = false, title = "Show Broken Support/Resistance", group = "Extras ⏶⏷")
showthema1en = input(defval = false, title = "MA 1", inline = "ma1")
showthema1len = input(defval = 50, title = "", inline = "ma1")
showthema1type = input(defval = "SMA", title = "", options = ["SMA", "EMA"], inline = "ma1")
showthema2en = input(defval = false, title = "MA 2", inline = "ma2")
showthema2len = input(defval = 200, title = "", inline = "ma2")
showthema2type = input(defval = "SMA", title = "", options = ["SMA", "EMA"], inline = "ma2")

ma1 = showthema1en ? (showthema1type == "SMA" ? sma(close, showthema1len) : ema(close, showthema1len)) : na
ma2 = showthema2en ? (showthema2type == "SMA" ? sma(close, showthema2len) : ema(close, showthema2len)) : na

sr_plot(ma1, color = not na(ma1) ? color.blue : na)
sr_plot(ma2, color = not na(ma2) ? color.red : na)

// get Pivot High/low
float sr_src1 =  ppsrc == 'High/Low' ? high : max(close, open)
float sr_src2 =  ppsrc == 'High/Low' ? low: min(close, open)
float sr_ph = pivothigh(sr_src1, sr_prd, sr_prd)
float sr_pl = pivotlow(sr_src2, sr_prd, sr_prd) 

// draw Pivot points
sr_plotshape(sr_ph and showpp, text = "H",  style = shape.labeldown, color = na, textcolor = color.red, location = location.abovebar, offset = -sr_prd)
sr_plotshape(sr_pl and showpp, text = "L",  style = shape.labelup, color = na, textcolor = color.lime, location = location.belowbar, offset = -sr_prd)

//calculate maximum S/R channel width
sr_prdhighest =  highest(300)
sr_prdlowest = lowest(300)
cwidth = (sr_prdhighest - sr_prdlowest) * ChannelW / 100

// get/keep Pivot levels
var pivotvals= array.new_float(0)
var pivotlocs= array.new_float(0)
if sr_ph or sr_pl
    array.unshift(pivotvals, sr_ph ? sr_ph : sr_pl)
    array.unshift(pivotlocs, bar_index)
    for x = array.size(pivotvals) - 1 to 0
        if bar_index - array.get(pivotlocs, x) > loopback // remove old pivot points
            array.pop(pivotvals)
            array.pop(pivotlocs)
            continue
        break

//find/create SR channel of a pivot point
get_sr_vals(ind)=>
    float lo = array.get(pivotvals, ind)
    float hi = lo
    int numpp = 0
    for y = 0 to array.size(pivotvals) - 1
        float cpp = array.get(pivotvals, y)
        float wdth = cpp <= hi ? hi - cpp : cpp - lo
        if wdth <= cwidth // fits the max channel width?
            if cpp <= hi
                lo := min(lo, cpp)
            else
                hi := max(hi, cpp)
                
            numpp := numpp + 20 // each pivot point added as 20
    [hi, lo, numpp] 

// keep old SR channels and calculate/sort new channels if we met new pivot point
var suportresistance = array.new_float(20, 0) // min/max levels
changeit(x, y)=>
    tmp = array.get(suportresistance, y * 2)
    array.set(suportresistance, y * 2, array.get(suportresistance, x * 2))
    array.set(suportresistance, x * 2, tmp)
    tmp := array.get(suportresistance, y * 2 + 1)
    array.set(suportresistance, y * 2 + 1, array.get(suportresistance, x * 2 + 1))
    array.set(suportresistance, x * 2 + 1, tmp)
    
if sr_ph or sr_pl
    supres = array.new_float(0)  // number of pivot, strength, min/max levels
    stren = array.new_float(10, 0)
    // get levels and strengs
    for x = 0 to array.size(pivotvals) - 1
        [hi, lo, strength] = get_sr_vals(x)
        array.push(supres, strength)
        array.push(supres, hi)
        array.push(supres, lo)
    
    // add each HL to strengh
    for x = 0 to array.size(pivotvals) - 1
        h = array.get(supres, x * 3 + 1)
        l = array.get(supres, x * 3 + 2)
        s = 0
        for y = 0 to loopback
            if (high[y] <= h and high[y] >= l) or
               (low[y] <= h and low[y] >= l)
                s := s + 1
        array.set(supres, x * 3, array.get(supres, x * 3) + s)
    
    //reset SR levels
    array.fill(suportresistance, 0)
    // get strongest SRs
    src = 0
    for x = 0 to array.size(pivotvals) - 1
        stv = -1. // value
        stl = -1 // location
        for y = 0 to array.size(pivotvals) - 1
            if array.get(supres, y * 3) > stv and array.get(supres, y * 3) >= minstrength * 20
                stv := array.get(supres, y * 3)
                stl := y
        if stl >= 0
            //get sr level
            hh = array.get(supres, stl * 3 + 1)
            ll = array.get(supres, stl * 3 + 2)
            array.set(suportresistance, src * 2, hh)
            array.set(suportresistance, src * 2 + 1, ll)
            array.set(stren, src, array.get(supres, stl * 3))
            
            // make included pivot points' strength zero 
            for y = 0 to array.size(pivotvals) - 1
                if (array.get(supres, y * 3 + 1) <= hh and array.get(supres, y * 3 + 1) >= ll) or
                   (array.get(supres, y * 3 + 2) <= hh and array.get(supres, y * 3 + 2) >= ll)
                    array.set(supres, y * 3, -1)

            src += 1
            if src >= 10
                break
    
    for x = 0 to 8
        for y = x + 1 to 9
            if array.get(stren, y) > array.get(stren, x)
                tmp = array.get(stren, y) 
                array.set(stren, y, array.get(stren, x))
                changeit(x, y)
                
    
get_level(ind)=>
    float ret = na
    if ind < array.size(suportresistance)
        if array.get(suportresistance, ind) != 0
            ret := array.get(suportresistance, ind)
    ret
    
get_color(ind)=>
    color ret = na
    if ind < array.size(suportresistance)
        if array.get(suportresistance, ind) != 0
            ret := array.get(suportresistance, ind) > close and array.get(suportresistance, ind + 1) > close ? res_col :
                   array.get(suportresistance, ind) < close and array.get(suportresistance, ind + 1) < close ? sup_col :
                   inch_col
    ret

var srchannels = array.new_box(10)
for x = 0 to min(9, maxnumsr)
    box.delete(array.get(srchannels, x))
    srcol = get_color(x * 2)
    if not na(srcol)
        array.set(srchannels, x, 
                  box.new(left = bar_index, top = get_level(x * 2), right = bar_index + 1, bottom = get_level(x * 2 + 1), 
                          border_color = srcol, 
                          border_width = 1,
                          extend = extend.both, 
                          bgcolor = srcol))

resistancebroken = false
supportbroken = false

// check if it's not in a channel
not_in_a_channel = true
for x = 0 to min(9, maxnumsr)
    if close <= array.get(suportresistance, x * 2) and close >= array.get(suportresistance, x * 2 + 1) 
        not_in_a_channel := false

// if price is not in a channel then check broken ones
if not_in_a_channel
    for x = 0 to min(9, maxnumsr)
        if close[1] <= array.get(suportresistance, x * 2) and close > array.get(suportresistance, x * 2)
            resistancebroken := true
        if close[1] >= array.get(suportresistance, x * 2 + 1) and close < array.get(suportresistance, x * 2 + 1)
            supportbroken := true

alertcondition(resistancebroken, title = "Resistance Broken", message = "Resistance Broken")
alertcondition(supportbroken, title = "Support Broken", message = "Support Broken")
plotshape(showsrbroken and resistancebroken, style = shape.triangleup, location = location.belowbar, color = color.new(color.lime, 0), size = size.tiny)
plotshape(showsrbroken and supportbroken, style = shape.triangledown, location = location.abovebar, color = color.new(color.red, 0), size = size.tiny)

Overview

Support Resistance Channels groups nearby pivots into channels whose width is limited by a percentage of the recent high-low range, then draws up to a set number of channels on the price chart. Channels change color when price is inside them, and broken levels can be shown. Pivot period, source, minimum strength, and loopback control which levels qualify. Optional SMA or EMA lines and pivot labels can be plotted. It has no trade entries or exits.

Details

Published by

webcrack4 on GitHub

Code credit

LonesomeTheBlue, as written in the script's header

Type

Indicator, Pine Script v4

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
Pivot Periodint10sr_prd
SourcestringHigh/Lowppsrc
Maximum Channel Width %int5ChannelW
Minimum Strengthint1minstrength
Maximum Number of S/Rint6maxnumsr
Loopback Periodint290loopback
Resistance Colorcolorcolor.new(color.red, 75)res_col
Support Colorcolorcolor.new(color.lime, 75)sup_col
Color When Price in Channelcolorcolor.new(color.gray, 75)inch_col
Show Pivot Pointsboolfalseshowpp
Show Broken Support/Resistanceboolfalseshowsrbroken
MA 1boolfalseshowthema1en
Show all 17 settings
SettingTypeDefaultVariable
showthema1lenint50showthema1len
showthema1typestringSMAshowthema1type
MA 2boolfalseshowthema2en
showthema2lenint200showthema2len
showthema2typestringSMAshowthema2type
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

947 stars

Moving Average Channel plots separate simple moving averages for upper and lower bands on the price chart. It fills the space between bands with semi-transparent color and colors bars green above the upper band, red below the lower band, or gray in between. Us

Indicator v4 Moving averagesSupport & resistance
Updated 12 days ago · GPL-3.0 GitHub repository of Moving Average Channel

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows
330 stars

This indicator monitors multiple cryptocurrency symbols for trading signals. It calculates and plots entry prices, take profit, and stop loss levels for each symbol including BTCUSDT, ETHUSDT, BNBUSDT and others. Price crossovers trigger buy, sell or close ale

Indicator v5 Support & resistanceScreeners & dashboards
Updated 2 months ago · None stated GitHub repository of Multi Alert Long/Short [Alorse]

This overlay indicator draws a fixed-range volume profile on the price chart, splitting traded activity into up and down volume at each price level. It also plots a sentiment profile, a developing point of control, and value-area high and low around a configur

Indicator v5 VolumeSupport & resistance
Updated 2 months ago · MIT GitHub repository of Volume Profile and Indicator by DGT

BZ-tracker

by Allen1212
303 stars

The BZ-tracker indicator marks ARK Invest buy and sell transactions on stock charts with labels. It plots green labels for purchases and red labels for sales, each annotated with a multiplier such as X1 or X2 to show the number of ARK ETFs trading the stock on

Indicator v4 Support & resistanceScreeners & dashboards
Updated 2 years ago · None stated GitHub repository of BZ-tracker

Function - Linear Regression

by ricardosantos79
261 stars

This indicator fits a linear regression through stored pivot highs and lows and draws the resulting channel on the price chart. A function returns predicted values, maximum and minimum deviations, and the average absolute deviation. Confirmed two-bar pivots up

Indicator v5 TrendSupport & resistance
Updated 4 years ago · None stated GitHub repository of Function - Linear Regression

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