← Script Marketplace
Open-source scriptindicator/v1

Zig Zag

by Kodexius·@kodexius·

Connect confirmed alternating swing highs and lows with a configurable Zig Zag path.

#pivots#swing-trading#zig-zag
Zig Zag chart preview

Description

Zig Zag filters minor price movements and connects confirmed pivot highs and lows. Pivot depth, path width, color, history length, and optional price labels are configurable. Pivots appear only after the selected right-side confirmation period, so historical legs do not use future information before confirmation.

Open-source script. Everyone can inspect the source code, use the script on a chart, and save an editable copy.

Release notes

Version history · 1 published version

Version 1CurrentChart updatedZig Zag · Aug 31, 2026
Release notes

Initial official release.

View current source ↓
Source codempl-2.0View source

// Connect confirmed swing highs and lows without using future data.
indicator("Zig Zag", { overlay: true, maxPolylines: 1, maxLabels: 100 });

const depth = input.int("Pivot depth", 5, { min: 2, max: 50 });
const maxPivots = input.int("Maximum pivots", 40, { min: 4, max: 100 });
const showPrices = input.bool("Show pivot prices", false);
const lineColor = input.color("Line color", "#22d3ee");
const lineWidth = input.int("Line width", 2, { min: 1, max: 4 });

const highs = pivothigh(high, depth, depth);
const lows = pivotlow(low, depth, depth);
const pivots = [];

function acceptPivot(kind, index, price) {
  const candidate = { kind, index, price };
  const previous = pivots[pivots.length - 1];
  if (!previous) {
    pivots.push(candidate);
    return;
  }
  if (previous.kind === kind) {
    const moreExtreme = kind === "high" ? price >= previous.price : price <= previous.price;
    if (moreExtreme) pivots[pivots.length - 1] = candidate;
    return;
  }
  pivots.push(candidate);
}

for (let confirmation = 0; confirmation < close.length; confirmation++) {
  const pivotIndex = confirmation - depth;
  if (pivotIndex < 0) continue;
  if (Number.isFinite(highs[confirmation])) acceptPivot("high", pivotIndex, highs[confirmation]);
  if (Number.isFinite(lows[confirmation])) acceptPivot("low", pivotIndex, lows[confirmation]);
}

const visible = pivots.slice(-maxPivots);
if (visible.length >= 2) {
  const points = visible.map((pivot) => chart.point.from_index(pivot.index, pivot.price));
  polyline.new({ points, xloc: "index", color: lineColor, width: lineWidth });
  if (showPrices) {
    visible.forEach((pivot) => label.new({
      x: pivot.index,
      y: pivot.price,
      xloc: "index",
      text: pivot.price.toFixed(2),
      position: pivot.kind === "high" ? "top" : "bottom",
      color: "#0f172a",
      textColor: lineColor,
      size: "small",
    }));
  }
}

Community discussion

0 comments

Loading…

No comments yet. Start the discussion.