Meta
meta({...}) names the definition, gives it a stable slug, and sets kind: "flow" so it can emit events. Call it once, at the top of the entry file.
If you only want lines on the chart and no events, write an indicator instead.
Signature
meta({
kind: "flow" | "indicator";
name?: string;
shortName?: string;
slug?: string;
version?: number;
description?: string;
category?: string;
params?: Record<string, FlowParamDef>;
dataSource?: IndicatorDataSource;
runOn?: string[];
runOnReason?: string;
window?: { on?: Array<"barClose"> }; // when the definition runs
}): voidField | Notes |
|---|---|
|
|
| Stable id. Studies bind to it with |
| Library name and chart legend label. |
| Defaults to 1. |
| Library grouping, for example |
| Legacy settings. Prefer |
|
|
| Allowlist of chart timeframes the definition may run on, and the message shown when one is blocked. See Timeframe handles and runOn. |
|
|
meta.id is deprecated: use slug. window.timeframes and window.timeframe are deprecated and lint warns (meta/timeframes-deprecated, meta/timeframe-deprecated): declare timeframe("1h") handles instead.
Warmup is required when you keep state
If the script writes state with ctx.accum or a handle's state, deriving it fails with window/warmup-required until you say how far back that state remembers:
A lookback of N bars:
warmup((w) => w.window(length)).An EMA:
warmup((w) => w.ema(length)). A Wilder or RMA smoother:warmup((w) => w.wilder(length)).State that resets each session or day, such as a session's range:
warmup((w) => w.day()). A weekly reset:w.span("7d").State that never forgets (a running total, a count, a latched flag):
warmup((w) => w.forever()).
Call warmup(...) once, at the top level after the inputs, so it can read their handles. warmup(200) declares a constant. The depth is capped at your plan's indicator memory, and lint warns with window/clamped-to-cap when it is. A stateless definition declares nothing.
retain(...) sets how many recent buckets handle.bars(n) can read, 64 by default: retain({ "1d": 250 }) reads a deep span of one timeframe, and retain((r) => r.span("20d")) keeps 20 days of whichever timeframe is read. Every term is on Warmup and memory.
Example
meta({
name: "London open drive",
kind: "flow",
slug: "london-open-drive",
shortName: "LOD",
runOn: ["1m", "5m"],
runOnReason: "Session logic is intraday",
});Settings and profiles
Definitions have the same settings as indicators: dialog, every input.* kind including multiSelect, range and array, and layout with when. Read the values from ctx.params.<id> in onBar. Legacy meta.params still works for scalar dials and merges with input.*, but new scripts use input.*. See Settings inputs and dialog.
A definition that declares any input.* must also call dialog({ title }). Without it the inputs reach neither the settings panel nor ctx.params, and deriving fails with settings/dialog-required.
dialog({ title: "Wide bar settings" });
const minRange = input.number({ id: "minRange", label: "Min range", default: 5, min: 0 });
export function onBar(ctx) {
if (ctx.high - ctx.low < ctx.params.minRange) return;
// ...
}A profile is a named set of values for these settings. The script's own defaults are the Default profile. Events are stored per set of settings, so each profile has its own events when you run the definition over history. See Versions and profiles.
Definitions also get pane() and scale(), which route outputs to subpanes and price scales exactly as they do for indicators. See Panes & scales.
Common mistakes
Omitting
slugwhen a study needs to bind to the definition, or changing it after studies already do.Using
meta.idinstead ofslug.Keeping state in
ctx.accumwithout awarmup.Writing chart-only math as a definition. Use an indicator.
