feature
MACD
Public library indicator MACD (macd). Same source as the Chartnaut-owned row in the live indicator table.
What it plots
Pane MACD line, signal line, and histogram of their difference.
Key decisions
Piece | Why it matters |
|---|---|
Fast/slow EMA of close | MACD = fast − slow; seed each EMA from SMA at first full period. |
Signal = EMA of MACD | Needs its own buffer after the MACD line exists. |
| Histogram series uses bar/plot helper (not only |
Full script
meta({
shortName: "MACD",
kind: "pane",
dataSource: "candles",
category: "custom",
});
dialog({
title: "MACD Configuration",
description: "Configure MACD settings",
width: 400,
height: 450,
resizable: false,
showEnabledCheckbox: true,
resetToDefaults: {
enabled: true,
confirmationMessage: "Are you sure you want to reset all MACD settings to their default values?",
},
});
const fastPeriod = input.number({
id: "fastPeriod",
label: "Fast Period",
default: 12,
min: 1,
step: 1,
});
const slowPeriod = input.number({
id: "slowPeriod",
label: "Slow Period",
default: 26,
min: 1,
step: 1,
});
const signalPeriod = input.number({
id: "signalPeriod",
label: "Signal Period",
default: 9,
min: 1,
step: 1,
});
const macdColor = input.color({
id: "macdColor",
label: "MACD Color",
default: "#2962FF",
allowAlpha: true,
});
const signalColor = input.color({
id: "signalColor",
label: "Signal Color",
default: "#FF6D00",
allowAlpha: true,
});
const histColor = input.color({
id: "histColor",
label: "Histogram Color",
default: "#26A69A",
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" }, fastPeriod, slowPeriod, signalPeriod),
section({ id: "display", title: "Display Options" }, labelsEnabled),
),
tab({ id: "appearance", title: "Appearance" },
section({ id: "colors", title: "Colors", columns: 2 }, macdColor, signalColor, histColor, lineStyle),
),
);
output.line({
id: "macd",
lineWidth: 2,
colorFrom: macdColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "MACD",
});
output.line({
id: "signal",
lineWidth: 1,
colorFrom: signalColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "Signal",
});
output.histogram({
id: "histogram",
colorFrom: histColor,
labelFrom: labelsEnabled,
titleWhenLabeled: "Histogram",
});
/** @param {ScriptedCtx} ctx */
export function onBar(ctx) {
var fp = ctx.params.fastPeriod || 12;
var sp = ctx.params.slowPeriod || 26;
var sigP = ctx.params.signalPeriod || 9;
var closeBuf = ctx.accum("closeBuf", [], function (prev) {
prev.push(ctx.close);
return prev;
});
var len = closeBuf.length;
// Fast EMA
var fastK = 2 / (fp + 1);
var fastEma;
if (len < fp) return;
if (len === fp) {
var fSum = 0;
for (var i = 0; i < fp; i++) fSum += closeBuf[i];
fastEma = fSum / fp;
} else {
var prevFast = ctx.accum("fastEma", 0, function (prev) { return prev; });
fastEma = ctx.close * fastK + prevFast * (1 - fastK);
}
ctx.accum("fastEma", 0, function () { return fastEma; });
// Slow EMA
var slowK = 2 / (sp + 1);
var slowEma;
if (len < sp) return;
if (len === sp) {
var sSum = 0;
for (var j = 0; j < sp; j++) sSum += closeBuf[j];
slowEma = sSum / sp;
} else {
var prevSlow = ctx.accum("slowEma", 0, function (prev) { return prev; });
slowEma = ctx.close * slowK + prevSlow * (1 - slowK);
}
ctx.accum("slowEma", 0, function () { return slowEma; });
var macdVal = fastEma - slowEma;
var macdBuf = ctx.accum("macdBuf", [], function (prev) {
prev.push(macdVal);
return prev;
});
// Signal EMA of MACD line
var sigK = 2 / (sigP + 1);
var signal;
if (macdBuf.length < sigP) {
ctx.plot("macd", macdVal);
return;
}
if (macdBuf.length === sigP) {
var sigSum = 0;
for (var k = 0; k < sigP; k++) sigSum += macdBuf[k];
signal = sigSum / sigP;
} else {
var prevSig = ctx.accum("signal", 0, function (prev) { return prev; });
signal = macdVal * sigK + prevSig * (1 - sigK);
}
ctx.accum("signal", 0, function () { return signal; });
ctx.plot("macd", macdVal);
ctx.plot("signal", signal);
ctx.bar("histogram", macdVal - signal);
}