Support and Resistance

A stock price chart with candlestick patterns showing support and resistance levels, marked by red lines and numbered blue labels.

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:

Line chart showing stock or financial data with support levels marked, indicated by horizontal base line labeled 'SUPPORT' and arrows pointing to support points.

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.

Forex trading chart showing fluctuating euro to US dollar exchange rate, with candlestick patterns and a horizontal resistance line near 1.2290.

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 - Support and Resistance

Snippet
// 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)

ThinkScript - Support and Resistance

Snippet

# Support Resistance Channels# Original: Support Resistance Channels declare upper; # Input Parametersinput pivotPeriod = 10; # "Pivot Period"input sourceType = {default "High/Low", "Close/Open"}; # "Source"input maxChannelWidthPct = 5; # "Maximum Channel Width %"input minStrength = 1; # "Minimum Strength"input maxNumSR = 6; # "Maximum Number of S/R"input loopbackPeriod = 290; # "Loopback Period" # Color inputsinput resistanceColor = Color.RED;input supportColor = Color.GREEN;input inChannelColor = Color.GRAY; # Display optionsinput showPivotPoints = no; # "Show Pivot Points"input showBrokenSR = no; # "Show Broken Support/Resistance" # Moving Average inputsinput showMA1 = no; # "Show MA 1"input ma1Length = 50; # "MA 1 Length"input ma1Type = {default SMA, EMA}; # "MA 1 Type" input showMA2 = no; # "Show MA 2"input ma2Length = 200; # "MA 2 Length"input ma2Type = {default SMA, EMA}; # "MA 2 Type" # Variables for pivot detectiondef src1 = if sourceType == sourceType."High/Low" then high else Max(close, open);def src2 = if sourceType == sourceType."High/Low" then low else Min(close, open); # Moving Averagesdef ma1Value = if showMA1 then (if ma1Type == ma1Type.SMA then SimpleMovingAvg(close, ma1Length) else ExpAverage(close, ma1Length)) else Double.NaN; def ma2Value = if showMA2 then (if ma2Type == ma2Type.SMA then SimpleMovingAvg(close, ma2Length) else ExpAverage(close, ma2Length)) else Double.NaN; plot MA1 = ma1Value;MA1.SetDefaultColor(Color.BLUE);MA1.SetHiding(!showMA1); plot MA2 = ma2Value;MA2.SetDefaultColor(Color.RED);MA2.SetHiding(!showMA2); # Pivot High/Low calculationdef pivotHigh = if high > Highest(src1[1], pivotPeriod) and high > Highest(src1[-pivotPeriod], -1) then high else Double.NaN;def pivotLow = if low < Lowest(src2[1], pivotPeriod) and low < Lowest(src2[-pivotPeriod], -1) then low else Double.NaN; # Show pivot pointsplot PivotHighPlot = if showPivotPoints and !IsNaN(pivotHigh) then pivotHigh else Double.NaN;PivotHighPlot.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);PivotHighPlot.SetDefaultColor(Color.RED);PivotHighPlot.SetLineWeight(2); plot PivotLowPlot = if showPivotPoints and !IsNaN(pivotLow) then pivotLow else Double.NaN;PivotLowPlot.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);PivotLowPlot.SetDefaultColor(Color.GREEN);PivotLowPlot.SetLineWeight(2); # Calculate maximum channel widthdef highest300 = Highest(high, 300);def lowest300 = Lowest(low, 300);def channelWidth = (highest300 - lowest300) * maxChannelWidthPct / 100; # Support/Resistance Level Calculations# Note: ThinkScript limitations require a simplified approach compared to the original Pine Script # Calculate recent pivot levels for S/Rdef recentPivotHigh1 = if !IsNaN(pivotHigh) then pivotHigh else recentPivotHigh1[1];def recentPivotHigh2 = if !IsNaN(pivotHigh) and pivotHigh != recentPivotHigh1 then recentPivotHigh1[1] else recentPivotHigh2[1];def recentPivotHigh3 = if !IsNaN(pivotHigh) and pivotHigh != recentPivotHigh1 and pivotHigh != recentPivotHigh2 then recentPivotHigh2[1] else recentPivotHigh3[1]; def recentPivotLow1 = if !IsNaN(pivotLow) then pivotLow else recentPivotLow1[1];def recentPivotLow2 = if !IsNaN(pivotLow) and pivotLow != recentPivotLow1 then recentPivotLow1[1] else recentPivotLow2[1];def recentPivotLow3 = if !IsNaN(pivotLow) and pivotLow != recentPivotLow1 and pivotLow != recentPivotLow2 then recentPivotLow2[1] else recentPivotLow3[1]; # Simplified S/R level identificationdef resistance1 = recentPivotHigh1;def resistance2 = recentPivotHigh2;def resistance3 = recentPivotHigh3; def support1 = recentPivotLow1;def support2 = recentPivotLow2;def support3 = recentPivotLow3; # Determine if price is in a channeldef inChannel1 = close <= resistance1 and close >= support1;def inChannel2 = close <= resistance2 and close >= support2;def inChannel3 = close <= resistance3 and close >= support3; def notInAnyChannel = !inChannel1 and !inChannel2 and !inChannel3; # Check for broken support/resistancedef resistanceBreak1 = close[1] <= resistance1 and close > resistance1 and notInAnyChannel;def supportBreak1 = close[1] >= support1 and close < support1 and notInAnyChannel; def resistanceBreak2 = close[1] <= resistance2 and close > resistance2 and notInAnyChannel;def supportBreak2 = close[1] >= support2 and close < support2 and notInAnyChannel; def anyResistanceBreak = resistanceBreak1 or resistanceBreak2;def anySupportBreak = supportBreak1 or supportBreak2; # Plot Support/Resistance levelsplot Resistance1Line = if !IsNaN(resistance1) and resistance1 > 0 then resistance1 else Double.NaN;plot Support1Line = if !IsNaN(support1) and support1 > 0 then support1 else Double.NaN; plot Resistance2Line = if !IsNaN(resistance2) and resistance2 > 0 then resistance2 else Double.NaN;plot Support2Line = if !IsNaN(support2) and support2 > 0 then support2 else Double.NaN; plot Resistance3Line = if !IsNaN(resistance3) and resistance3 > 0 then resistance3 else Double.NaN;plot Support3Line = if !IsNaN(support3) and support3 > 0 then support3 else Double.NaN; # Set colors based on position relative to priceResistance1Line.SetDefaultColor(if close < resistance1 then resistanceColor else inChannelColor);Support1Line.SetDefaultColor(if close > support1 then supportColor else inChannelColor); Resistance2Line.SetDefaultColor(if close < resistance2 then resistanceColor else inChannelColor);Support2Line.SetDefaultColor(if close > support2 then supportColor else inChannelColor); Resistance3Line.SetDefaultColor(if close < resistance3 then resistanceColor else inChannelColor);Support3Line.SetDefaultColor(if close > support3 then supportColor else inChannelColor); # Set line stylesResistance1Line.SetStyle(Curve.LONG_DASH);Support1Line.SetStyle(Curve.LONG_DASH);Resistance2Line.SetStyle(Curve.SHORT_DASH);Support2Line.SetStyle(Curve.SHORT_DASH);Resistance3Line.SetStyle(Curve.POINTS);Support3Line.SetStyle(Curve.POINTS); # Plot broken S/R signalsplot ResistanceBreakSignal = if showBrokenSR and anyResistanceBreak then low else Double.NaN;ResistanceBreakSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);ResistanceBreakSignal.SetDefaultColor(Color.GREEN);ResistanceBreakSignal.SetLineWeight(2); plot SupportBreakSignal = if showBrokenSR and anySupportBreak then high else Double.NaN;SupportBreakSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);SupportBreakSignal.SetDefaultColor(Color.RED);SupportBreakSignal.SetLineWeight(2); # AlertsAlert(anyResistanceBreak, "Resistance Broken", Alert.BAR, Sound.Ding);Alert(anySupportBreak, "Support Broken", Alert.BAR, Sound.Ring); # Add labels for identificationAddLabel(yes, "SR Channels: " + maxNumSR + " levels", Color.GRAY); # Cloud between S/R levels for better visualizationAddCloud(Resistance1Line, Support1Line, if inChannel1 then CreateColor(128, 128, 128) else Color.CURRENT, CreateColor(0, 0, 0)); AddCloud(Resistance2Line, Support2Line, if inChannel2 then CreateColor(100, 100, 100) else Color.CURRENT, CreateColor(0, 0, 0)); AddCloud(Resistance3Line, Support3Line, if inChannel3 then CreateColor(75, 75, 75) else Color.CURRENT, CreateColor(0, 0, 0));