Emit and labels
ctx.emit records that the setup happened on this bar. On the chart it draws the event's paint. When the definition runs over history, each accepted emit becomes a stored event that studies read.
Every emit needs a label: the text on the chart pin and in the events list. An emit without one is dropped.
Signature
ctx.emit(
eventId: string,
payload?: Record<string, unknown>,
opts?: {
label: string; // required
subtitle?: string;
timeStart?: number; // unix seconds
timeEnd?: number; // unix seconds
price?: number;
}
): voidOption | Notes |
|---|---|
| Required. Trimmed; an empty label counts as missing. Stored as |
| A smaller line under the pin title. Keep it to about two datapoints, such as |
| Start of the event, in unix seconds. Defaults to |
| End of the event, in unix seconds. Defaults to |
| The Y position for |
Example
// s comes from ctx.session(...), st from ctx.accum(...)
ctx.emit("london_range", {
sessionKey: s.key,
high: st.high,
low: st.low,
}, {
label: `London range ${(st.high - st.low).toFixed(1)}`,
subtitle: `H ${st.high.toFixed(2)} · L ${st.low.toFixed(2)}`,
timeStart: s.start,
timeEnd: ctx.time,
price: st.high,
});A point-in-time event needs neither timeStart nor timeEnd. For an event that spans an interval, such as a session, a gap or a consolidation, set both so the stored event covers the whole interval. Set timeStart to the bar where the pin should sit: the pin goes at timeStart, not at the bar that detected the event.
When an emit is dropped
Cause | What you see |
|---|---|
The id was never passed to |
|
No |
|
| Nothing. It is dedupe working as declared. See oncePer. |
The bar is inside the warmup | Nothing stored. The |
|
|
One run stores at most 100,000 events. The run stops with an error when it passes that. If a definition's events are missing after a run, see Emit not collected.
Label rules
Write the label inline in the call:
ctx.emit("id", payload, { label: "..." }). Lintevents/emit-missing-labelreads the call itself, so it warns when the options come from a variable.Write labels a trader can read, such as
"OR break ↑", never the raw id"or_break_up". The pin shows the label, not the id.Do not declare
_displayLabelor_displaySubtitlein the payload. Lint fails withevents/reserved-payload-key.Do not put display text only in the payload. The chart and the events list read the label.
Labels and oncePer
oncePer decides whether the event fires again. The label decides how a fired event is titled. Use both, and never write your own dedupe.
Events that close chart drawings
A range, hline or trendline output declared with mode: "invalidateOnEvent" and invalidateOnEvent: "<event id>" seals its live drawings on the bar that event fires. Detect the break in onBar, emit, and let the output close itself. Do not repeat the same condition in an invalidateWhen predicate. See Drawing on the chart.
Studies
Studies do not call ctx.emit. They read stored events, which carry _displayLabel and, when set, _displaySubtitle. See Study API.
