Indicator · Pine Script v6 · On the chart

Zigzag Impulse Stats

by northis

Zigzag Impulse Stats calculates statistical metrics across dynamic zigzag segments overlayed on the price chart.

View on GitHub

Repaints

GitHub stars3on the repository
Pine versionv6current
Lines of code558
Settings30inputs
LicenceMIT
Last update3 days ago25 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

558 lines of Pine Script v6 from PineScript/ZigzagImpulseStats.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

ZigzagImpulseStats.pine
//@version=6
indicator("Zigzag Impulse Stats", overlay = true, max_lines_count = 500, max_labels_count = 500, max_bars_back = 5000)

if barstate.isfirst
    log.warning("Zigzag Impulse Stats initialized. Collecting data...")

// ═══════════════════════════════════════════════════════════════
// Zigzag Settings
// ═══════════════════════════════════════════════════════════════
float devStart   = input.float(0.1, "Deviation Start (%)", minval = 0.00001, maxval = 100.0, step = 0.1, group = "Zigzag")
float devEnd     = input.float(0.5, "Deviation End (%)", minval = 0.00001, maxval = 100.0, step = 0.1, group = "Zigzag")
float devStep    = input.float(0.1, "Deviation Step (%)", minval = 0.00001, maxval = 100.0, step = 0.1, group = "Zigzag")
int   depthInput = input.int(10, "Depth", minval = 2, group = "Zigzag")
color lineClr    = input.color(#2962FF, "Line color", group = "Zigzag")
bool  extLast    = input.bool(true, "Extend to last bar", group = "Zigzag")
int   maxSegBars = input.int(2000, "Max bars per segment (timeout limit)", minval = 10, group = "Display")

bool  showRZ     = input.bool(true, "Show Ratio Zigzag (rz)", group = "Metrics")
bool  showZD     = input.bool(true, "Show Zigzag Depth (zd)", group = "Metrics")
bool  showH      = input.bool(true, "Show Heterogeneity (h)", group = "Metrics")
bool  showUnif   = input.bool(true, "Show Uniformity (unif)", group = "Metrics")
bool  showDevLine= input.bool(true, "Show Dev Line (devL)", group = "Metrics")
bool  showDevCand= input.bool(true, "Show Dev Candle (devC)", group = "Metrics")
bool  showArea   = input.bool(true, "Show Envelope Area (area)", group = "Metrics")

// ═══════════════════════════════════════════════════════════════
// Impulse Mode
// ═══════════════════════════════════════════════════════════════
bool  impulseMode   = input.bool(false, "Enable Impulse Mode", group = "Impulse Mode", tooltip = "If enabled, only segments satisfying the conditions below are highlighted as impulses")
int   impMinBars    = input.int(10, "Min bars in segment", minval = 1, maxval = 300, group = "Impulse Mode")

bool  impUseRZ      = input.bool(true, "Filter by RZ <", group = "Impulse Mode", inline = "irz")
int   impThreshRZ   = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "irz")

bool  impUseZD      = input.bool(true, "Filter by ZD <", group = "Impulse Mode", inline = "izd")
int   impThreshZD   = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "izd")

bool  impUseH       = input.bool(true, "Filter by H <", group = "Impulse Mode", inline = "ih")
int   impThreshH    = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "ih")

bool  impUseUnif    = input.bool(true, "Filter by Unif <", group = "Impulse Mode", inline = "iunif")
int   impThreshUnif = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "iunif")

bool  impUseDevL    = input.bool(true, "Filter by DevL <", group = "Impulse Mode", inline = "idevl")
int   impThreshDevL = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "idevl")

bool  impUseDevC    = input.bool(true, "Filter by DevC <", group = "Impulse Mode", inline = "idevc")
int   impThreshDevC = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "idevc")

bool  impUseArea    = input.bool(true, "Filter by Area <", group = "Impulse Mode", inline = "iarea")
int   impThreshArea = input.int(30, "", minval = 0, maxval = 100, group = "Impulse Mode", inline = "iarea")

// ═══════════════════════════════════════════════════════════════
// Calculation Functions
// ═══════════════════════════════════════════════════════════════
getCross(float x1, float y1, float x2, float y2, float x3, float y3) =>
    float dx1 = x2 - x1
    float dy1 = y2 - y1
    float dx2 = x3 - x2
    float dy2 = y3 - y2
    dx1 * dy2 - dy1 * dx2

update_envelope(array<float> upX, array<float> upY, array<float> dnX, array<float> dnY, float idx, float h, float l) =>
    while array.size(upX) >= 2
        int sz = array.size(upX)
        if getCross(array.get(upX, sz - 2), array.get(upY, sz - 2), array.get(upX, sz - 1), array.get(upY, sz - 1), idx, h) >= 0
            array.pop(upX)
            array.pop(upY)
        else
            break
    array.push(upX, idx)
    array.push(upY, h)
    
    while array.size(dnX) >= 2
        int sz = array.size(dnX)
        if getCross(array.get(dnX, sz - 2), array.get(dnY, sz - 2), array.get(dnX, sz - 1), array.get(dnY, sz - 1), idx, l) <= 0
            array.pop(dnX)
            array.pop(dnY)
        else
            break
    array.push(dnX, idx)
    array.push(dnY, l)

calc_area_metric(array<float> upX, array<float> upY, array<float> dnX, array<float> dnY, float startPrice, float endPrice, int duration) =>
    float stat_area = 0.0
    float fullLen = math.abs(endPrice - startPrice)
    if fullLen > 1e-10
        float upArea = 0.0
        if array.size(upX) > 1
            for i = 1 to array.size(upX) - 1
                upArea += (array.get(upX, i) - array.get(upX, i - 1)) * (array.get(upY, i - 1) + array.get(upY, i)) / 2.0
        float dnArea = 0.0
        if array.size(dnX) > 1
            for i = 1 to array.size(dnX) - 1
                dnArea += (array.get(dnX, i) - array.get(dnX, i - 1)) * (array.get(dnY, i - 1) + array.get(dnY, i)) / 2.0
        float sumArea = upArea - dnArea
        float maxArea = fullLen * duration
        if maxArea > 1e-10
            stat_area := math.max(0.0, math.min(sumArea / maxArea, 1.0))
    stat_area

calc_heterogeneity(int startIndex, int duration, float minP, float maxP) =>
    float diffPart = 1.0
    float rangeP = maxP - minP
    if rangeP > 1e-10
        int BINS = 10
        array<int> bins = array.new<int>(BINS, 0)
        float binSize = rangeP / BINS
        
        for step = 0 to duration
            int bIdx = startIndex + step
            float l = low[bar_index - bIdx]
            float h = high[bar_index - bIdx]
            
            int startBin = math.max(0, math.min(int((l - minP) / binSize), BINS - 1))
            int endBin   = math.max(0, math.min(int((h - minP) / binSize), BINS - 1))
            for b = startBin to endBin
                array.set(bins, b, array.get(bins, b) + 1)
                
        int firstThird = array.get(bins, 0) + array.get(bins, 1) + array.get(bins, 2)
        int lastThird  = array.get(bins, 7) + array.get(bins, 8) + array.get(bins, 9)
        int whole = 0
        for b = 0 to BINS - 1
            whole += array.get(bins, b)
        if whole > 0
            diffPart := math.abs(firstThird - lastThird) / float(whole)
    diffPart

calc_rz_metric(array<float> L, array<float> H, int duration) =>
    float stat_rz = na
    if duration > 0
        int maxExtremaBarCount = 0
        array<int> stack = array.new<int>() // Monotonic stack of increasing L values
        
        for i = 0 to duration
            float l_i = array.get(L, i)
            
            // Maintain stack
            while array.size(stack) > 0
                int top_idx = array.get(stack, array.size(stack) - 1)
                if array.get(L, top_idx) > l_i
                    array.pop(stack)
                else
                    break
            array.push(stack, i)
            
            if i <= maxExtremaBarCount
                continue
                
            float h_i = array.get(H, i)
            float l_min = h_i
            bool found = false
            
            if i < duration
                for j = i + 1 to duration
                    float l_j = array.get(L, j)
                    if h_i < l_j
                        break
                    if l_j < l_min
                        l_min := l_j
                        found := true
                    
            if found
                // Binary search on monotonic stack instantly finds the break index backward!
                int low_idx = 0
                int high_idx = array.size(stack) - 1
                int best_k = -1
                
                while low_idx <= high_idx
                    int mid_idx = low_idx + int((high_idx - low_idx) / 2)
                    int stack_val_idx = array.get(stack, mid_idx)
                    float s_val = array.get(L, stack_val_idx)
                    
                    if s_val <= l_min
                        best_k := stack_val_idx
                        low_idx := mid_idx + 1
                    else
                        high_idx := mid_idx - 1
                        
                int count = best_k != -1 ? (i - best_k) : (i + 1)
                if count > maxExtremaBarCount
                    maxExtremaBarCount := count
                    
        stat_rz := maxExtremaBarCount / float(duration)
    stat_rz

calc_uniformity(int startIndex, int duration) =>
    float stat_unif = 0.0
    if duration > 0
        array<float> points = array.new<float>()
        // Collect all H and L
        for step = 0 to duration
            int bIdx = startIndex + step
            float cL = low[bar_index - bIdx]
            float cH = high[bar_index - bIdx]
            array.push(points, cL)
            array.push(points, cH)
        
        array.sort(points)
        
        // Unique intervals and calculate counts
        float currentPoint = array.get(points, 0)
        float sumCounts = 0.0
        float maxCount = 0.0
        int validIntervals = 0
        
        for i = 1 to array.size(points) - 1
            float nextPoint = array.get(points, i)
            if nextPoint - currentPoint > 1e-10
                float localMin = currentPoint
                float localMax = nextPoint
                
                int cdlCount = 0
                for step = 0 to duration
                    int bIdx = startIndex + step
                    float cL = low[bar_index - bIdx]
                    float cH = high[bar_index - bIdx]
                    if cL <= localMin + 1e-10 and cH >= localMax - 1e-10
                        cdlCount += 1
                
                if cdlCount == 0
                    cdlCount := 1
                    
                sumCounts += cdlCount
                if cdlCount > maxCount
                    maxCount := cdlCount
                validIntervals += 1
                
                currentPoint := nextPoint
                
        if validIntervals > 0 and maxCount > 0
            float n = sumCounts / validIntervals
            float m = maxCount
            stat_unif := 1.0 - (n / m)
            
    stat_unif

calc_zd_metric(array<float> L, array<float> H, int duration, float totalRange) =>
    float stat_zd = 0.0
    if duration > 0 and totalRange > 1e-10
        float max_depth = 0.0
        for i = 0 to duration
            float h_i = array.get(H, i)
            float local_max_depth = 0.0
            if i < duration
                for j = i + 1 to duration
                    float l_j = array.get(L, j)
                    if h_i < l_j
                        break
                    float depth = h_i - l_j
                    if depth > local_max_depth
                        local_max_depth := depth
            if local_max_depth > max_depth
                max_depth := local_max_depth
        stat_zd := max_depth / totalRange
    stat_zd

calc_all_stats(int startIndex, float startPrice, int endIndex, float endPrice, bool calcRZ, bool calcH, bool calcUnif, bool calcDevLine, bool calcDevCand, bool calcArea, bool calcZD) =>
    bool isUp = endPrice > startPrice
    int duration = endIndex - startIndex
    
    float stat_rz = na
    float stat_hMax = na
    float stat_unif = na
    float stat_devLine = na
    float stat_devCand = na
    float stat_area = na
    float stat_zd = na

    if duration > 0
        float minP = math.min(startPrice, endPrice)
        float maxP = math.max(startPrice, endPrice)
        float totalRange = math.abs(endPrice - startPrice)
        float maxDistanceLine = 0.0
        float maxDistanceCand = 0.0

        array<float> L = (calcRZ or calcZD) ? array.new<float>(duration + 1) : na
        array<float> H = (calcRZ or calcZD) ? array.new<float>(duration + 1) : na
        
        array<float> movementExtrema = calcDevCand ? array.new<float>(duration + 1) : na
        array<float> devCLs = calcDevCand ? array.new<float>(duration + 1) : na
        array<float> devCHs = calcDevCand ? array.new<float>(duration + 1) : na

        array<float> upX = calcArea ? array.new<float>() : na
        array<float> upY = calcArea ? array.new<float>() : na
        array<float> dnX = calcArea ? array.new<float>() : na
        array<float> dnY = calcArea ? array.new<float>() : na

        // --- SINGLE PASS: GATHER DATA & ON-THE-FLY ALGORITHMS ---
        for step = 0 to duration
            int bIdx = startIndex + step
            float cL = low[bar_index - bIdx]
            float cH = high[bar_index - bIdx]
            
            minP := math.min(minP, cL)
            maxP := math.max(maxP, cH)

            if calcRZ or calcZD
                float rzL = cL
                float rzH = cH
                if not isUp
                    rzL := -cH
                    rzH := -cL
                array.set(L, step, rzL)
                array.set(H, step, rzH)
                
            if calcDevCand
                array.set(devCLs, step, cL)
                array.set(devCHs, step, cH)
                float movementExtremum = isUp ? cH : cL
                array.set(movementExtrema, step, movementExtremum)

            if calcDevLine and step > 0 and step < duration and totalRange > 1e-10
                float t = step / float(duration)
                float lineValue = startPrice + (endPrice - startPrice) * t
                float distHigh = math.abs(cH - lineValue)
                float distLow  = math.abs(cL - lineValue)
                float dist = math.max(distHigh, distLow)
                if dist > maxDistanceLine
                    maxDistanceLine := dist

            if calcArea
                float h = cH
                float l = cL
                if step == 0
                    h := startPrice
                    l := startPrice
                if step == duration
                    h := endPrice
                    l := endPrice
                    
                update_envelope(upX, upY, dnX, dnY, float(startIndex + step), h, l)

        // --- CALC RESULTS ---
        if calcDevLine
            stat_devLine := totalRange > 1e-10 ? math.min(maxDistanceLine / totalRange, 1.0) : 0.0

        if calcDevCand
            if duration > 1 and totalRange > 1e-10
                for step = 1 to duration - 1
                    float candleExtremum = isUp ? array.get(devCLs, step) : array.get(devCHs, step)
                    float dist = 1e10
                    for j = 0 to duration
                        float d = math.abs(array.get(movementExtrema, j) - candleExtremum)
                        if d < dist
                            dist := d
                    if dist > maxDistanceCand
                        maxDistanceCand := dist
            stat_devCand := totalRange > 1e-10 ? math.min(maxDistanceCand / totalRange, 1.0) : 0.0

        if calcArea
            stat_area := calc_area_metric(upX, upY, dnX, dnY, startPrice, endPrice, duration)

        if calcH
            stat_hMax := calc_heterogeneity(startIndex, duration, minP, maxP)
            
        if calcUnif
            stat_unif := calc_uniformity(startIndex, duration)

        if calcRZ
            stat_rz := calc_rz_metric(L, H, duration)

        if calcZD
            stat_zd := calc_zd_metric(L, H, duration, totalRange)

    [stat_rz, stat_hMax, stat_unif, stat_devLine, stat_devCand, stat_area, stat_zd]

// ═══════════════════════════════════════════════════════════════
// ZigZag Type & Methods
// ═══════════════════════════════════════════════════════════════
type ZigZag
    float dev
    color clr
    array<float> price
    array<int> bar
    array<bool> isHigh
    array<line> lines
    array<label> labels
    label liveLabel
    line extLine

method draw_segment_label(ZigZag zz, int sBar, float sPrc, int eBar, float ePrc, line ln, int barDiff, bool isLive) =>
    bool doCalcRZ   = showRZ or (impulseMode and impUseRZ)
    bool doCalcZD   = showZD or (impulseMode and impUseZD)
    bool doCalcH    = showH or (impulseMode and impUseH)
    bool doCalcUnif = showUnif or (impulseMode and impUseUnif)
    bool doCalcDevL = showDevLine or (impulseMode and impUseDevL)
    bool doCalcDevC = showDevCand or (impulseMode and impUseDevC)
    bool doCalcArea = showArea or (impulseMode and impUseArea)

    [stat_rz, stat_hMax, stat_unif, stat_devLine, stat_devCand, stat_area, stat_zd] = calc_all_stats(sBar, sPrc, eBar, ePrc, doCalcRZ, doCalcH, doCalcUnif, doCalcDevL, doCalcDevC, doCalcArea, doCalcZD)

    bool isImpulse = true
    if impulseMode
        if barDiff < impMinBars
            isImpulse := false
        if impUseRZ and (stat_rz * 100 >= impThreshRZ)
            isImpulse := false
        if impUseZD and (stat_zd * 100 >= impThreshZD)
            isImpulse := false
        if impUseH and (stat_hMax * 100 >= impThreshH)
            isImpulse := false
        if impUseUnif and (stat_unif * 100 >= impThreshUnif)
            isImpulse := false
        if impUseDevL and (stat_devLine * 100 >= impThreshDevL)
            isImpulse := false
        if impUseDevC and (stat_devCand * 100 >= impThreshDevC)
            isImpulse := false
        if impUseArea and (stat_area * 100 >= impThreshArea)
            isImpulse := false

    if impulseMode
        if isImpulse
            line.set_color(ln, zz.clr)
            line.set_width(ln, 3)
        else
            line.set_color(ln, color.new(zz.clr, 80))
            line.set_width(ln, 1)
    else
        line.set_color(ln, zz.clr)
        line.set_width(ln, 2)

    label lb = na
    if not impulseMode or isImpulse
        array<string> lines = array.new<string>()
        array.push(lines, "[" + str.tostring(math.round(zz.dev, 2)) + "%]")
        if showRZ
            array.push(lines, "rz: " + str.tostring(int(stat_rz * 100)))
        if showZD
            array.push(lines, "zd: " + str.tostring(int(stat_zd * 100)))
        if showH
            array.push(lines, "h: " + str.tostring(int(stat_hMax * 100)))
        if showUnif
            array.push(lines, "unif: " + str.tostring(int(stat_unif * 100)))
        if showDevLine
            array.push(lines, "devL: " + str.tostring(int(stat_devLine * 100)))
        if showDevCand
            array.push(lines, "devC: " + str.tostring(int(stat_devCand * 100)))
        if showArea
            array.push(lines, "area: " + str.tostring(int(stat_area * 100)))

        string txt = array.join(lines, "\n")
        
        if txt != ""
            string lblStyle = ePrc > sPrc ? label.style_label_down : label.style_label_up
            lb := label.new(eBar, ePrc, txt, xloc = xloc.bar_index, style = lblStyle, color = color.new(color.blue, 30), textcolor = color.white, size = size.normal)
            if not isLive
                zz.labels.push(lb)
    lb

method process_unfinalized_segment(ZigZag zz) =>
    int _dummy = 0
    int n = zz.price.size()
    if n >= 2
        int sBar = zz.bar.get(n - 2)
        int eBar = zz.bar.get(n - 1)
        float sPrc = zz.price.get(n - 2)
        float ePrc = zz.price.get(n - 1)
        line ln = zz.lines.get(n - 2)
        
        if not na(zz.liveLabel)
            label.delete(zz.liveLabel)
            zz.liveLabel := na
            
        int age = bar_index - sBar
        int barDiff = math.abs(eBar - sBar)
        if age <= 4500 and barDiff <= maxSegBars
            zz.liveLabel := zz.draw_segment_label(sBar, sPrc, eBar, ePrc, ln, barDiff, true)
        _dummy := 1

method finalize_segment(ZigZag zz) =>
    int _dummy = 0
    int n = zz.price.size()
    if n >= 2
        int sBar = zz.bar.get(n - 2)
        int eBar = zz.bar.get(n - 1)
        float sPrc = zz.price.get(n - 2)
        float ePrc = zz.price.get(n - 1)
        line ln = zz.lines.get(n - 2)
        
        if not na(zz.liveLabel)
            label.delete(zz.liveLabel)
            zz.liveLabel := na
            
        int age = bar_index - sBar
        int barDiff = math.abs(eBar - sBar)
        if age <= 4500 and barDiff <= maxSegBars
            zz.draw_segment_label(sBar, sPrc, eBar, ePrc, ln, barDiff, false)
        _dummy := 1

method update_zigzag(ZigZag zz, float pivotPrice, int pivBar, bool isHigh) =>
    int _dummy = 0
    int n = zz.price.size()
    if n == 0
        zz.price.push(pivotPrice)
        zz.bar.push(pivBar)
        zz.isHigh.push(isHigh)
        _dummy := 1
    else
        bool lastIsHigh = zz.isHigh.get(n - 1)
        float lastPrice = zz.price.get(n - 1)

        if lastIsHigh == isHigh
            if (isHigh and pivotPrice > lastPrice) or (not isHigh and pivotPrice < lastPrice)
                zz.price.set(n - 1, pivotPrice)
                zz.bar.set(n - 1, pivBar)
                if zz.lines.size() > 0
                    zz.lines.get(zz.lines.size() - 1).set_xy2(pivBar, pivotPrice)
                zz.process_unfinalized_segment()
            _dummy := 2
        else
            float dev = 100.0 * (pivotPrice - lastPrice) / math.abs(lastPrice)
            bool validDev = isHigh ? (dev >= zz.dev) : (dev <= -zz.dev)
            if validDev
                zz.finalize_segment()
                zz.price.push(pivotPrice)
                zz.bar.push(pivBar)
                zz.isHigh.push(isHigh)
                line ln = line.new(zz.bar.get(zz.bar.size() - 2), zz.price.get(zz.price.size() - 2), pivBar, pivotPrice, color = zz.clr, width = 2)
                zz.lines.push(ln)
                zz.process_unfinalized_segment()
            _dummy := 3

// ═══════════════════════════════════════════════════════════════
// Zigzag Execution
// ═══════════════════════════════════════════════════════════════
var array<ZigZag> zigzags = array.new<ZigZag>()
if barstate.isfirst
    float d = devStart
    float step = devStep > 0 ? devStep : 0.1
    int count = 0
    while d <= devEnd + 0.00001 and count < 20
        zigzags.push(ZigZag.new(d, lineClr, array.new<float>(), array.new<int>(), array.new<bool>(), array.new<line>(), array.new<label>(), na, na))
        d += step
        count += 1

int depth = depthInput < 4 ? 2 : int(depthInput / 2)

float ph = ta.pivothigh(high, depth, depth)
float pl = ta.pivotlow(low, depth, depth)

if not na(ph)
    for zz in zigzags
        zz.update_zigzag(ph, bar_index - depth, true)

if not na(pl)
    for zz in zigzags
        zz.update_zigzag(pl, bar_index - depth, false)

if extLast and barstate.islast
    for zz in zigzags
        int n = zz.price.size()
        if n > 0
            if not na(zz.extLine)
                line.delete(zz.extLine)
            bool lastIsHigh = zz.isHigh.get(n - 1)
            float curPrice  = lastIsHigh ? low : high
            zz.extLine := line.new(zz.bar.get(n - 1), zz.price.get(n - 1), bar_index, curPrice, color = zz.clr, width = 2, style = line.style_dashed)

Overview

Zigzag Impulse Stats measures segment ratio, depth, heterogeneity, uniformity, trendline deviation, candle deviations, and envelope area. An optional Impulse Mode highlights valid impulse movements based on customizable threshold filters for each metric. Users can configure deviation settings, depth parameters, and toggle individual statistical metrics on or off. Note that because this script relies on zigzag pivot detection, line endpoints repaint on unconfirmed active bars until a new swing point is confirmed.

Details

Published by

northis on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Trend, Support & resistance

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • Signals can change on the live bar or after it closes (repainting)

Settings

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

SettingTypeDefaultVariable
Deviation Start (%)float0.1devStart
Deviation End (%)float0.5devEnd
Deviation Step (%)float0.1devStep
Depthint10depthInput
Line colorcolor#2962FFlineClr
Extend to last barbooltrueextLast
Max bars per segment (timeout limit)int2000maxSegBars
Show Ratio Zigzag (rz)booltrueshowRZ
Show Zigzag Depth (zd)booltrueshowZD
Show Heterogeneity (h)booltrueshowH
Show Uniformity (unif)booltrueshowUnif
Show Dev Line (devL)booltrueshowDevLine
Show all 30 settings
SettingTypeDefaultVariable
Show Dev Candle (devC)booltrueshowDevCand
Show Envelope Area (area)booltrueshowArea
Enable Impulse ModeboolfalseimpulseMode
Min bars in segmentint10impMinBars
Filter by RZ <booltrueimpUseRZ
impThreshRZint30impThreshRZ
Filter by ZD <booltrueimpUseZD
impThreshZDint30impThreshZD
Filter by H <booltrueimpUseH
impThreshHint30impThreshH
Filter by Unif <booltrueimpUseUnif
impThreshUnifint30impThreshUnif
Filter by DevL <booltrueimpUseDevL
impThreshDevLint30impThreshDevL
Filter by DevC <booltrueimpUseDevC
impThreshDevCint30impThreshDevC
Filter by Area <booltrueimpUseArea
impThreshAreaint30impThreshArea
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

575 stars

This indicator detects equal highs and lows by comparing prices within user-defined left and right bars using a tolerance percentage. It plots horizontal lines on the price chart for equal highs in one color and lows in another. A screener allows input of mult

Indicator v5 Support & resistanceTrend
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows with Screener

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

AI Trend

by dearvn
257 stars

AI Trend is an indicator that plots pivot points, trend lines, and support and resistance levels directly on the price chart. It marks high and low pivots based on user-defined length, draws trend lines that check for violations at specified points, and identi

Indicator v5 TrendSupport & resistance
Updated 6 weeks ago · None stated GitHub repository of AI Trend

Ichimoku Cloud

by harryguiacorn
219 stars

This indicator plots Ichimoku Cloud elements on the price chart, including Tenkan-sen, Kijun-sen, Senkou Span A and B lines with optional Chikou Span. It signals trend changes via Tenkan-sen and Kijun-sen crosses and places arrows at Kijun-sen direction shifts

Indicator v5 TrendMoving averages
Updated 1 year ago · None stated GitHub repository of Ichimoku Cloud
219 stars

This indicator identifies local swing highs and swing lows to construct a Zig Zag pattern on the main price chart. It evaluates pivot points based on a customizable number of surrounding left and right bars. Using persistent variables, the script tracks previo

Indicator v4 Support & resistanceTrend Repaints
Updated 5 years ago · None stated GitHub repository of Teaching: Finding Highs and Lows 6

Dynamic Linear Regression

by TradersPost
218 stars

Dynamic Linear Regression calculates and plots linear regression trendlines and standard deviation channels directly on the price chart over a user-selected time period. Traders can configure static channels locked at the end time, dynamic channels that contin

Indicator v6 TrendSupport & resistance
Updated 3 months ago · None stated GitHub repository of Dynamic Linear Regression

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