Skip to content

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.

Conventions ​

  • Time (TimeInput) is epoch milliseconds, an ISO-8601 string or a Date. The chart always returns epoch milliseconds.
  • Coordinates are CSS pixels relative to the chart's top-left corner.
  • Logical indices count bars: bar i is centered on index i. 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 ​

ts
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:

ExtraRegistered as
heikinAshiTransform, renkoTransform, rangeTransformTransforms heikin-ashi, renko, range (data.registerTransform)
longPosition, shortPosition, pitchfork, fibExtensionDrawing types long-position, short-position, pitchfork, fib-extension
dateRange, datePriceRange, calloutDrawing types date-range, date-price-range, callout
ts
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 use

Using 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 ​

MemberDescription
element: HTMLElementThe element the chart created inside its container
options(): ChartOptionsThe resolved options, frozen; change them with applyOptions
applyOptions(options: ChartOptionsInput): voidDeep-merges option changes; arrays and functions are replaced
layout(): LayoutRectangles of panes, axes and separators, for positioning HTML overlays
resize(width, height): voidSets the size; with autoSize the container size wins on its next change
batch(operation: () => void): voidRuns several calls and dispatches their events once afterwards
on(type, listener): UnsubscribeSubscribes to an event
select(selection: Selection | null): voidSelects a drawing, order, alert or marker
selection(): Selection | nullThe selected object
saveState(): ChartStateThe user's layout: main series type, view, panes, indicators, drawings
loadState(state: ChartState): voidRestores a layout atomically; invalid states throw and change nothing
screenshot(): HTMLCanvasElementRenders pending changes and returns a canvas of the whole chart
destroy(): voidRemoves the element and releases all resources
ts
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.

MemberDescription
set(bars: readonly BarInput[], options?: { interval? }): voidReplaces 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[]): voidReplaces the last source bar (same time) or appends newer bars. Rejects older bars
addTrades(trade: TradeInput | readonly TradeInput[]): numberFolds trades into the source bars; needs a source interval. Skips trades the calendar drops, returns how many were applied
prepend(bars: readonly BarInput[]): numberInserts older source bars; ignores bars at or after the first bar; returns how many were inserted
clear(): voidRemoves the bars and ends a running replay; the interval and timeframe stay
sourceInterval(): Interval | nullResolution of the source bars
timeframe(): Interval | nullThe displayed timeframe; null is the source resolution
setTimeframe(timeframe: IntervalInput | null): voidAggregates the source to a coarser timeframe without refetching; null shows the source resolution
transform(): BarTransformInput | nullThe transform building the displayed bars
setTransform(transform: BarTransformInput | null): voidBuilds 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: numberNumber of displayed bars
at(index: number): Bar | nullThe displayed bar at an index
last(): Bar | nullThe latest displayed bar
indexOf(time: TimeInput): numberIndex of the displayed bar with exactly this time, or -1
toArray(): Bar[]A copy of the displayed bars
bars: BarsViewThe displayed bars as a read-only columnar view, without copying (BarsView)
source: BarsViewThe source bars as a view, up to the cursor while replaying
ts
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 ​

ts
interface BarTransformInput {
  type: string; // 'heikin-ashi', 'renko', 'range' (extras) or a registered type
  params?: Record<string, unknown>;
}
TypeParametersDisplayed bars
heikin-ashinoneHeikin-Ashi candles, one per bar of the timeframe
renkobox: brick sizeBricks on the closes; a new brick needs a close one box beyond the last, a reversal two
rangerange: high-to-low of a barBars 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.

MemberDescription
start(time: TimeInput, settings?: Partial<ReplaySettings>): voidStarts (or restarts) replay showing the source data up to and including time
stop(): voidEnds replay and shows all data
play(): void / pause(): voidPlays speed steps per second until the end
step(count = 1): numberAdvances count steps; returns how many were possible
seek(time: TimeInput): voidMoves the cursor to any time at or after the first bar, forward or back
configure(settings: Partial<ReplaySettings>): voidChanges the speed or the step, also while playing
state(): ReplayState | nullThe replay, or null when all data is shown
ts
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 ​

MemberDescription
getVisibleRange(): TimeRange | nullTimes of the first and last visible bars
setVisibleRange({ from, to }): voidShows the bars between two times
getVisibleLogicalRange(): LogicalRange | nullLogical indices at the plot edges
setVisibleLogicalRange(range: LogicalRange): voidShows a logical index range
scrollToTime(time, align?: 'left' | 'center' | 'right'): voidDefault center
scrollToIndex(index, align?): void
scrollToRealTime(): voidBack to the latest bar at the configured right offset
isFollowing(): booleanWhether the latest bar is in view, so new bars scroll into view
fitContent(): voidShows every bar
zoomIn(): void / zoomOut(): voidZooms by one step, keeping the latest bar in place when visible
getBarSpacing(): number / setBarSpacing(px): voidDistance between bars
reset(): voidConfigured bar spacing and the real-time position
timeToX(time): number | null / xToTime(x): number | nullInterpolated between bars, extrapolated beyond them
indexToX(index): number | null / xToIndex(x): number | null

priceScale ​

ts
chart.priceScale(paneId = 'main', scaleId = 'right'): PriceScaleApi

Each 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.

ts
// 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 });
MemberDescription
getRange(): PriceRange | nullVisible value range
setRange({ min, max }): voidFixes the range and turns auto-scaling off
autoScale(): void / isAutoScale(): booleanAuto-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): voidHigher values at the bottom
getMargins() / setMargins({ top, bottom } | null): voidSpace around the auto-scaled data, as fractions of the pane; null follows priceScale.margins
priceToY(price): number | null / yToPrice(y): number | nullChart 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.

MemberDescription
list(): Pane[]Panes from top to bottom
get(id): Pane | null
add({ id, title?, height? }): voidAdds an empty pane at the bottom
update(id, { title?, height? }): void
remove(id): voidRemoves a pane and its drawings; its indicators and series must be removed first
move(id, index): voidReorders panes; the main pane stays at index 0

series ​

Additional series aligned to the main bars by time, such as a comparison symbol.

MemberDescription
add(series: SeriesInput): stringReturns the id
update(id, { title?, visible?, style?, scale? }): void
remove(id): voidFails 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): voidAdds a custom series type to this chart
types(): string[]Available types
ts
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 ​

MemberDescription
add(indicator: IndicatorInput): stringReturns the id
update(id, { params?, source?, visible?, colors?, scale? })
remove(id): voidFails 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): voidAdds 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 ​

MemberDescription
set(drawings: readonly DrawingInput[]): voidReplaces 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? }?): voidLets the user place a drawing; continuous keeps the tool active
duplicate(id): stringAdds a copy as an undoable step
bounds(id): DrawingBounds | nullArea 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): booleanEdits a text drawing in place
cancelTool(): void / activeTool(): string | null
undo() / redo(): boolean / canUndo() / canRedo(): boolean
registerType(type, definition: DrawingTypeDefinition): voidAdds 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 ​

MemberDescription
set(orders) / add(order) / update(id, patch) / remove(id)
get(id) / list()

markers ​

MemberDescription
set(markers) / add(marker) / update(id, patch) / remove(id)
get(id) / list()

alerts ​

MemberDescription
set(alerts) / add(alert) / update(id, patch) / remove(id)
get(id) / list()Includes status and triggeredAt
rearm(id): voidArms an alert that fired with frequency once again

Orders, markers and alerts are described in Trading.

crosshair ​

MemberDescription
get(): CrosshairState | nullWhere the crosshair is
set({ time, price?, pane? }): voidShows the crosshair without a pointer, e.g. to mirror another chart
clear(): void
ts
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 ​

MemberDescription
add(plugin: ChartPlugin): voidAttaches a plugin; names are unique
remove(name: string): voidDetaches a plugin
get(name): ChartPlugin | null
list(): string[]Names in the order the plugins paint
ts
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.

EventPayloadWhen
crosshairMove{ visible: true, ...CrosshairState } | { visible: false }The pointer moves over the chart or leaves it
click / doubleClickChartPointerEventIncludes the clicked target object, if any
contextMenuChartPointerEventListening 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
ts
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.

OptionDescription
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 ​

ts
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.

Released under the MIT license.