API reference
Everything is exported from @kumochart-sdk/core. Types are named after what they describe: XxxInput is what you pass in, Xxx is what the chart returns.
- createChart
- Chart
- data · replay · timeScale · priceScale · panes · series · indicators · drawings · orders · markers · alerts · crosshair · plugins
- Events
- Options
- Intervals and calendars
- Errors
Conventions
- Time (
TimeInput) is epoch milliseconds, an ISO-8601 string or aDate. The chart always returns epoch milliseconds. - Coordinates are CSS pixels relative to the chart's top-left corner.
- Logical indices count bars: bar
iis centered on indexi. Indices may be fractional or beyond the data. - Inputs are copied. The chart never keeps or mutates objects you pass in.
- API calls do not emit events. Only user actions (and alerts) do.
createChart
function createChart(container: HTMLElement, options?: ChartOptionsInput): Chart;Creates a chart that fills container. Throws a ChartError if the container is invalid, a required browser API is missing, or an option is invalid.
Extras
The more specialised features are extras, which a chart only has once registered, so that applications without them do not ship their code:
| Extra | Registered as |
|---|---|
heikinAshiTransform, renkoTransform, rangeTransform | Transforms heikin-ashi, renko, range (data.registerTransform) |
longPosition, shortPosition, pitchfork, fibExtension | Drawing types long-position, short-position, pitchfork, fib-extension |
dateRange, datePriceRange, callout | Drawing types date-range, date-price-range, callout |
import { createChart, registerExtras, renkoTransform } from '@kumochart-sdk/core';
registerExtras(chart); // all of them, under the names above
chart.data.registerTransform('renko', renkoTransform); // or only those you useUsing an extra that is not registered throws a ChartError that says so. The Vue and React components register them through their configure prop, which runs before the other props apply.
Chart
| Member | Description |
|---|---|
element: HTMLElement | The element the chart created inside its container |
options(): ChartOptions | The resolved options, frozen; change them with applyOptions |
applyOptions(options: ChartOptionsInput): void | Deep-merges option changes; arrays and functions are replaced |
layout(): Layout | Rectangles of panes, axes and separators, for positioning HTML overlays |
resize(width, height): void | Sets the size; with autoSize the container size wins on its next change |
batch(operation: () => void): void | Runs several calls and dispatches their events once afterwards |
on(type, listener): Unsubscribe | Subscribes to an event |
select(selection: Selection | null): void | Selects a drawing, order, alert or marker |
selection(): Selection | null | The selected object |
saveState(): ChartState | The user's layout: main series type, view, panes, indicators, drawings |
loadState(state: ChartState): void | Restores a layout atomically; invalid states throw and change nothing |
screenshot(): HTMLCanvasElement | Renders pending changes and returns a canvas of the whole chart |
destroy(): void | Removes the element and releases all resources |
interface Selection {
kind: 'drawing' | 'order' | 'alert' | 'marker';
id: string;
}data
The main OHLCV series. Writes go to the source data; reads return the displayed bars: the source aggregated to the timeframe, built by a transform when one is set, and clipped by a running replay.
| Member | Description |
|---|---|
set(bars: readonly BarInput[], options?: { interval? }): void | Replaces the source. Times must be strictly ascending. interval declares their resolution (e.g. '1m'); without it, bars are displayed as given |
update(bar: BarInput | readonly BarInput[]): void | Replaces the last source bar (same time) or appends newer bars. Rejects older bars |
addTrades(trade: TradeInput | readonly TradeInput[]): number | Folds trades into the source bars; needs a source interval. Skips trades the calendar drops, returns how many were applied |
prepend(bars: readonly BarInput[]): number | Inserts older source bars; ignores bars at or after the first bar; returns how many were inserted |
clear(): void | Removes the bars and ends a running replay; the interval and timeframe stay |
sourceInterval(): Interval | null | Resolution of the source bars |
timeframe(): Interval | null | The displayed timeframe; null is the source resolution |
setTimeframe(timeframe: IntervalInput | null): void | Aggregates the source to a coarser timeframe without refetching; null shows the source resolution |
transform(): BarTransformInput | null | The transform building the displayed bars |
setTransform(transform: BarTransformInput | null): void | Builds the displayed bars from the timeframe's bars, e.g. Renko bricks; null shows the timeframe's bars |
registerTransform(type, definition: BarTransformDefinition) | Adds a custom transform |
length: number | Number of displayed bars |
at(index: number): Bar | null | The displayed bar at an index |
last(): Bar | null | The latest displayed bar |
indexOf(time: TimeInput): number | Index of the displayed bar with exactly this time, or -1 |
toArray(): Bar[] | A copy of the displayed bars |
bars: BarsView | The displayed bars as a read-only columnar view, without copying (BarsView) |
source: BarsView | The source bars as a view, up to the cursor while replaying |
interface BarInput {
time: TimeInput;
open: number;
high: number;
low: number;
close: number;
volume?: number; // default 0
}
interface TradeInput {
time: TimeInput;
price: number;
size?: number; // added to the bar's volume, default 0
}A timeframe must be built from whole source bars: 5m, 15m, 1h, 1D from 1m; 1W and 1M from 1D; 4h but not 90s from 1m. Displayed bars take the first open, the highest high, the lowest low, the last close and the summed volume of their source bars, and are timed at the start of their period (calendar). A trade in the period of the last source bar updates it; a later one opens a new bar; one in an earlier period throws. set() keeps the timeframe when the new interval can still build it, and resets it to null otherwise. loadMore.before is the time of the first source bar.
Bar transforms
interface BarTransformInput {
type: string; // 'heikin-ashi', 'renko', 'range' (extras) or a registered type
params?: Record<string, unknown>;
}| Type | Parameters | Displayed bars |
|---|---|---|
heikin-ashi | none | Heikin-Ashi candles, one per bar of the timeframe |
renko | box: brick size | Bricks on the closes; a new brick needs a close one box beyond the last, a reversal two |
range | range: high-to-low of a bar | Bars spanning exactly range; the last one is still forming |
These transforms are extras: register them first. box and range default to the average true range of the last 14 bars, rounded to two significant digits; the size is kept while bars stream in and computed again when the bars are rebuilt (new data, timeframe or replay start). The transform stays when data or the timeframe changes. Indicators, alerts and markers work on the transformed bars. Renko and range bars are not periods of time: bricks completed in the same bar of the timeframe are a millisecond apart, and the bar countdown is hidden. See Timeframes and replay.
replay
Bar replay: a time cursor hides the source data after it. Timeframes, indicators, alerts, series and markers see only the revealed past, and a coarser timeframe shows its bar forming from the revealed source bars. Data keeps streaming in while replaying and stays hidden until the cursor reaches it. These calls emit no events; playback emits replay.
| Member | Description |
|---|---|
start(time: TimeInput, settings?: Partial<ReplaySettings>): void | Starts (or restarts) replay showing the source data up to and including time |
stop(): void | Ends replay and shows all data |
play(): void / pause(): void | Plays speed steps per second until the end |
step(count = 1): number | Advances count steps; returns how many were possible |
seek(time: TimeInput): void | Moves the cursor to any time at or after the first bar, forward or back |
configure(settings: Partial<ReplaySettings>): void | Changes the speed or the step, also while playing |
state(): ReplayState | null | The replay, or null when all data is shown |
interface ReplaySettings {
speed: number; // steps per second while playing, default 1
step: 'bar' | 'source'; // default 'bar'
}
interface ReplayState extends ReplaySettings {
time: number; // the last revealed source time
playing: boolean;
ended: boolean; // every source bar is revealed
}A bar step completes the displayed bar in progress or reveals the next one; a source step reveals one source bar. Alerts keep firing on revealed bars, with replay: true. The countdown of the latest bar is hidden while replaying.
timeScale
| Member | Description |
|---|---|
getVisibleRange(): TimeRange | null | Times of the first and last visible bars |
setVisibleRange({ from, to }): void | Shows the bars between two times |
getVisibleLogicalRange(): LogicalRange | null | Logical indices at the plot edges |
setVisibleLogicalRange(range: LogicalRange): void | Shows a logical index range |
scrollToTime(time, align?: 'left' | 'center' | 'right'): void | Default center |
scrollToIndex(index, align?): void | |
scrollToRealTime(): void | Back to the latest bar at the configured right offset |
isFollowing(): boolean | Whether the latest bar is in view, so new bars scroll into view |
fitContent(): void | Shows every bar |
zoomIn(): void / zoomOut(): void | Zooms by one step, keeping the latest bar in place when visible |
getBarSpacing(): number / setBarSpacing(px): void | Distance between bars |
reset(): void | Configured bar spacing and the real-time position |
timeToX(time): number | null / xToTime(x): number | null | Interpolated between bars, extrapolated beyond them |
indexToX(index): number | null / xToIndex(x): number | null |
priceScale
chart.priceScale(paneId = 'main', scaleId = 'right'): PriceScaleApiEach pane has a right scale, which drawings, orders and alerts use, and a left scale with an axis on the left of the plots, shown while something uses it. Any other id is an overlay scale without an axis. Series and indicators choose theirs with scale; each scale fits only what is on it.
// Volume under the bars, in the bottom fifth of the main pane.
chart.indicators.add({ type: 'VOL', pane: 'main', scale: 'volume' });
chart.priceScale('main', 'volume').setMargins({ top: 0.8, bottom: 0 });
// A second symbol on the left axis.
chart.series.add({ type: 'line', scale: 'left', title: 'ETH', data: ethPoints });| Member | Description |
|---|---|
getRange(): PriceRange | null | Visible value range |
setRange({ min, max }): void | Fixes the range and turns auto-scaling off |
autoScale(): void / isAutoScale(): boolean | Auto-scaling fits the visible data. Dragging or wheel-zooming the price axis turns it off (the plot can then also be dragged vertically); double-clicking the axis turns it back on |
getMode(): PriceScaleMode / setMode(mode): void | 'normal' | 'log' | 'percent' | 'indexed' |
isInverted(): boolean / setInverted(inverted): void | Higher values at the bottom |
getMargins() / setMargins({ top, bottom } | null): void | Space around the auto-scaled data, as fractions of the pane; null follows priceScale.margins |
priceToY(price): number | null / yToPrice(y): number | null | Chart coordinates |
While nothing is on the right scale it follows the left one, so drawings stay aligned. The left axis can be dragged and double-clicked like the right one. Coordinates, including layout() and pointer events, count from the chart's left edge, beyond a left axis.
Percent and indexed modes measure against the first visible value of the pane. While that base is unusable (zero, or negative for indexed mode) and while a logarithmic pane has no positive values, the pane is drawn in normal mode.
panes
The main pane ('main') is always first and takes the space the other panes leave. Indicators and series placed in 'new' get a pane of their own, which is removed with its last occupant.
| Member | Description |
|---|---|
list(): Pane[] | Panes from top to bottom |
get(id): Pane | null | |
add({ id, title?, height? }): void | Adds an empty pane at the bottom |
update(id, { title?, height? }): void | |
remove(id): void | Removes a pane and its drawings; its indicators and series must be removed first |
move(id, index): void | Reorders panes; the main pane stays at index 0 |
series
Additional series aligned to the main bars by time, such as a comparison symbol.
| Member | Description |
|---|---|
add(series: SeriesInput): string | Returns the id |
update(id, { title?, visible?, style?, scale? }): void | |
remove(id): void | Fails while an alert reads the series |
get(id) / list() | |
setData(id, points) / updateData(id, point | points) / prependData(id, points) | Same rules as data; aggregated to the timeframe (value series keep the last value of each period) and clipped by replay |
registerType(type, definition: SeriesTypeDefinition): void | Adds a custom series type to this chart |
types(): string[] | Available types |
interface SeriesInput {
id?: string;
type: string; // 'line', 'area', 'columns', 'candles', …
pane?: string; // 'main' (default), 'new' or a pane id
scale?: string; // 'right' (default), 'left' or an overlay scale id
title?: string;
visible?: boolean;
style?: Record<string, unknown>; // overrides of the type's style
data?: Array<{ time: TimeInput; value: number | null } | BarInput>;
}Built-in types: candles, hollow-candles, ohlc, high-low, hlc-area (OHLC points) and line, step-line, line-markers, area, baseline, columns (value points). Their style properties are listed by SeriesStyleMap; the main series uses the same types through options.mainSeries.
indicators
| Member | Description |
|---|---|
add(indicator: IndicatorInput): string | Returns the id |
update(id, { params?, source?, visible?, colors?, scale? }) | |
remove(id): void | Fails while an alert or an indicator reads it |
get(id) / list() | |
valuesAt(id, index?): IndicatorValue[] | Formatted values at a bar (default: the latest) |
register(type, definition: IndicatorDefinition): void | Adds a custom indicator type to this chart |
types(): string[] | Available types |
scale places an indicator on the right (default), left or an overlay scale of its pane, e.g. volume under the bars. source is a price field (close by default) or another indicator's output, { kind: 'indicator', id, key? }, e.g. a moving average of RSI (Indicators on indicators). See Indicators.
drawings
| Member | Description |
|---|---|
set(drawings: readonly DrawingInput[]): void | Replaces every drawing and clears the undo history |
add(drawing): string / update(id, patch) / remove(id) / clear() | Undoable steps |
get(id) / list() | |
startTool(type, { style?, text?, continuous? }?): void | Lets the user place a drawing; continuous keeps the tool active |
duplicate(id): string | Adds a copy as an undoable step |
bounds(id): DrawingBounds | null | Area of a drawing in chart coordinates, e.g. for a floating toolbar |
levels(id): string[] | Lines of a drawing alerts can watch, e.g. ['top', 'bottom'] |
editText(id): boolean | Edits a text drawing in place |
cancelTool(): void / activeTool(): string | null | |
undo() / redo(): boolean / canUndo() / canRedo(): boolean | |
registerType(type, definition: DrawingTypeDefinition): void | Adds a custom drawing type |
types(): string[] | Available types |
Built-in types: trend-line, ray, extended-line, arrow, horizontal-line, horizontal-ray, vertical-line, rectangle, parallel-channel, path, fib-retracement, price-range and text. Extras: fib-extension, date-range, date-price-range, long-position, short-position, pitchfork and callout. See Drawings.
orders
| Member | Description |
|---|---|
set(orders) / add(order) / update(id, patch) / remove(id) | |
get(id) / list() |
markers
| Member | Description |
|---|---|
set(markers) / add(marker) / update(id, patch) / remove(id) | |
get(id) / list() |
alerts
| Member | Description |
|---|---|
set(alerts) / add(alert) / update(id, patch) / remove(id) | |
get(id) / list() | Includes status and triggeredAt |
rearm(id): void | Arms an alert that fired with frequency once again |
Orders, markers and alerts are described in Trading.
crosshair
| Member | Description |
|---|---|
get(): CrosshairState | null | Where the crosshair is |
set({ time, price?, pane? }): void | Shows the crosshair without a pointer, e.g. to mirror another chart |
clear(): void |
interface CrosshairState {
x: number;
y: number;
paneId: string | null; // null over the time axis
index: number; // logical index, may lie beyond the data
time: number | null;
price: number | null; // value at y in the pane's scale
bar: Bar | null; // the hovered bar
}plugins
| Member | Description |
|---|---|
add(plugin: ChartPlugin): void | Attaches a plugin; names are unique |
remove(name: string): void | Detaches a plugin |
get(name): ChartPlugin | null | |
list(): string[] | Names in the order the plugins paint |
interface ChartPlugin {
name: string;
attach?(host: PluginHost): void; // when added
detach?(): void; // when removed or the chart is destroyed
paint?(context: PluginPaintContext): void; // per pane and layer ('below' or 'above' the series)
}withAlpha(color, alpha) is exported for plugins and custom drawings that need a translucent theme color. See Plugins.
Events
chart.on(type, listener) returns a function that unsubscribes. Listeners run after the operation that caused the event; errors thrown by listeners are rethrown after all listeners ran.
| Event | Payload | When |
|---|---|---|
crosshairMove | { visible: true, ...CrosshairState } | { visible: false } | The pointer moves over the chart or leaves it |
click / doubleClick | ChartPointerEvent | Includes the clicked target object, if any |
contextMenu | ChartPointerEvent | Listening suppresses the browser menu |
visibleRangeChange | { range, logicalRange } | The visible bars change, for any reason |
loadMore | { before } | Fewer than loadMoreThreshold bars remain hidden on the left |
selectionChange | { selection } | The user selects or deselects an object |
paneResize | { paneId, height } | The user finished dragging a pane separator |
drawingsChange | { reason, ids } | The user created, edited, removed, undid or redid drawings |
toolChange | { tool: null } | The drawing tool ended (finished or cancelled by the user) |
orderDrag / alertDrag | { id, phase, price, initialPrice } | phase is start, move, end or cancel |
buttonClick | { kind, id, buttonId } | A label button of an order or alert was clicked |
alertTrigger | { id, time, value, threshold, trigger, replay } | An alert condition was met; replay while replaying history |
replay | { state: ReplayState, reason: 'step' | 'end' } | Replay playback revealed data, or reached the end and paused |
interface ChartPointerEvent {
x: number;
y: number;
paneId: string | null;
index: number | null;
time: number | null;
price: number | null;
target: { kind: 'drawing' | 'order' | 'alert' | 'marker'; id: string; part: string } | null;
}Options
Defaults in parentheses.
| Option | Description |
|---|---|
autoSize (true) | Follow the container size |
locale (runtime default) | BCP 47 locale for numbers and dates |
timeZone (local) | IANA time zone, e.g. Asia/Shanghai |
theme (darkTheme) | Colors; lightTheme is exported too |
font.family, font.size (12) | Text of axes, legends and labels |
grid.vertical, grid.horizontal (true), grid.style (solid) | |
crosshair.mode (free) | free follows the pointer, magnet snaps to the close of the hovered bar |
crosshair.vertical, crosshair.horizontal, crosshair.labels (true), crosshair.style (dashed) | |
mainSeries.type (candles) | Any series type |
mainSeries.source (close) | Price plotted by line-like types: open, high, low, close, hl2, hlc3, ohlc4 |
mainSeries.styles ({}) | Style overrides per type, e.g. { candles: { upColor: '#0f0' } } |
mainSeries.barColor (null) | ({ index, bar, indicator }) => color | null colors single bars (Coloring bars) |
timeScale.visible (true), timeScale.height (28) | |
timeScale.barSpacing (8), minBarSpacing (0.5), maxBarSpacing (60) | Pixels per bar |
timeScale.rightOffset (60) | Space after the latest bar at the real-time position |
timeScale.loadMoreThreshold (20) | Bars hidden on the left that trigger loadMore |
timeScale.formatter (null) | (time, { kind, unit, locale, timeZone }) => string |
priceScale.visible (true), priceScale.minWidth (48) | |
priceScale.margins ({ top: 0.1, bottom: 0.08 }) | Space around auto-scaled data, as a fraction of the pane |
priceScale.precision ('auto') | Decimals of prices; auto infers them from the data |
priceScale.formatter (null) | (value, { paneId, mode, precision, locale }) => string |
latestPrice.line, latestPrice.label (true), latestPrice.countdown (false), latestPrice.style (dotted) | |
legend.visible (true) | OHLC and indicator values at the top of each pane |
interaction.pan, wheelZoom, pinchZoom, axisScale, kineticScroll, keyboard (true) | |
interaction.longPressMs (300) | Touch press that shows the crosshair |
interaction.touchMagnifier (true) | A loupe above the finger while placing anchors or dragging objects by touch |
panes.defaultHeight (120), panes.minHeight (40), panes.separatorHeight (5) | |
drawings.magnet (off) | weak snaps anchors near the bar's OHLC values, strong always; Ctrl/⌘ inverts it while held |
drawings.hitTolerance (6), drawings.handleRadius (5) | |
calendar.timeZone (null) | Zone of the trading calendar; null uses timeZone |
calendar.sessions ([]) | Trading sessions such as ['09:30-11:30', '13:00-15:00']; others are dropped. Empty: around the clock |
calendar.dayStart ('00:00') | Time a trading day starts, e.g. '21:00' for night sessions |
calendar.weekdays ([0, …, 6]) | Trading weekdays (0 = Sunday); other dates move to the next trading weekday |
calendar.weekStart (1) | First day of a week bar (0 = Sunday) |
calendar.bucket (null) | (time, interval, fallback) => number | null: overrides the period of a time, null drops it |
performance.maxPixelRatio (3) | Caps the canvas resolution |
texts ({}) | Words painted on the canvas, e.g. { target: 'TP' }; the rest follow locale (Chinese for zh) |
Keyboard
With interaction.keyboard, while the chart has focus: arrows scroll and zoom, End returns to real time, Escape cancels a drag or the drawing tool and clears the selection, Delete removes the selected drawing, Enter finishes a path, Ctrl/⌘ + C and Ctrl/⌘ + V copy and paste the selected drawing, Ctrl/⌘ + Z undoes and Ctrl/⌘ + Shift + Z or Ctrl + Y redoes. While drawing or dragging, Shift constrains the direction, Ctrl/⌘ inverts the magnet and Alt drags a copy.
Intervals and calendars
type IntervalInput = Interval | string; // '15s', '1m', '5m', '1h', '4h', '1D', '2D', '1W', '1M', '3M'
interface Interval {
unit: 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month';
count: number;
}
function parseInterval(input: IntervalInput): Interval;
function formatInterval(interval: IntervalInput): string; // canonical shorthand, e.g. '1D'
function createCalendar(options?: CalendarInput): Calendar;
interface Calendar {
/** Start of the bar of `interval` that `time` belongs to, or `null` when the calendar drops it. */
bucket(time: TimeInput, interval: IntervalInput): number | null;
}In shorthands m is minute and M is month; h, D and W may be lower or upper case. The calendar is the one the chart uses, with the options of calendar (its timeZone defaults to the local zone), so you can align your own data the same way. Intraday bars start at their session's start, daily, weekly and monthly bars at local midnight of their trading date. See Timeframes and replay.
Errors
Every invalid argument, unknown id or illegal call throws a ChartError (exported) whose message names the offending value, for example:
[kumochart] bars[3] (time 1714642260000) is older than the last bar (time 1714642320000). update() only replaces the last bar or appends newer ones; use set() or prepend() to change history.Operations validate before they change anything, so a thrown error leaves the chart as it was.