Indicator · Pine Script v5 · On the chart

Zig Zag

by TWODS-CAPITAL

This overlay indicator draws a zigzag of confirmed swing highs and lows on the price chart.

View on GitHub

Repaints

GitHub stars37on the repository
Pine versionv5runs as is
Lines of code175
Settings8inputs
LicenceMIT
Last update3 years ago10 Feb 2023

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

175 lines of Pine Script v5 from Technical-Indicators/Technical Indicators are Here🤩/Zig-Zag.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Zig-Zag.pine
//@version=5
indicator("Zig Zag", overlay=true, max_lines_count=500, max_labels_count=500)
dev_threshold = input.float(title="Deviation (%)", defval=5.0, minval=0.00001, maxval=100.0)
depth = input.int(title="Depth", defval=10, minval=1)
line_color = input(title="Line Color", defval=#2962FF)
extend_to_last_bar = input(title="Extend to Last Bar", defval=true)
display_reversal_price = input(title="Display Reversal Price", defval=true)
display_cumulative_volume = input(title="Display Cumulative Volume", defval=true)
display_reversal_price_change = input(title="Display Reversal Price Change", defval=true, inline="price rev")
difference_price = input.string("Absolute", "", options=["Absolute", "Percent"], inline="price rev")

pivots(src, length, isHigh) =>
    p = nz(src[length])
    if length == 0
        [time, p]
    else
        isFound = true
        for i = 0 to math.abs(length - 1)
            if isHigh and src[i] > p
                isFound := false
            if not isHigh and src[i] < p
                isFound := false
        for i = length + 1 to 2 * length
            if isHigh and src[i] >= p
                isFound := false
            if not isHigh and src[i] <= p
                isFound := false
        if isFound and length * 2 <= bar_index
            [time[length], p]
        else
            [int(na), float(na)]

[iH, pH] = pivots(high, math.floor(depth / 2), true)
[iL, pL] = pivots(low, math.floor(depth / 2), false)

calc_dev(base_price, price) =>
    100 * (price - base_price) / base_price

price_rotation_aggregate(price_rotation, pLast, cum_volume) =>
    str = ""
    if display_reversal_price
        str += str.tostring(pLast, format.mintick) + " "
    if display_reversal_price_change
        str += price_rotation + " "
    if display_cumulative_volume
        str += "\n" + cum_volume
    str
    
caption(isHigh, iLast, pLast, price_rotation, cum_volume) =>
    price_rotation_str = price_rotation_aggregate(price_rotation, pLast, cum_volume)
    if display_reversal_price or display_reversal_price_change or display_cumulative_volume
        if not isHigh
            label.new(iLast, pLast, text=price_rotation_str, style=label.style_none, xloc=xloc.bar_time, yloc=yloc.belowbar, textcolor=color.red)
        else
            label.new(iLast, pLast, text=price_rotation_str, style=label.style_none, xloc=xloc.bar_time, yloc=yloc.abovebar, textcolor=color.green)

price_rotation_diff(pLast, price) =>
    if display_reversal_price_change
        tmp_calc = price - pLast
        str = difference_price == "Absolute"? (math.sign(tmp_calc) > 0? "+" : "") + str.tostring(tmp_calc, format.mintick) : (math.sign(tmp_calc) > 0? "+" : "-") + str.tostring((math.abs(tmp_calc) * 100)/pLast, format.percent)
        str := "(" + str  + ")"
        str
    else
        ""

var line lineLast = na
var label labelLast = na
var int iLast = 0
var float pLast = 0
var bool isHighLast = true // otherwise the last pivot is a low pivot
var int linesCount = 0
var float sumVol = 0
var float sumVolLast = 0

pivotFound(dev, isHigh, index, price) =>
    if isHighLast == isHigh and not na(lineLast)
        // same direction
        if isHighLast ? price > pLast : price < pLast
            if linesCount <= 1
                line.set_xy1(lineLast, index, price)
            line.set_xy2(lineLast, index, price)
            label.set_xy(labelLast, index, price)
            label.set_text(labelLast, price_rotation_aggregate(price_rotation_diff(line.get_y1(lineLast), price), price, str.tostring(sumVol + sumVolLast, format.volume)))
            [lineLast, labelLast, isHighLast, false, sumVol + sumVolLast]
        else
            [line(na), label(na), bool(na), false, float(na)]
    else // reverse the direction (or create the very first line)
        if na(lineLast)
            id = line.new(index, price, index, price, xloc=xloc.bar_time, color=line_color, width=2)
            lb = caption(isHigh, index, price, price_rotation_diff(pLast, price),  str.tostring(sumVol, format.volume))
            [id, lb, isHigh, true, sumVol]
        else
            // price move is significant
            if math.abs(dev) >= dev_threshold
                id = line.new(iLast, pLast, index, price, xloc=xloc.bar_time, color=line_color, width=2)
                lb = caption(isHigh, index, price, price_rotation_diff(pLast, price),  str.tostring(sumVol, format.volume))
                [id, lb, isHigh, true, sumVol]
            else
                [line(na), label(na), bool(na), false, float(na)]

sumVol += nz(volume[math.floor(depth / 2)])

if not na(iH) and not na(iL) and iH == iL
    dev1 = calc_dev(pLast, pH)
    [id2, lb2, isHigh2, isNew2, sum2] = pivotFound(dev1, true, iH, pH)
    if isNew2
        linesCount := linesCount + 1
    if not na(id2)
        lineLast := id2
        labelLast := lb2
        isHighLast := isHigh2
        iLast := iH
        pLast := pH
        sumVolLast := sum2
        sumVol := 0
    dev2 = calc_dev(pLast, pL)
    [id1, lb1, isHigh1, isNew1, sum1] = pivotFound(dev2, false, iL, pL)
    if isNew1
        linesCount := linesCount + 1
    if not na(id1)
        lineLast := id1
        labelLast := lb1
        isHighLast := isHigh1
        iLast := iL
        pLast := pL
        sumVolLast := sum1
        sumVol := 0
else
    if not na(iH)
        dev1 = calc_dev(pLast, pH)
        [id, lb, isHigh, isNew, sum] = pivotFound(dev1, true, iH, pH)
        if isNew
            linesCount := linesCount + 1
        if not na(id)
            lineLast := id
            labelLast := lb
            isHighLast := isHigh
            iLast := iH
            pLast := pH
            sumVolLast := sum
            sumVol := 0
    else
        if not na(iL)
            dev2 = calc_dev(pLast, pL)
            [id, lb, isHigh, isNew, sum] = pivotFound(dev2, false, iL, pL)
            if isNew
                linesCount := linesCount + 1
            if not na(id)
                lineLast := id
                labelLast := lb
                isHighLast := isHigh
                iLast := iL
                pLast := pL
                sumVolLast := sum
                sumVol := 0

var line extend_line = na
var label extend_label = na
if extend_to_last_bar == true and barstate.islast == true
    isHighLastPoint = not isHighLast
    curSeries = isHighLastPoint ? high : low
    if na(extend_line) and na(extend_label)
        extend_line := line.new(line.get_x2(lineLast), line.get_y2(lineLast), time, curSeries, xloc=xloc.bar_time, color=line_color, width=2)
        extend_label := caption(not isHighLast, time, curSeries,  price_rotation_diff(line.get_y2(lineLast), curSeries), str.tostring(sumVol, format.volume))  
    line.set_xy1(extend_line, line.get_x2(lineLast), line.get_y2(lineLast))
    line.set_xy2(extend_line, time, curSeries)
    
    price_rotation = price_rotation_diff(line.get_y1(extend_line), curSeries)                                                                                                  
    remaingRealTimeVol = 0.
    for i = math.abs(math.floor(depth / 2) - 1) to 0
        remaingRealTimeVol += volume[i]
    label.set_xy(extend_label, time, curSeries)    
    label.set_text(extend_label, price_rotation_aggregate(price_rotation, curSeries, str.tostring(sumVol+remaingRealTimeVol, format.volume)))
    label.set_textcolor(extend_label, isHighLastPoint? color.green : color.red)
    label.set_yloc(extend_label, yloc= isHighLastPoint? yloc.abovebar : yloc.belowbar)

Overview

Zig Zag finds pivots with a depth window, then keeps a turn only when price moves beyond the deviation threshold. Lines connect successive reversals, and the last segment can be moved or extended to the current bar. Optional labels show the reversal price, the change as an absolute value or a percent, and cumulative volume between turns. It does not issue entries or exits.

Details

Published by

TWODS-CAPITAL on GitHub

Type

Indicator, Pine Script v5

Draws

On the price chart

Category

Support & resistance, Trend

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 (%)float5.0dev_threshold
Depthint10depth
Line Colorcolor#2962FFline_color
Extend to Last Barbooltrueextend_to_last_bar
Display Reversal Pricebooltruedisplay_reversal_price
Display Cumulative Volumebooltruedisplay_cumulative_volume
Display Reversal Price Changebooltruedisplay_reversal_price_change
difference_pricestringAbsolutedifference_price
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