Interface IndicatorDescriptor

interface IndicatorDescriptor {
    alerts?: readonly IndicatorAlertSpec[];
    category?: string;
    fills?: readonly IndicatorFillSpec[];
    hasSource?: boolean;
    id: string;
    inputs: readonly IndicatorInput[];
    markerAnchor?: "price" | "plot";
    name: string;
    placement: "onchart" | "pane";
    plots: readonly IndicatorPlot[];
    attach(ctx: IndicatorAttachContext): void | () => void;
    background(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): readonly (null | string)[]
    | readonly IndicatorBackgroundSpec[];
    barColors(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): readonly (null | string)[];
    calc(
        bars: readonly Bar[],
        settings: Readonly<IndicatorSettings>,
        store: IndicatorStore,
        ctx?: IndicatorCalcContext,
    ): IndicatorValues;
    calcTail(
        bars: readonly Bar[],
        settings: Readonly<IndicatorSettings>,
        fromIndex: number,
        previous: IndicatorValues,
        store: IndicatorStore,
        ctx?: IndicatorCalcContext,
    ): null | IndicatorValues;
    draws(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): readonly IndicatorDrawing[];
    levels(ctx: IndicatorLevelContext): readonly IndicatorLevel[];
    markers(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): readonly IndicatorMarker[];
    range(
        settings: Readonly<IndicatorSettings>,
    ): null | { max: number; min: number };
    table(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): | null
    | {
        options?: Partial<ChartTableOptions>;
        rows: readonly (readonly TableCell[])[];
    };
    tables(
        ctx: {
            bars: readonly Bar[];
            settings: Readonly<IndicatorSettings>;
            values: IndicatorValues;
        },
    ): readonly IndicatorTableSpec[];
}

Properties

alerts?: readonly IndicatorAlertSpec[]

Optional conditions the runtime watches on the descriptor's behalf, emitted as 'indicator:alert' on the chart's event bus with an IndicatorAlertPayload. See IndicatorAlertSpec.

category?: string

Grouping for a picker UI ('Trend', 'Momentum', 'Volume', 'Volatility').

fills?: readonly IndicatorFillSpec[]

Shaded bands between pairs of plots: the Ichimoku cloud, a Bollinger channel. A pair of lines is not the same picture as a filled region: the fill is what makes "price is above the cloud" readable at a glance, and which side leads is itself the signal, hence the two colours.

hasSource?: boolean

This indicator was written from code the host can show the user.

Its legend row then carries a source button beside the gear, and pressing it emits indicatorSource with the same payload indicatorSettings carries. The engine does not hold the code and does not want to: a descriptor may be compiled from a script, generated, or written by hand in the host's own bundle, and only the host knows which of those it can put in front of somebody. So this says a button is worth offering, and the host decides what the button opens.

Absent or false draws no button, which is every built-in study.

id: string

Registry key, e.g. 'macd'.

inputs: readonly IndicatorInput[]
markerAnchor?: "price" | "plot"

What aboveBar and belowBar are measured against.

'plot', the default, is this study's own first plot, which is right for a mark that belongs to the line: an arrow on a moving average sits against the average.

'price' is the instrument's candles, so above is above the high and below is below the low. That is what a buy or sell signal on an overlay study means, and anchoring one to the study's own column instead puts it wherever that column happens to sit: a study that anchors its marks to a mid-body line draws every "below" mark through the middle of the candle.

Ignored by a study in its own pane, which has no candles to measure against, and ignored when the chart has no primary series yet. Both fall back to the first plot rather than dropping the marker. It applies to the marks that name no target; a study in its own pane sends a mark to the candles with overlay: true on that mark.

name: string

Display name, e.g. 'MACD'.

placement: "onchart" | "pane"

'onchart' overlays the price pane; 'pane' gets its own pane.

plots: readonly IndicatorPlot[]

Methods

  • Optional per-instance lifecycle, for indicators whose data is not derived from the chart's bars (CVD, PCR, an external feed). Called once when the instance is created; return a teardown function.

    Fetch into ctx.store, then call ctx.requestRecompute(): calc runs again and reads what you stored.

    Parameters

    Returns void | () => void

  • Optional per-bar shading behind everything else in the indicator's pane: a full-height column per bar, null where nothing should be shaded.

    A regime study answers "which state is the market in right now", and that is a property of the whole bar, not a price. Drawn as a plot it would need a value to sit at and would fight the pane's autoscale; as a column behind the candles it reads at a glance and costs the scale nothing.

    Return a list of IndicatorBackgroundSpec instead to shade somewhere else as well: each column can name the price pane or a plot (see IndicatorOutputTarget), one column per target, and a column naming none shades the indicator's pane exactly as the plain form does.

    Runs after every calc. Return [] to clear the study's own shading and release every targeted column.

    Parameters

    Returns readonly (null | string)[] | readonly IndicatorBackgroundSpec[]

  • Optional recolouring of the main price candles, one entry per bar, null to leave that bar with its own colour.

    Distinct from a plot's colorBy, which paints the indicator's own series: a trend filter, a volatility regime or a higher-timeframe bias is a statement about the price bars themselves, and drawing it as a second series beside them says something weaker.

    Only one indicator's colours can be on the candles at a time; the most recent publisher wins, and publishers run in addIndicator order, so the winner is the same one from frame to frame. Removing it, or hiding it, restores the bars' own colours.

    Parameters

    Returns readonly (null | string)[]

  • Optional bar-anchored signal markers: a named "Buy"/"Sell" plate, an arrow at a crossover. Runs after every calc, so it reads the values it just produced rather than recomputing anything.

    A plot cannot express this: a plot is a column of prices drawn as a line or histogram, whereas a signal is a discrete event with a label. Returning [] (when a showLabels-style input is off, say) clears every layer. A mark can name the price pane or a plot to anchor to instead of the default (see IndicatorOutputTarget).

    Parameters

    Returns readonly IndicatorMarker[]

  • Optional fixed price range for the indicator's own pane (RSI 0..100). Applied only when the indicator creates its pane: two indicators sharing a pane would otherwise fight over it.

    Parameters

    Returns null | { max: number; min: number }

  • Optional summary grid pinned to a corner of the pane.

    Some studies are not a value per bar at all: a seasonality heatmap is a matrix of monthly returns, a scoreboard is a handful of statistics. Those have no place in calc, whose contract is one column per plot aligned to the bars, so they come back through here instead. Runs after every calc.

    Return null (or a zero-row grid) to draw nothing, which is how a showTable-style input should switch it off.

    Parameters

    Returns
        | null
        | {
            options?: Partial<ChartTableOptions>;
            rows: readonly (readonly TableCell[])[];
        }