Script outputs: line, histogram, bands, markers, levels, table, panel

A user script returns an array of outputs, each identified by a shape. Five shapes are drawn on the canvas (line, histogram, bands, markers, levels) and two are rendered as draggable DOM cards (table, panel). Every output is normalised before it reaches the renderer, and anything unrecognised is reported rather than silently dropped.

Senzoukria · Documentation · Updated September 2026


Where to find it

Where
Return value of compute() in any user script; drawn on the chart when the script is shown
Targets
"On the chart" (overlay) or "Own pane" (a 90 px pane under the chart)
DOM limits
Table: 50 rows and 8 columns; panel: 50 entries; excess is truncated
Time key
point.time must equal a bar's bucketTsNs (nanosecond epoch); other points are discarded

What it does

The renderer only knows SeriesOutput values; it never sees the script that produced them. The built-in indicators and user scripts therefore share the same shapes and the same normalisation rules: a point outside the visible bars is discarded, a non-finite value becomes a gap (value: null), and a null value written on purpose, for example during a moving average's warm-up, is preserved as a lifted pen instead of a false segment.

The draw target is chosen per script. "On the chart" overlays the price; "Own pane" reserves a pane whose height is fixed by the renderer at 90 px. Because tables and panels are DOM elements, a pane script whose only remaining outputs are a table does not reserve an empty pane: the split between canvas and DOM outputs is made before the renderer counts panes.

Shapes and their fields

Output shapes accepted from a user script, after normalisation
ShapeFieldsDefaults applied
linepoints [{time, value|null}], style {color, width, style}color #7ed321; width clamped 0.5–12; style solid, dashed or dots
histogrampoints [{time, value}], positiveColor, negativeColor#22c55e positive, #ef4444 negative; a bar without a finite value emits no point
bandsupper, basis, lower point arrays, fillAlpha, stylefillAlpha 0.12, clamped 0–1; style as for line
markersmarkers [{time, price, kind, color, label?}]kind dot unless arrow-up, arrow-down or square; color #7ed321
levelslevels [{price, from, to|null, color, label?, style?}]to null = runs to the right edge; only price and from are required
tabletitle?, columns [{key, label, align?}], rows [{key: string|number|null}]Rejected when no column; max 8 columns and 50 rows; unknown row keys dropped
paneltitle?, entries [{label, value, color?}]Max 50 entries; an entry without a string or finite number value is skipped

Table and panel cards

Tables and panels are rendered as floating cards over the chart because a table has to be read, selected and copied, which a canvas cannot offer, and because a 90 px pane holds only three lines. Each card is titled with the script name, followed by " · " and the output's title when one is given. Cards are dragged by their header; their position is saved per output under the key orderflow.seriesTables.v1 at the end of the drag. Without a saved position, cards cascade from the top-right corner (60 px down and 12 px in, offset by 26 px and 14 px per additional card) so two cards never overlap exactly.

The DOM is updated once per animation frame, not at the 4 Hz bar publication rate, and a null cell is printed as "—" rather than 0. Column alignment defaults to left; a script that wants numbers on the right sets align: "right" on the column.

How to use it

The lib helpers build the common shapes: lib.line(chronoBars, values, color, width), lib.histogram, lib.markers, lib.levels, lib.table(columns, rows, title) and lib.panel. Arrays passed to lib helpers are in chronological order, so reverse the newest-first bars first. A script can return several outputs, for example one bands output and one line for a VWAP with sigma bands.

A rejected shape does not vanish: the script is flagged in the Indicators panel, where the line under its name becomes "Unrecognised return value. An indicator returns a series, lines or markers — see \"Indicator: what to return\"." instead of its draw target. A script that returns outputs which draw nothing is flagged "empty", which distinguishes "it does not work" from "there was nothing to show".

Limits and pitfalls

  • Widths below 0.5 or above 12 px are clamped; unknown style names fall back to solid.
  • Histogram points with a null or non-finite value are removed entirely, unlike lines where null is a gap.
  • Levels are segments keyed by price and from; they are not filtered on bar time, so a from timestamp older than the loaded history simply starts at the left edge.
  • A table with more than 50 rows is truncated; write the truncation in the title yourself if the count matters.

This page in other languages

Frequently asked questions

Why is my table not in the pane I selected?
Tables and panels always render as DOM cards over the chart, whatever the draw target. The target only affects canvas shapes such as lines and histograms.
How do I show a gap instead of a line to zero during warm-up?
Return value: null for those points. The renderer lifts the pen; a zero would draw a false segment.
Can I move the table card and keep its place?
Yes. Drag it by its header; the position is stored per output in localStorage and restored when the chart reopens.

Keep reading