feature
Stochastic
Public library indicator Stochastic (stochastic). Same source as the Chartnaut-owned row in the live indicator table.
What it plots
Pane %K / %D oscillator (0–100) with overbought, middle, and oversold guide lines.
Key decisions
Piece | Why it matters |
|---|---|
Raw %K from highest high / lowest low | Position of close inside the recent range. |
Two-stage SMA smooth | %K smoothed, then %D as SMA of %K. |
Guide lines from params | Levels are plotted as series so they move with settings. |
Full script
meta({
shortName: "Stoch",
kind: "pane",
dataSource: "candles",
category: "custom",
});
dialog({
title: "Stochastic Configuration",
description: "Configure Stochastic Oscillator settings",
width: 400,
height: 450,
resizable: false,
showEnabledCheckbox: true,
resetToDefaults: {
enabled: true,
confirmationMessage: "Are you sure you want to reset all Stochastic settings to their default values?",
},
});
const kLength = input.number({
id: "kLength",
label: "%K Length",
default: 14,
min: 1,
step: 1,
});
const kSmoothing = input.number({
id: "kSmoothing",
label: "%K Smoothing",
default: 3,
min: 1,
step: 1,
});
const dSmoothing = input.number({
id: "dSmoothing",
label: "%D Smoothing",
default: 3,
min: 1,
step: 1,
});
const upperBandValue = input.number({
id: "upperBandValue",
label: "Overbought Level",
default: 80,
min: 50,
max: 100,
step: 1,
});
const middleBandValue = input.number({
id: "middleBandValue",
label: "Middle Level",
default: 50,
min: 0,
max: 100,
step: 1,
});
const lowerBandValue = input.number({
id: "lowerBandValue",
label: "Oversold Level",
default: 20,
min: 0,
max: 50,
step: 1,
});
const kColor = input.color({
id: "kColor",
label: "%K Color",
default: "#2962FF",
allowAlpha: true,
});
const dColor = input.color({
id: "dColor",
label: "%D 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" }, kLength, kSmoothing, dSmoothing),
section({ id: "levels", title: "Signal Levels" }, upperBandValue, middleBandValue, lowerBandValue),
section({ id: "display", title: "Display Options" }, labelsEnabled),
),
tab({ id: "appearance", title: "Appearance" },
section({ id: "lines", title: "Lines", columns: 2 }, kColor, dColor, lineStyle),
),
);
output.line({
id: "k",
lineWidth: 2,
colorFrom: kColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "%K",
});
output.line({
id: "d",
lineWidth: 1,
colorFrom: dColor,
lineStyleFrom: lineStyle,
labelFrom: labelsEnabled,
titleWhenLabeled: "%D",
});
output.line({
id: "upperBand",
lineWidth: 1,
titleWhenLabeled: "Overbought",
});
output.line({
id: "middleBand",
lineWidth: 1,
titleWhenLabeled: "Middle",
});
output.line({
id: "lowerBand",
lineWidth: 1,
titleWhenLabeled: "Oversold",
});
/** @param {ScriptedCtx} ctx */
export function onBar(ctx) {
var kLen = ctx.params.kLength || 14;
var kSm = ctx.params.kSmoothing || 3;
var dSm = ctx.params.dSmoothing || 3;
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 < kLen) return;
var highest = -Infinity;
var lowest = Infinity;
for (var i = highBuf.length - kLen; i < highBuf.length; i++) {
if (highBuf[i] > highest) highest = highBuf[i];
if (lowBuf[i] < lowest) lowest = lowBuf[i];
}
var range = highest - lowest;
var rawK = range !== 0 ? ((ctx.close - lowest) / range) * 100 : 50;
var rawKBuf = ctx.accum("rawKBuf", [], function (prev) {
prev.push(rawK);
return prev;
});
if (rawKBuf.length < kSm) return;
var kSum = 0;
for (var j = rawKBuf.length - kSm; j < rawKBuf.length; j++) kSum += rawKBuf[j];
var kVal = kSum / kSm;
var kBuf = ctx.accum("kBuf", [], function (prev) {
prev.push(kVal);
return prev;
});
ctx.plot("k", kVal);
ctx.plot("upperBand", ctx.params.upperBandValue != null ? ctx.params.upperBandValue : 80);
ctx.plot("middleBand", ctx.params.middleBandValue != null ? ctx.params.middleBandValue : 50);
ctx.plot("lowerBand", ctx.params.lowerBandValue != null ? ctx.params.lowerBandValue : 20);
if (kBuf.length < dSm) return;
var dSum = 0;
for (var d = kBuf.length - dSm; d < kBuf.length; d++) dSum += kBuf[d];
var dVal = dSum / dSm;
ctx.plot("d", dVal);
}