param() turns a value into a setting users can change without editing
code. Each param you declare shows up in the chart's settings for the
overlay and in om metric series --params, and the value you read in
init() drives your logic. This is how you ship a configurable
Indicator: an adjustable period, a threshold, a multiplier, an on/off
toggle. kScript (legacy) had fifteen input() types; an Indicator has
one, the number, and this page is what each of the fifteen becomes.
param("length", 20, { min: 2, max: 200, description: "Length" });
let n: i32 = 20;
export function init(): void { n = i32(p_length()); }Every param takes a name, a default, and usually a description (the
text shown beside the field). min and max bound the setting, and
required: true refuses a use that does not set it. There is no step,
no group, and no label: the description is the label.
The types
kScript type | Surfaced as | Indicator |
|---|---|---|
number, float | number field | param(name, default, { min, max }), read as f64 |
int | integer field | the same param, cast with i32(p_name()); the chart rounds nothing, so cast where you use it |
slider | slider | the same param with min and max; the chart chooses the control |
boolean | toggle | param(name, 1, { min: 0, max: 1 }), tested as p_name() > 0.5 |
select, multiSelect | dropdown | not in Indicators yet; a numeric mode param (0, 1, 2) switched on with switch is the nearest |
string, text | text field | not in Indicators yet; strings leave the module through string slots, never enter it |
color, color[] | color picker | not in Indicators yet as a param; color and colors are declared per output, box, or segment, and a hand-written sheet can bind a style knob (Styling) |
source | source dropdown | not in Indicators yet; the source is the declaration input(name, source.field) |
timeframe | timeframe field | not in Indicators yet; an interval pin on the input, honored on your machine |
session | session field | not in Indicators yet; session math is integer math on the time source (Time and sessions) |
symbol | symbol field | not in Indicators yet; a symbol + exchange pin on the input, honored on your machine |
Every param is an f64 today; non-numeric params are product work, and
the rows above name the declaration that carries the same intent. What a
kScript select chose at runtime, an Indicator chooses at declaration
time: two moving-average kinds are two classes, and a mode param picks
which one writes the output.
Examples by type
Number with min and max. An adjustable period clamped to a sensible range; the cast makes it a bar count:
param("length", 14, { min: 2, max: 100, description: "Length" });Select, as a mode number. A dropdown that switched behavior becomes a
numeric mode and a switch in init() or state():
param("ma_type", 1, { min: 0, max: 1, description: "0 = simple, 1 = exponential" });Color. The user recolors the plot in the chart's style settings; the file declares the default:
output("ma", line, overlay, { color: "#2563eb", width: 2 });Boolean. An on/off toggle is a 0/1 param; to hide a line, write NaN
to it while the toggle is off, and to switch a mark off, feed the toggle
into its gate output:
param("show_fast", 1, { min: 0, max: 1, description: "Show the fast line" });Source. Which data feeds the module is the declaration, and a second feed is a second input; the chart user picks the market, not the source:
input("close", ohlcv.close);
input("buy", trades.volume, { side: "BUY" });Symbol and timeframe. Pins on the input, both halves together for a
market, interval on its own; the chart reads its own market for every
input, your machine honors the pins:
input("btc_4h", ohlcv.close, { symbol: "BTCUSDT", exchange: "BINANCE_FUTURES", interval: "FOUR_HOURS" });Style-only inputs
kScript treated a plot color, line width, or show/hide toggle as
style-only when it could prove the setting was presentation-only, and
patched the rendered output without recomputing. An Indicator makes the
split explicit: color, width, opacity, and line_style on an output
are declared style the chart edits without a recompute, and a
hand-written sheet can expose one as a settings knob with style: { "output", "property" } (no accessor, no recompute). Every param(...)
is compute-affecting by construction: it reaches init() and the module
re-runs when it changes.
Every type in one module
Number, integer, float, slider, and boolean params driving one average, with the select-as-mode and the color-as-declaration in the same file.
import { input, line, none, ohlcv, output, overlay, param, shape } from "./sdk/declare";
import { in_close, in_low } from "./gen/inputs";
import { emitRow, out_above, out_average, out_band, out_mark } from "./gen/outputs";
import { p_average, p_float_multiplier, p_int_length, p_number_length, p_show_marks, p_slider_width } from "./gen/params";
import { Ema, Sma } from "./sdk/ta";
// number: a period, cast to a bar count where it is used.
param("number_length", 12, { min: 2, max: 50, description: "Number Length" });
// int: the same declaration; the cast is what makes it an integer.
param("int_length", 14, { min: 2, max: 50, description: "Int Length" });
// float: a fractional multiplier, used as f64.
param("float_multiplier", 1.5, { min: 0.5, max: 5, description: "Float Multiplier" });
// boolean: 0 or 1.
param("show_marks", 1, { min: 0, max: 1, description: "Show marks on bars above the band" });
// select: a mode number, 0 = simple, 1 = exponential.
param("average", 1, { min: 0, max: 1, description: "Average: 0 simple, 1 exponential" });
// slider: a bounded number; the band width in percent.
param("slider_width", 2, { min: 1, max: 5, description: "Band width, percent" });
input("close", ohlcv.close);
input("low", ohlcv.low);
// color: declared on the output, editable in the chart's style settings.
output("average", line, overlay, { color: "#2563eb", width: 2, description: "The chosen average" });
output("band", line, overlay, { color: "#94a3b8", width: 1, line_style: "dotted", description: "Average plus the band width" });
output("mark", shape, overlay, { color: "#16a34a", shape_where: "above", description: "The low of each bar closing above the band" });
output("above", none, overlay, { description: "1 when the close is above the band and marks are on" });
let sma = new Sma(12);
let ema = new Ema(14);
let mode: i32 = 1;
let multiplier: f64 = 1.5;
let showMarks: bool = true;
let bandPct: f64 = 2.0;
let average: f64 = NaN;
let close: f64 = NaN;
let low: f64 = NaN;
export function init(): void {
sma = new Sma(i32(p_number_length()));
ema = new Ema(i32(p_int_length()));
mode = i32(p_average());
multiplier = p_float_multiplier();
showMarks = p_show_marks() > 0.5;
bandPct = p_slider_width();
}
export function state(): i32 {
close = in_close();
low = in_low();
const simple = sma.update(close);
const exponential = ema.update(close);
switch (mode) {
case 0:
average = simple;
break;
default:
average = exponential;
}
return isNaN(average) ? 0 : 1;
}
export function finalize(): void {
const band = average * (1.0 + (bandPct * multiplier) / 100.0);
out_average(average);
out_band(band);
out_mark(low);
out_above(showMarks && close > band ? 1.0 : 0.0);
emitRow();
}
export function reset(): void {
sma.reset();
ema.reset();
average = NaN;
close = NaN;
low = NaN;
}Both averages update on every bar whatever the mode, so switching the setting never restarts a warm-up; only the line written changes.
Defaults are checked
The default must sit inside min..max, and the build checks it before
the compiler runs, naming the path:
| Mistake | Error |
|---|---|
a default above max | params.0.default: default above max |
min above max | params.0.min: min must be <= max |
a step option | param options accept only { required, min, max, description }, not 'step' |
a computed default (param("n", base * 2)) | expected a numeric literal |
| a name built from a variable | expected a string literal |
a string default (param("mode", "ema")) | expected a numeric literal |
Declarations are literals: the extractor reads them from the text
without running it. A kScript defaultValue type mismatch has no
counterpart because there is one type.
Reading a param on your machine
An installed package's params are arguments to every surface that evaluates it, so the same setting the chart user drags is the one an alert or a series query pins:
om metric series --metric wrun/@you/typed-inputs/average --params number_length=20,average=0 --symbol BTCUSDT --exchange BINANCE_FUTURES --bars 60om metric get --metric wrun/@you/name/output:length=20 is the inline
form. A param the caller does not pass takes its default; one declared
required: true refuses the call by name instead.