feature

Donchian Channels

Public library indicator Donchian Channels (donchian_channels). Same source as the Chartnaut-owned row in the live indicator table.

What it plots

Three overlay lines: highest high, lowest low, and midpoint over period.

Key decisions

Piece

Why it matters

Separate high/low buffers

Channel edges come from extremes, not close.

Middle = (highest + lowest) / 2

Mid is derived — not a third independent series.

Warmup gate on buffer length

No plots until a full window exists.

Full script

meta({
  shortName: "DC",
  kind: "overlay",
  dataSource: "candles",
  category: "custom",
});

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

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

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

const middleColor = input.color({
  id: "middleColor",
  label: "Middle Color",
  default: "#FF6D00",
  allowAlpha: true,
});

const lowerColor = input.color({
  id: "lowerColor",
  label: "Lower 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),
    section({ id: "display", title: "Display Options" }, labelsEnabled),
  ),
  tab({ id: "appearance", title: "Appearance" },
    section({ id: "lines", title: "Lines", columns: 2 }, upperColor, middleColor, lowerColor, lineStyle),
  ),
);

output.line({
  id: "upper",
  lineWidth: 1,
  colorFrom: upperColor,
  lineStyleFrom: lineStyle,
  labelFrom: labelsEnabled,
  titleWhenLabeled: "DC Upper",
});

output.line({
  id: "middle",
  lineWidth: 1,
  colorFrom: middleColor,
  lineStyleFrom: lineStyle,
  labelFrom: labelsEnabled,
  titleWhenLabeled: "DC Mid",
});

output.line({
  id: "lower",
  lineWidth: 1,
  colorFrom: lowerColor,
  lineStyleFrom: lineStyle,
  labelFrom: labelsEnabled,
  titleWhenLabeled: "DC Lower",
});

/** @param {ScriptedCtx} ctx */
export function onBar(ctx) {
  var p = ctx.params.period || 20;

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

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

  if (highBuf.length < p) return;

  var highest = -Infinity;
  var lowest = Infinity;
  for (var i = highBuf.length - p; i < highBuf.length; i++) {
    if (highBuf[i] > highest) highest = highBuf[i];
    if (lowBuf[i] < lowest) lowest = lowBuf[i];
  }

  ctx.plot("upper", highest);
  ctx.plot("lower", lowest);
  ctx.plot("middle", (highest + lowest) / 2);
}

Next

  1. Indicator examples

  2. Indicator series types

  3. Declaring indicator dependencies