Indicator · Pine Script v6 · On the chart

Support and Resistance Logistic Regression | Flux Charts

by DarkNoah· code credited to fluxchart

This indicator detects pivot highs and lows, evaluates how often levels are respected by price, and uses an internal logistic regression model to estimate the probability that a level will hold.

View on GitHub

GitHub stars2on the repository
Pine versionv6current
Lines of code258
Settings16inputs
LicenceNone statedfile: MPL-2.0
Last updatetoday28 Oct 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

258 lines of Pine Script v6 from plugins/vibe-quant/web/indicators/main/logistic-sr/source.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

source.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © fluxchart
//
//@version=6

const bool DEBUG = false
const int retestCooldown = 3

indicator("Support and Resistance Logistic Regression | Flux Charts", shorttitle ="S&R (Logistic Regression) | Flux Charts",  overlay = true, max_lines_count = 500, max_labels_count = 500)

pivotLength = input.int(14, "Pivot Length", group = "General Configuration", tooltip = "This setting defines the number of bars used to determine a significant high or low for pivot detection.", minval=0,  display = display.none)
targetRespects = input.int(3, "Target Respects", group = "General Configuration", tooltip = "This input specifies how many times a level must be retested by price action for it to be considered a strong support or resistance level by the underlying model.\nHigher settings will result in less zones detected.", display = display.none)
probabilityThreshold = input.float(0.7, "Probability Threshold", step=0.05, minval=0.001, maxval=1., group = "General Configuration", tooltip = "This is the minimum probability output from the logistic regression model for a detected pivot to be considered a valid support or resistance level and be plotted on the chart.\nHigher settings will result in less zones rendered.", display = display.none)
hideFarLines = input.bool(true, "Hide Far Lines", group = "General Configuration")

showAllPivots = DEBUG ? input.bool(false, "[DBG] Show All Pivots", group = "General Configuration", display = display.none) : false
showRespectedPivots = DEBUG ? input.bool(false, "[DBG] Show Respected Pivots", group = "General Configuration", display = display.none) : false
showRegressionPivots = DEBUG ? input.bool(true, "[DBG] Show Regression Pivots", group = "General Configuration", display = display.none) : true

showPredictionLabels = input.bool(true, "Show Prediction Labels", group = "Style", display = display.none)
showRetests = input.bool(false, "Show Retests", group = "Style", display = display.none)
showBreaks = input.bool(false, "Show Breaks", group = "Style", display = display.none)
lineStyle = input.string("____", "    ", options = ["____", "----", "...."], group = "Style", inline = "s1", display = display.none)
lineWidth = input.int(3, "Width", [1,2,3], group = "Style", inline = "s1", display = display.none)
supportColor = input.color(#089981, "Lines & Labels", group = "Style", inline = "s2")
resistanceColor = input.color(#f23645, "", group = "Style", inline = "s2")
textColorSupport = input.color(color.white, "Text", group = "Style", inline = "s3")
textColorResistance = input.color(color.white, "", group = "Style", inline = "s3")

type srLine
    bool isSupport
    float level
    int startTime
    int startIndex
    int endTime
    int endIndex
    int timesRespected

    float detectedRSI
    float detectedBodySize
    bool detectedByRegression
    int latestRetestIndex = 0
    float detectedPrediction

    line srLine
    label predictionLabel

var allPivots = array.new<srLine>()
var respectedPivots = array.new<srLine>()
var regressionPivots = array.new<srLine>()

//#region Logistic Regression
const float lr = 0.008

logistic(x1, x2, y0, y1, y2, logisticTimes) =>
    exponent = math.exp(-(y0 + y1 * x1 + y2 * x2))
    logRtn = 1.0 / (1.0 + exponent)

    logRtn

loss(y, p) =>
    -y * math.log(p) - (1 - y) * math.log(1 - p)

predict(_isSupport, _level, _rsi, _bodySize) =>
    float baseBias = 1.0
    float rsiBias = 1.0
    float bodySizeBias = 1.0

    typeSize = 0
    for curRS in allPivots
        if curRS.isSupport == _isSupport
            typeSize += 1
    
    float _logRes = 0.0
    logisticTimes = 0

    if typeSize > 0
        for curRS in allPivots
            if curRS.isSupport != _isSupport
                continue
            
            isRespected = curRS.timesRespected >= targetRespects ? 1.0 : -1.0
            p = logistic(curRS.detectedRSI, curRS.detectedBodySize, baseBias, rsiBias, bodySizeBias, logisticTimes)
            logisticTimes += 1


            loss = loss(isRespected, p)

            rsiBias -= lr * (p + loss) * curRS.detectedRSI
            bodySizeBias -= lr * (p + loss) * curRS.detectedBodySize

            _logRes := logistic(_rsi, _bodySize, baseBias, rsiBias, bodySizeBias, logisticTimes)
            logisticTimes += 1
    
    _logRes
//#endregion

//#region Time By Bar
var timeByBar = array.new<int>()
if barstate.isconfirmed
    if timeByBar.size() == 0
        while timeByBar.size() != bar_index
            timeByBar.push(0)
    timeByBar.push(time)

getTimeByBar (barIndex) =>
    if timeByBar.size() <= barIndex
        time
    else
        timeByBar.get(barIndex)
//#endregion

pivotHigh = ta.pivothigh(pivotLength, pivotLength)
pivotLow = ta.pivotlow(pivotLength, pivotLength)

rsi = ta.rsi(close, pivotLength)
rsi := nz(rsi, 0)
bodySize = math.abs(close - open)

pivotTime = time[pivotLength]
pivotIndex = bar_index[pivotLength]
pivotRSI = rsi[pivotLength]
pivotBodySize = bodySize[pivotLength]

atr = ta.atr(pivotLength)

if (not na(pivotHigh))
    _pivotRSIBinary = pivotRSI > 50 ? 1 : -1
    _pivotBodySizeBinary = pivotBodySize > atr ? 1 : -1
    newPivot = srLine.new(false, pivotHigh, pivotTime, pivotIndex, na, na, 0, _pivotRSIBinary, _pivotBodySizeBinary)
    allPivots.push(newPivot)
    predVal = predict(false, pivotHigh, _pivotRSIBinary, _pivotBodySizeBinary)
    //label.new(pivotIndex, high, str.tostring(predVal))
    if predVal >= probabilityThreshold
        newPivot.detectedByRegression := true
        newPivot.detectedPrediction := predVal
        regressionPivots.push(newPivot)

if (not na(pivotLow))
    _pivotRSIBinary = pivotRSI > 50 ? 1 : -1
    _pivotBodySizeBinary = pivotBodySize > atr ? 1 : -1
    newPivot = srLine.new(true, pivotLow, pivotTime, pivotIndex, na, na, 0, _pivotRSIBinary, _pivotBodySizeBinary)
    allPivots.push(newPivot)
    predVal = predict(true, pivotLow, _pivotRSIBinary, _pivotBodySizeBinary)
    if predVal >= probabilityThreshold
        newPivot.detectedByRegression := true
        newPivot.detectedPrediction := predVal
        regressionPivots.push(newPivot)

updateSRLine (srLine sr) =>
    _retest = false
    _break = false
    if na(sr.endIndex)
        if sr.isSupport
            if low < sr.level
                if close > sr.level
                    if sr.detectedByRegression and bar_index > sr.latestRetestIndex + retestCooldown
                        _retest := true
                        sr.latestRetestIndex := bar_index
                        if showRetests
                            label.new(time, sr.level, "R", xloc = xloc.bar_time, yloc = yloc.belowbar, textcolor = textColorSupport, color = supportColor, style = label.style_label_up,  size=size.tiny)
                    sr.timesRespected += 1
                    if sr.timesRespected == targetRespects
                        respectedPivots.push(sr)
                else
                    if sr.detectedByRegression
                        _break := true
                        if showBreaks
                            label.new(time, sr.level, "B", xloc = xloc.bar_time, yloc = yloc.abovebar, textcolor = color.white, color = color.blue, style = label.style_label_down,  size=size.tiny)
                    sr.endIndex := bar_index
                    sr.endTime := time
        else
            if high > sr.level
                if close < sr.level
                    if sr.detectedByRegression and bar_index > sr.latestRetestIndex + retestCooldown
                        _retest := true
                        sr.latestRetestIndex := bar_index
                        if showRetests
                            label.new(time, sr.level, "R", xloc = xloc.bar_time, yloc = yloc.abovebar, textcolor = textColorResistance, color = resistanceColor, style = label.style_label_down,  size=size.tiny)
                    sr.timesRespected += 1
                    if sr.timesRespected == targetRespects
                        respectedPivots.push(sr)
                else
                    if sr.detectedByRegression
                        _break := true
                        if showBreaks
                            label.new(time, sr.level, "B", xloc = xloc.bar_time, yloc = yloc.belowbar, textcolor = color.white, color = color.blue, style = label.style_label_up,  size=size.tiny)
                    sr.endIndex := bar_index
                    sr.endTime := time
    [_retest, _break]

destroySRLine (srLine sr) =>
    line.delete(sr.srLine)
    sr.srLine := na
    label.delete(sr.predictionLabel)
    sr.predictionLabel := na

renderSRLine (srLine sr, string renderType) =>
    _shouldRender = true
    if hideFarLines and na(sr.endTime) and (math.abs(close - sr.level) > atr * 7)
        _shouldRender := false
    if _shouldRender
        _endTime = nz(sr.endTime, time)
        _endIndex = nz(sr.endIndex, bar_index)
        renderColor = sr.isSupport ? color.green : color.red
        if renderType == "Respected"
            renderColor := sr.isSupport ? color.yellow : color.purple
        if renderType == "Regression"
            renderColor := sr.isSupport ? supportColor : resistanceColor
        
        if na(sr.srLine)
            sr.srLine := line.new(sr.startTime, sr.level, _endTime, sr.level, xloc = xloc.bar_time, color = renderColor, width = lineWidth, style = lineStyle == "----" ? line.style_dashed : lineStyle == "____" ? line.style_solid : line.style_dotted)
            if showPredictionLabels
                if not sr.isSupport
                    sr.predictionLabel := label.new(sr.startTime, sr.level, str.tostring(sr.detectedPrediction * 100, format.percent), xloc = xloc.bar_time, textcolor = resistanceColor, color = color.new(color.white, 100), style = label.style_label_down)
                else
                    sr.predictionLabel := label.new(sr.startTime, sr.level, str.tostring(sr.detectedPrediction * 100, format.percent), xloc = xloc.bar_time, textcolor = supportColor, color = color.new(color.white, 100), style = label.style_label_up)
            sr.predictionLabel.set_x(na(sr.endIndex) ? getTimeByBar(_endIndex) : getTimeByBar((sr.startIndex + _endIndex) / 2))
        else
            sr.srLine.set_x2(_endTime)
            if showPredictionLabels
                sr.predictionLabel.set_x(na(sr.endIndex) ? getTimeByBar(_endIndex) : getTimeByBar((sr.startIndex + _endIndex) / 2))
    else
        destroySRLine(sr)
    true

_supportRetestDetected = false
_supportBreakDetected = false
_resistanceRetestDetected = false
_resistanceBreakDetected = false

if barstate.isconfirmed
    for curSR in allPivots
        [_retest, _break] = updateSRLine(curSR)
        if curSR.isSupport
            _supportRetestDetected := _retest ? true : _supportRetestDetected
            _supportBreakDetected := _break ? true : _supportBreakDetected
        else
            _resistanceRetestDetected := _retest ? true : _resistanceRetestDetected
            _resistanceBreakDetected := _break ? true : _resistanceBreakDetected
        if showAllPivots
            destroySRLine(curSR)
            renderSRLine(curSR, "All")

if barstate.islast
    if showRespectedPivots
        for curSR in respectedPivots
            destroySRLine(curSR)
            renderSRLine(curSR, "Respected")
    if showRegressionPivots
        for curSR in regressionPivots
            destroySRLine(curSR)
            renderSRLine(curSR, "Regression")

alertcondition(_supportRetestDetected, "Support Retest")
alertcondition(_resistanceRetestDetected, "Resistance Retest")
alertcondition(_supportBreakDetected, "Support Break")
alertcondition(_resistanceBreakDetected, "Resistance Break")

Overview

Qualifying support and resistance lines are projected onto the price chart alongside optional prediction labels, retest markers, and breakout highlights. Users can adjust the pivot length, target respect count, logistic probability threshold, and line visibility settings.

Details

Published by

DarkNoah on GitHub

Code credit

fluxchart, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Support & resistance, AI / machine learning

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 Lengthint14pivotLength
Target Respectsint3targetRespects
Probability Thresholdfloat0.7probabilityThreshold
Hide Far LinesbooltruehideFarLines
[DBG] Show All Pivotsboolfalse[DBG] Show All Pivots
[DBG] Show Respected Pivotsboolfalse[DBG] Show Respected Pivots
[DBG] Show Regression Pivotsbooltrue[DBG] Show Regression Pivots
Show Prediction LabelsbooltrueshowPredictionLabels
Show RetestsboolfalseshowRetests
Show BreaksboolfalseshowBreaks
string____lineStyle
Widthint3lineWidth
Show all 16 settings
SettingTypeDefaultVariable
Lines & Labelscolor#089981supportColor
resistanceColorcolor#f23645resistanceColor
Textcolorcolor.whitetextColorSupport
textColorResistancecolorcolor.whitetextColorResistance
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

Chandelier Flip Radar plots an ATR trailing stop on the price chart and tracks a directional trend state. It holds a ratchet stop until an accepted flip, using close or wick extremums and a body filter so weak breaks do not change direction. Distance to the fl

Indicator v6 TrendVolatility & bands
Updated yesterday · MIT GitHub repository of Chandelier Flip Radar [WavesUnchained]

ML KNN Predictor V2 Enhanced

by haydarkadioglu
1 stars

Calculates machine learning price predictions using a weighted K-Nearest Neighbors algorithm. It evaluates price position, trend, RSI, volatility, Fair Value Gaps, Support and Resistance levels, and volume to identify similar historical pattern matches. The in

Indicator v5 AI / machine learningSMC / ICT / price action
Updated 8 months ago · None stated GitHub repository of ML KNN Predictor V2 Enhanced

This indicator scans the chart for 101 distinct patterns, including single-bar, two-bar, and multi-bar candlestick patterns, classic chart patterns, and harmonic patterns. It features a complex situation context engine for confluence detection and displays a B

Indicator v5 Candlestick patternsSupport & resistance Repaints
948 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 10 days ago · GPL-3.0 GitHub repository of Moving Average Channel

More indicators

Trade Your Charts With a Regulated Broker

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

Compare brokers