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. |
| 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);
}