feature
Bollinger Bands
Public library indicator Bollinger Bands (bollinger). Same source as the Chartnaut-owned row in the live indicator table.
What it plots
Overlay mid (SMA of close) plus upper/lower bands at ± standardDeviations × σ.
Key decisions
Piece | Why it matters |
|---|---|
SMA + population stdev of the same window | Bands widen/tighten with recent volatility. |
Three | Mid, upper, and lower are independent series for styling. |
Warmup on | No bands until the close buffer is full. |
Full script
meta({
shortName: "BB",
kind: "overlay",
dataSource: "candles",
category: "custom",
});
dialog({
title: "Bollinger Bands Configuration",
description: "Configure Bollinger Bands settings",
width: 400,
height: 400,
resizable: false,
showEnabledCheckbox: true,
resetToDefaults: {
enabled: true,
confirmationMessage: "Are you sure you want to reset all Bollinger Bands settings to their default values?",
},
});
const period = input.number({
id: "period",
label: "Period",
default: 20,
min: 1,
step: 1,
});
const standardDeviations = input.number({
id: "standardDeviations",
label: "Standard Deviations",
default: 2,
min: 0.1,
step: 0.1,
});
const middleColor = input.color({
id: "middleColor",
label: "Middle Color",
default: "#2962FF",
allowAlpha: true,
});
const bandColor = input.color({
id: "bandColor",
label: "Band Color",
default: "#FF6D00",
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, standardDeviations),
section({ id: "display", title: "Display Options" }, labelsEnabled),
),
tab({ id: "appearance", title: "Appearance" },
section({ id: "lines", title: "Lines", columns: 2 }, middleColor, bandColor, lineStyle),
),
);
output.line({
id: "middle",
lineWidth: 2,
colorFrom: middleColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "BB Mid",
});
output.line({
id: "upper",
lineWidth: 1,
colorFrom: bandColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "BB Upper",
});
output.line({
id: "lower",
lineWidth: 1,
colorFrom: bandColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "BB Lower",
});
/** @param {ScriptedCtx} ctx */
export function onBar(ctx) {
var p = ctx.params.period || 20;
var mult = ctx.params.standardDeviations || 2;
var closeBuf = ctx.accum("closeBuf", [], function (prev) {
prev.push(ctx.close);
return prev;
});
if (closeBuf.length < p) return;
var sum = 0;
for (var i = closeBuf.length - p; i < closeBuf.length; i++) sum += closeBuf[i];
var sma = sum / p;
var sqSum = 0;
for (var j = closeBuf.length - p; j < closeBuf.length; j++) {
var diff = closeBuf[j] - sma;
sqSum += diff * diff;
}
var stdDev = Math.sqrt(sqSum / p);
ctx.plot("middle", sma);
ctx.plot("upper", sma + stdDev * mult);
ctx.plot("lower", sma - stdDev * mult);
}