feature

ATR

Public library indicator ATR (atr). Same source as the Chartnaut-owned row in the live indicator table.

What it plots

A pane line of Average True Range — volatility in price units, with selectable smoothing.

Key decisions

Piece

Why it matters

True range formula

Uses high−low,

high−prevClose

,

low−prevClose

so gaps count.

smoothingType select

RMA (Wilder), SMA, EMA, or WMA after the first full window.

Seed then recurse

First ATR is a simple average of TR; later bars use the chosen smoother.

Full script

meta({
  shortName: "ATR",
  kind: "pane",
  dataSource: "candles",
  category: "custom",
});

dialog({
  title: "ATR Configuration",
  description: "Configure Average True Range (ATR) settings",
  width: 400,
  height: 350,
  resizable: false,
  showEnabledCheckbox: true,
  resetToDefaults: {
    enabled: true,
    confirmationMessage: "Are you sure you want to reset all ATR settings to their default values?",
  },
});

const period = input.number({
  id: "period",
  label: "Period",
  default: 14,
  min: 1,
  step: 1,
});

const smoothingType = input.select({
  id: "smoothingType",
  label: "Smoothing",
  default: "RMA",
  options: [
    { value: "RMA", label: "RMA (Wilder's)" },
    { value: "SMA", label: "SMA" },
    { value: "EMA", label: "EMA" },
    { value: "WMA", label: "WMA" },
  ],
});

const lineColor = input.color({
  id: "lineColor",
  label: "Line Color",
  default: "#2962FF",
  allowAlpha: true,
});

const lineStyle = input.lineStyle({
  id: "lineStyle",
  label: "Line Style",
  default: LineStyle.Solid,
});

const labelsEnabled = input.boolean({
  id: "labelsEnabled",
  label: "Show Labels",
  default: true,
});

layout(
  tab({ id: "general", title: "General" },
    section({ id: "parameters", title: "Parameters" }, period, smoothingType),
    section({ id: "display", title: "Display Options" }, labelsEnabled),
  ),
  tab({ id: "appearance", title: "Appearance" },
    section({ id: "line", title: "Line", columns: 2 }, lineColor, lineStyle),
  ),
);

output.line({
  id: "atr",
  lineWidth: 2,
  colorFrom: lineColor,
  lineStyleFrom: lineStyle,
  labelFrom: labelsEnabled,
  titleWhenLabeled: "ATR",
});

/** @param {ScriptedCtx} ctx */
export function onBar(ctx) {
  var p = ctx.params.period || 14;
  var sm = ctx.params.smoothingType || "RMA";

  var closeBuf = ctx.accum("closeBuf", [], function (prev) {
    prev.push(ctx.close);
    return prev;
  });

  if (closeBuf.length < 2) return;

  var prevClose = closeBuf[closeBuf.length - 2];
  var tr = Math.max(
    ctx.high - ctx.low,
    Math.abs(ctx.high - prevClose),
    Math.abs(ctx.low - prevClose)
  );

  var trBuf = ctx.accum("trBuf", [], function (prev) {
    prev.push(tr);
    return prev;
  });

  if (trBuf.length < p) return;

  if (trBuf.length === p) {
    var sum = 0;
    for (var i = 0; i < p; i++) sum += trBuf[i];
    var atr = sum / p;
    ctx.accum("atr", 0, function () { return atr; });
    ctx.plot("atr", atr);
    return;
  }

  var prevAtr = ctx.accum("atr", 0, function (prev) { return prev; });
  var atrVal;

  if (sm === "SMA") {
    var smaSum = 0;
    for (var j = trBuf.length - p; j < trBuf.length; j++) smaSum += trBuf[j];
    atrVal = smaSum / p;
  } else if (sm === "EMA") {
    var k = 2 / (p + 1);
    atrVal = tr * k + prevAtr * (1 - k);
  } else if (sm === "WMA") {
    var wSum = 0;
    var wDenom = 0;
    for (var w = 0; w < p; w++) {
      var weight = w + 1;
      wSum += trBuf[trBuf.length - p + w] * weight;
      wDenom += weight;
    }
    atrVal = wSum / wDenom;
  } else {
    atrVal = (prevAtr * (p - 1) + tr) / p;
  }

  ctx.accum("atr", 0, function () { return atrVal; });
  ctx.plot("atr", atrVal);
}

Next

  1. Indicator examples

  2. Indicator series types

  3. Declaring indicator dependencies