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 output.line ids

Mid, upper, and lower are independent series for styling.

Warmup on period

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

Next

  1. Indicator examples

  2. Indicator series types

  3. Declaring indicator dependencies