Support and Resistance

Definition

When a security chart has no clear trend direction (upward or downward) and it rather moving in sideways, we can identify levels at which the security price hits high and low.

A support level is a price which the security usually hits while going downwards before going back up. The contrary is a resistance level, which is an upper limit price that security chart hits before changing direction and go back downwards.

Identifying Support & Resistance

If the security price bounces back at the approximate same level 2 or more times, this is considered a support/resistance level.

  • Support level chart:

as seen from the chart, the securtiy price has bounced back 2 time from approximately the same level. This level then is identified as a support level. As the price appraoches the same level again, we expect, it’s going to feel support and bounce back. So a buy decision (or long position) at this level is a good action.

  • Resistance level chart:

As seen in the chart, the price bounced back down after hitting the same approcimate “resistance” level two time. we expect for furhter hit of the same level, price will bounce back and decrease. Therefor a sell (or short position) at this price level is a good action.

Usage

For a security that has a sideways movement, price will fluctuate between a resistance and support level. Supports are a Buying levels while Resistances are selling levels.

However it must be kept in mind that resistance and support levels can be broken. There are no clear rules under what conditions are the support and resistance levels broken. But in the general case, support & resistance should be used with care.

Pine Script V6 Code

// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/

//@version=6

indicator('Support Resistance Channels', 'SRchannel', overlay = true, max_bars_back = 501)

prd = input.int(defval = 10, title = 'Pivot Period', minval = 4, maxval = 30, group = 'Settings 🔨', tooltip = 'Used while calculating Pivot Points, checks left&right bars')

ppsrc = input.string(defval = 'High/Low', title = 'Source', options = ['High/Low', 'Close/Open'], group = 'Settings 🔨', tooltip = 'Source for Pivot Points')

ChannelW = input.int(defval = 5, title = 'Maximum Channel Width %', minval = 1, maxval = 8, group = 'Settings 🔨', tooltip = 'Calculated using Highest/Lowest levels in 300 bars')

minstrength = input.int(defval = 1, title = 'Minimum Strength', minval = 1, group = 'Settings 🔨', tooltip = 'Channel must contain at least 2 Pivot Points')

maxnumsr = input.int(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.int(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.color(defval = color.new(color.red, 75), title = 'Resistance Color', group = 'Colors 🟡🟢🟣')

sup_col = input.color(defval = color.new(color.lime, 75), title = 'Support Color', group = 'Colors 🟡🟢🟣')

inch_col = input.color(defval = color.new(color.gray, 75), title = 'Color When Price in Channel', group = 'Colors 🟡🟢🟣')

showpp = input.bool(defval = false, title = 'Show Pivot Points', group = 'Extras ⏶⏷')

showsrbroken = input.bool(defval = false, title = 'Show Broken Support/Resistance', group = 'Extras ⏶⏷')

showthema1en = input.bool(defval = false, title = 'MA 1', inline = 'ma1')

showthema1len = input.int(defval = 50, title = '', inline = 'ma1')

showthema1type = input.string(defval = 'SMA', title = '', options = ['SMA', 'EMA'], inline = 'ma1')

showthema2en = input.bool(defval = false, title = 'MA 2', inline = 'ma2')

showthema2len = input.int(defval = 200, title = '', inline = 'ma2')

showthema2type = input.string(defval = 'SMA', title = '', options = ['SMA', 'EMA'], inline = 'ma2')


ma1 = showthema1en ? showthema1type == 'SMA' ? ta.sma(close, showthema1len) : ta.ema(close, showthema1len) : na

ma2 = showthema2en ? showthema2type == 'SMA' ? ta.sma(close, showthema2len) : ta.ema(close, showthema2len) : na


plot(ma1, color = not na(ma1) ? color.blue : na)

plot(ma2, color = not na(ma2) ? color.red : na)


// get Pivot High/low

float src1 = ppsrc == 'High/Low' ? high : math.max(close, open)

float src2 = ppsrc == 'High/Low' ? low : math.min(close, open)

float ph = ta.pivothigh(src1, prd, prd)

float pl = ta.pivotlow(src2, prd, prd)


// draw Pivot points

plotshape(bool(ph) and showpp, text = 'H', style = shape.labeldown, color = na, textcolor = color.new(color.red, 0), location = location.abovebar, offset = -prd)

plotshape(bool(pl) and showpp, text = 'L', style = shape.labelup, color = na, textcolor = color.new(color.lime, 0), location = location.belowbar, offset = -prd)


//calculate maximum S/R channel width

prdhighest = ta.highest(300)

prdlowest = ta.lowest(300)

cwidth = (prdhighest - prdlowest) * ChannelW / 100


// get/keep Pivot levels

var pivotvals = array.new_float(0)

var pivotlocs = array.new_float(0)

if bool(ph) or bool(pl)

    array.unshift(pivotvals, bool(ph) ? ph : pl)

    array.unshift(pivotlocs, bar_index)

    for x = array.size(pivotvals) - 1 to 0 by 1

        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 by 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 := math.min(lo, cpp)

                lo

            else

                hi := math.max(hi, cpp)

                hi


            numpp := numpp + 20 // each pivot point added as 20

            numpp

    [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 bool(ph) or bool(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 by 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 by 1

        h = array.get(supres, x * 3 + 1)

        l = array.get(supres, x * 3 + 2)

        s = 0

        for y = 0 to loopback by 1

            if high[y] <= h and high[y] >= l or low[y] <= h and low[y] >= l

                s := s + 1

                s

        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 by 1

        stv = -1. // value

        stl = -1 // location

        for y = 0 to array.size(pivotvals) - 1 by 1

            if array.get(supres, y * 3) > stv and array.get(supres, y * 3) >= minstrength * 20

                stv := array.get(supres, y * 3)

                stl := y

                stl

        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 by 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 := src + 1

            if src >= 10

                break


    for x = 0 to 8 by 1

        for y = x + 1 to 9 by 1

            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

    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

    ret


var srchannels = array.new_box(10)

for x = 0 to math.min(9, maxnumsr) by 1

    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 math.min(9, maxnumsr) by 1

    if close <= array.get(suportresistance, x * 2) and close >= array.get(suportresistance, x * 2 + 1)

        not_in_a_channel := false

        not_in_a_channel


// if price is not in a channel then check broken ones

if not_in_a_channel

    for x = 0 to math.min(9, maxnumsr) by 1

        if close[1] <= array.get(suportresistance, x * 2) and close > array.get(suportresistance, x * 2)

            resistancebroken := true

            resistancebroken

        if close[1] >= array.get(suportresistance, x * 2 + 1) and close < array.get(suportresistance, x * 2 + 1)

            supportbroken := true

            supportbroken


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)