Vela, our next-generation charting platform, is live at vela.luxalgo.com.
LuxAlgo

Options

Market, display, drawings, settings, and per-indicator options for Vela™ and the workspace.

View as Markdown

The second argument to new Vela(container, options, deps?) configures market data, display, and behavior. Everything here is optional — new Vela('#chart', { data: myBars }) is enough to render candles.

This vocabulary is shared with the workspace, which accepts every option below except height (plus its shell options) — there, each one is the DEFAULT of every cell, overridable per cell through cells.

Per-indicator options (the third argument to addIndicator) are covered at the end.

Market options

How the chart obtains its candles.

OptionTypeMeaning
symbolstringSymbol to load — the string is the WHOLE market identity. A bare ticker ('BTCUSDT') resolves against the registered providers in declaration order (first one whose index lists it); an EXCHANGE: prefix ('coinbase:BTC-USD', case-insensitive) pins the venue — a registered provider name, or a listing prefix a provider's index declares ('NASDAQ:AAPL', strict: a wrong venue resolves to nothing).
timeframestringBar interval, e.g. '1h'.
session'regular' | 'extended'Trading session to show, on markets that have one (regular = RTH, the default; extended = pre/post-market included). The flag rides every data request — providers without a session concept ignore it. Switch at runtime with chart.setMarket({ session }) or the bottombar's RTH/ETH toggle.
barsnumberHow many bars of history to load. Depths beyond one ~10k-bar chunk paint the recent window first, then backfill older bars in the background — watch history:progress / await chart.historyComplete() for the full depth.
visibleRangeVisibleRangePreset | {from,to}—
dataOHLCV[]Offline bars. When set, no network fetch happens.

data and provider fetch are mutually exclusive. Supply data to run fully offline (recommended for first runs and tests), or set symbol/timeframe/bars to fetch.

The fetch path needs a registered provider. No provider is bundled — register one with chart.data.registerProvider(...); registering it fires the chart's parked initial load. Each bar is { time, open, high, low, close, volume? } with time in epoch milliseconds.

With offline data, timeframe is still honored — it sets bar spacing and axis labels — while symbol and bars are ignored.

A fetching chart pairs these market options with a registered provider — the display flags ride along in the same object, and registering the provider fires the parked initial load.

import { Vela } from '@luxalgo/vela';
import { BinanceProvider } from '@luxalgo/vela/providers/binance';

const chart = new Vela('#chart', {
  symbol: 'BTCUSDT',        // bare = first registered provider that lists it; 'binance:BTCUSDT' pins
  timeframe: '1h',
  bars: 500,                // how many bars of history to load
  live: true,               // history + a forming candle on each tick
  theme: 'dark',
  logScale: true,           // logarithmic price scale
  currentPriceLine: true,   // dashed line + axis label at the last price
  upColor: '#26a69a',       // recolor the default cyan/white candles
  downColor: '#ef5350',
});

// registering the provider resolves the symbol and fires the fetch
chart.data.registerProvider('binance', new BinanceProvider());

Display & behavior options

OptionTypeDefaultNotes
livebooleanfalsetrue adds a forming candle + live ticks on top of history.
theme'dark' | 'light' or a theme objectdarkPass an object to fully customize colors/fonts.
rendererrenderer classnativeA renderer class to instantiate; omit for the built-in native renderer (default). The multi-renderer port (IChartRenderer) stays open — pass any class implementing it.
defaultLanguagestringfirst registered engine*Scripting language used when addIndicator doesn't name one. Falls back to the first engine registered at construction, then to 'pine'.
currentPriceLinebooleantrueDashed line + axis label at the latest price.
logScalebooleanfalseLogarithmic price scale.
nativeBackend'auto' | 'canvas2d' | 'webgl2'autoNative geometry backend. auto = WebGL2 if available, else canvas2d. Only applies to the native renderer.
animationsboolean or { zoom?, pan?, scroll?, autoscale?, liveBar?, intro? }ontrue/false toggles every motion; an object configures each on its own (see The animations option below). Defaults: eased zoom on, pan momentum on (short snappy glide), autoscale glide on, first-load reveal on, live-bar glide off.
glownumber0Neon glow/bloom for line series (~0.6 = strong). WebGL2 only — ignored on canvas2d.
upColorstring#089981 (green)Bullish candle color (native renderer).
downColorstring#f23645 (red)Bearish candle color (native renderer).
priceStyle'candles' | 'bars' | 'line' | 'area' | 'baseline''candles'How the base price series is drawn (native renderer).
drawingsboolean | { toolbar?, tools?, groups? }toolbar shownInteractive drawing tools. true/omitted ⇒ toolbar visible; false ⇒ toolbar hidden (the chart.drawings API still works headlessly); object customizes it (see below). Capability-gated (native renderer only).
settings{ hidden?: string[] }all visibleChart-settings dialog visibility policy: setting ids to hide — a whole tab, a group, or a single row (see below).
priceAxis{ ticks?: (ctx) => PriceAxisTick[] | null }built-in ticksYour own price-axis ladder (native renderer): ticks returns each pane's ticks, and the axis labels and horizontal gridlines both follow them (see below).

* defaultLanguage falls back to the first injected engine's language if you don't set it.

Leave renderer off for the built-in native backend; a custom renderer class (implementing IChartRenderer) can be passed to swap the whole rendering backend.

The drawings option

By default the drawing toolbar is shown (on a renderer that supports it). Pass false to hide the bar while still driving drawings from code, or an object to customize which tools appear:

FieldTypeEffect
toolbarbooleanShow/hide the bar (default true).
toolsDrawingTypeKey[]Allow-list of tools; each is bucketed into its own group.
groups{ id, label, tools }[]Explicit, custom-labelled groups (unregistered/empty groups are dropped).
// hide the bar but keep the programmatic API:
new Vela('#chart', { data: bars, drawings: false });

// only a few tools:
new Vela('#chart', { data: bars, drawings: { tools: ['trendline', 'hline', 'box'] } });

See Drawing tools for the full catalogue and the chart.drawings API.

The animations option

Every eased motion of the native renderer is configured on its own. Each field takes true (the built-in feel), false (instant — the motion is off), or a duration in milliseconds: the ease time-constant, after which the motion has covered about 63% of the remaining distance; it looks settled after roughly three of them. Durations are capped at 1000 ms.

FieldDefaultWhat it eases
zoomtrue (70 ms)The wheel zoom: bar spacing glides toward each notch's target instead of jumping. Off, the keyboard zoom keys of the widget jump too.
pantrue (110 ms)Pan momentum on touch: the velocity a finger flick releases with decays over this time. false = the chart stops dead on release. A mouse release always stops dead.
scrollfollows pan (130 ms)The programmatic scroll glide — the scroll-to-latest button, chart.panBy, the keyboard pan keys — easing the view to its target at constant zoom. Left unset it is on whenever pan is on, so { pan: false } still means an instant pan everywhere.
autoscaletrue (80 ms)The price scale's glide toward its new range while a zoom or fling is in flight (off = it snaps every frame).
liveBarfalseThe forming candle (and the current-price line and label) slide toward each live tick instead of snapping: true = a 90 ms ease. A new bar always snaps; the crosshair, legend and data window always show the real values.
introtrue ('settle', 650 ms)The first-load reveal: candles draw themselves in left to right. 'settle' overshoots and eases back, 'grow' eases out; false skips it; { style?, duration? } sets the style and/or the sweep duration in ms (capped at 5000).
new Vela('#chart', {
  animations: {
    zoom: 150,          // a slower, softer zoom glide
    pan: false,         // …but a drag release stops dead (and panBy is instant)
    liveBar: true,      // the forming candle glides to each tick
    intro: { style: 'grow', duration: 400 },
  },
});

Each motion is also a live renderer feature — animZoom, animPan, animScroll, animAutoscale, animLiveBar, intro — so chart.renderer.set('animZoom', 0) switches it off at runtime (see Renderer features). The settings dialog's Symbol → Animation group carries on/off switches for zoom, pan momentum (inertia and scroll glide together), the price scale, price changes (the live bar) and the reveal; switching one back on restores the duration configured here. In the rich config they are animations.{zoom, pan, autoscale, intro} plus priceScale.animateLastPrice.

The settings option — hiding settings-dialog entries

By default the chart-settings dialog shows everything. settings.hidden lists setting ids to hide; an id hides its whole subtree, and a tab with nothing left disappears from the rail:

new VelaWorkspace('#chart', {
  layout: false,
  bars: 1000,                                  // force the fetch depth…
  settings: { hidden: ['advanced'] },          // …and remove the tab that would change it
});

// or a finer cut: one group, one row
new Vela('#chart', { data: bars, settings: { hidden: ['canvas.grid', 'scales.price-scale.countdown'] } });

Hiding is display-only: hidden values keep being stored, delivered, and applied — which is exactly what makes "force an option, hide its control" work. The policy is instance state, not chart config: it never rides getConfig()/applyConfig() into exported templates. It can also be set at runtime with chart.renderer.setSettingsVisibility({ hidden: [...] }).

Ids are dot-separated paths: <tab>, <tab>.<group>, <tab>.<group>.<row>. Enumerate every addressable id of a live chart with chart.renderer.listSettingsIds() (plugin chart types and host-app sections included).

The complete catalog — every id, at every depth. Any subset works; a parent id makes its children redundant:

new VelaWorkspace('#chart', {
  settings: {
    hidden: [
      // ══ Symbol tab ════════════════════════════════════════════════
      'symbol',                              // the whole tab
      'symbol.type',                         //   the Type select (chart style)
      'symbol.style.candles',                //   Candles group (also styles Heikin Ashi)
      'symbol.style.candles.body',           //     Body toggle + up/down colors
      'symbol.style.candles.borders',        //     Borders toggle + colors
      'symbol.style.candles.wick',           //     Wick toggle + colors
      'symbol.style.candles.spacing',        //     Spacing
      'symbol.style.bars',                   //   Bars group
      'symbol.style.bars.up-color',          //     Color Up
      'symbol.style.bars.down-color',        //     Color Down
      'symbol.style.bars.spacing',           //     Spacing
      'symbol.style.line',                   //   Line group
      'symbol.style.line.color',             //     Color
      'symbol.style.line.width',             //     Width
      'symbol.style.area',                   //   Area group
      'symbol.style.area.line-color',        //     Line color
      'symbol.style.area.width',             //     Width
      'symbol.style.area.top-fill',          //     Top fill
      'symbol.style.area.bottom-fill',       //     Bottom fill
      'symbol.style.baseline',               //   Baseline group
      'symbol.style.baseline.top-line',      //     Top line
      'symbol.style.baseline.bottom-line',   //     Bottom line
      'symbol.style.baseline.fill-top',      //     Fill top area
      'symbol.style.baseline.fill-bottom',   //     Fill bottom area
      'symbol.style.baseline.base-level',    //     Base level %
      'symbol.style.baseline.width',         //     Width
      'symbol.animation',                    //   Animation group
      'symbol.animation.zoom',               //     Animate zoom (the wheel-zoom glide)
      'symbol.animation.pan',                //     Pan momentum (drag-release inertia + scroll glide)
      'symbol.animation.autoscale',          //     Animate price scale (the autoscale glide)
      'symbol.animation.price-changes',      //     Animate price changes (the live-bar glide)
      'symbol.animation.intro',              //     Reveal on load (the first-paint candle reveal)
      'symbol.timezone',                     //   Time zone group

      // ══ Scales and lines tab ══════════════════════════════════════
      'scales',                              // the whole tab
      'scales.price-scale',                  //   Price scale group
      'scales.price-scale.mode',             //     Regular/Percent/Indexed/Logarithmic
      'scales.price-scale.invert',           //     Invert scale
      'scales.price-scale.last-price-line',  //     Last Price Line
      'scales.price-scale.last-price-label', //     Last price label
      'scales.price-scale.countdown',        //     Countdown to bar close
      'scales.price-scale.axis-labels',      //     Axis labels
      'scales.price-scale.border-color',     //     Scale border color
      'scales.crosshair',                    //   Crosshair group
      'scales.crosshair.color',              //     Color
      'scales.crosshair.width',              //     Width
      'scales.crosshair.style',              //     Solid/Dashed/Dotted

      // ══ Canvas tab ════════════════════════════════════════════════
      'canvas',                              // the whole tab
      'canvas.background',                   //   Background & text group
      'canvas.background.color',             //     Background
      'canvas.background.text-color',        //     Text color
      'canvas.background.text-size',         //     Text size
      'canvas.background.pane-separator',    //     Pane separator color
      'canvas.grid',                         //   Grid group
      'canvas.grid.vertical',                //     Vertical lines toggle + color
      'canvas.grid.horizontal',              //     Horizontal lines toggle + color
      'canvas.margins',                      //   Margins group
      'canvas.margins.top',                  //     Top (% of pane height)
      'canvas.margins.bottom',               //     Bottom (% of pane height)
      'canvas.margins.right',                //     Right (bars after the newest bar)
      'canvas.theme',                        //   Theme group (Dark/Light)

      // ══ Events tab (timeline marks — present once marks name groups) ═
      'events',                              // the whole tab
      'events.groups',                       //   Visible events (one checkbox per mark group)
      'events.groups.<group-id>',            //     a group's checkbox (the group id, kebab-cased)

      // ══ Widget & workspace tabs (shell-contributed) ═══════════════
      'status-line',                         // the whole Status line tab
      'status-line.parts',                   //   Status line group (the five rows below)
      'status-line.logo',                    //     Symbol logo
      'status-line.name',                    //     Symbol name
      'status-line.market',                  //     Market status
      'status-line.ohlc',                    //     OHLC values
      'status-line.change',                  //     Bar change values
      'status-line.indicators',              //   Indicators group (the two rows below)
      'status-line.indicator-titles',        //     Titles
      'status-line.indicator-values',        //     Values
      'advanced',                            // the whole Advanced tab
      'advanced.bars',                       //   Bars to fetch
      'time-zone',                           // the workspace Time zone group in the Symbol tab
      'time-zone.zone',                      //   (same row — UTC, Exchange, then the catalog;
                                             //    it replaces the renderer's `symbol.timezone`)
      'trading-session',                     // the RTH/ETH group in the Symbol tab
      'trading-session.session',             //   Session select
      'trading-session.premarket-color',     //   Pre-market shading color (day-split markets)
      'trading-session.postmarket-color',    //   Post-market shading color (day-split markets)
      'trading-session.extended-color',      //   Extended-hours shading color (overnight markets)
      'watermark',                           // the Watermark group (the two rows below)
      'watermark.visible',                   //   Symbol watermark
      'watermark.replay',                    //   Replay watermark (the line under it while replaying)

      // ══ Plugin chart types (registerChartType) ════════════════════
      'type:<chartTypeId>',                  // the type's settings tab (+ its subsections)
      'type:<chartTypeId>.<key>',            //   a value row, by its settings bag key
      'type:<chartTypeId>.<heading-slug>',   //   a group, by its heading label's slug
      'type:<chartTypeId>.<subsection-slug>',//   a subsection, by its title's slug
      'symbol.style.<chartTypeId>',          // a candle-drawn plugin style's Candles group
                                             //   (rows: .body, .borders, .wick, .spacing)

      // ══ Host sections (setSettingsSections) ═══════════════════════
      '<sectionId>',                         // the section's `id` field, else its title's slug
      '<sectionId>.<rowId>',                 //   a row's `id` field, else its label's slug
    ],
  },
});

Conditional entries hide-and-stay-hidden: trading-session only appears on symbols that have sessions, status-line only when the shell's status line is on, canvas.theme only when the host wires the theme switch — hiding them is safe either way. Host sections contributed through setSettingsSections need nothing from the contributor: the id fields are optional stability aids, label slugs are the fallback.

The priceAxis option — custom price-axis ticks

priceAxis.ticks replaces the built-in tick ladder of the native renderer's price axes. It is called for each pane — the price pane and every study pane — and returns the ticks to draw. The axis labels and the horizontal gridlines both follow the same ticks, so they always line up.

new Vela('#chart', {
  data: bars,
  priceAxis: {
    // Emphasize the built-in levels and add a muted level between two of them
    // wherever there is room.
    ticks: ({ mode, defaults, priceToY }) => {
      if (mode !== 'price') return null; // keep the built-in percent/indexed ticks
      const out = [];
      defaults.forEach((tick, i) => {
        out.push({ ...tick, major: true });
        const next = defaults[i + 1];
        if (next && Math.abs(priceToY(next.price) - priceToY(tick.price)) > 40) {
          const mid = (tick.price + next.price) / 2;
          out.push({ price: mid, label: mid.toFixed(2), major: false });
        }
      });
      return out;
    },
  },
});

Each tick is { price, label, major? }: price places the gridline and the label, label is drawn as given, and major: true draws the label semibold, major: false draws it muted, while leaving major out draws the regular label. Gridlines look the same either way. A label too close to the top or bottom edge of its pane is skipped, as with the built-in ticks.

The function receives one context object per pane:

FieldMeaning
pane{ id, kind } — kind is 'price' or 'study'.
min, maxThe pane's visible range, in prices (also in percent and indexed mode).
logWhether the pane's scale is logarithmic.
heightThe pane height in CSS pixels.
mode'price', 'percent' or 'indexed' — how the axis labels read this frame.
baselineThe percent/indexed baseline price (undefined in price mode).
mintickThe symbol's tick size, when known.
fontSizeThe axis font size in pixels.
priceToY(price)A price's y within the pane, in CSS pixels (log and inverted scales included).
defaultsThe built-in ticks for this frame — return them, or a filtered or extended copy, to build on them.
  • Return null or undefined to keep the built-in ticks, or an empty array to draw none.
  • Entries with a non-finite price or a non-string label are dropped.
  • If the function throws, the pane keeps its built-in ticks and the console shows one warning for the chart.
  • A pane whose indicator declares its own axis (a blank or categorical axis) draws no price ticks and never calls the function. The extra scale column of an indicator merged onto its own scale keeps its built-in ticks.
  • The function runs again only when a pane's range, height, mode, baseline, tick size or font size changes. If your ticks depend on your own state, set the function again to recompute them.

The option seeds the native renderer's runtime priceAxisTicks feature: change or clear it later with chart.renderer.set('priceAxisTicks', fn) or null (see Renderer features). A function is never part of getConfig(). On a workspace, the top-level priceAxis is the default of every cell, including cells a later layout change creates.

Non-obvious defaults, called out

  • Animations are on by default (eased zoom, snappy inertial pan).
  • The current-price line is on by default.
  • The price scale is linear by default (logScale: false).

Instead of 'dark'/'light', pass a full theme object to control every color and the font — all seven fields are required:

const midnight = {
  background:  '#0b0e14',
  textColor:   '#c9d1d9',
  gridColor:   '#1c2230',
  borderColor: '#30363d',
  upColor:     '#3fb950',
  downColor:   '#f85149',
  fontFamily:  'Inter, system-ui, sans-serif',
};

new Vela('#chart', { data: bars, theme: midnight });

The theme can also be swapped at runtime — chart.setTheme('light') (or a full theme object) re-skins the chart live and emits theme:changed so your surrounding UI can follow; users reach the same switch in chart settings → Canvas → Theme. The built-in dark and light themes share the same candle colors, so switching never recolors the series. Setting only a background color through the settings dialog (or applyConfig) keeps the app theme: when that background lands in the other luminance class (a white plot on the dark theme), the derived inks — text, grid, axis border — re-base automatically so legends and axis labels stay readable, while any explicitly chosen text color wins.

Capability-gated options

Some options only take effect when the active backend supports them. glow is WebGL2-only — it is silently ignored on the canvas2d backend. If you force nativeBackend: 'canvas2d', glow has no effect.

A native-renderer styling combo: draw price as a glowing line on the GPU backend and make panning instant while keeping the eased zoom.

new Vela('#chart', {
  data: bars,
  priceStyle: 'line',                 // candles | bars | line | area | baseline
  nativeBackend: 'webgl2',            // force the GPU backend
  glow: 0.6,                          // neon bloom on line series (WebGL2 only)
  animations: { zoom: true, pan: false }, // eased zoom, no pan momentum
});

Per-indicator options

The optional second argument to addIndicator(source, options) — runIndicator and runScript take the same object:

OptionTypeMeaning
idstringThe indicator's id on the chart — an opaque, non-empty string you own (a document key, an editor tab, a UUID). It is what handle.id, chart.indicators(), the indicator:* events, script:run and the legend/pane surfaces carry, so you can address the indicator without keeping a side map. Omit it and the chart mints one — stable while the indicator stays on the chart, not across reloads. An id already live on the chart is rejected, never renamed: addIndicator throws, runIndicator/runScript resolve { ok: false, error }. Removing the indicator frees its id.
languagestringWhich registered engine runs this script. Defaults to the chart's defaultLanguage.
inputsRecord<string, InputValue>Input overrides, keyed by input title or key.
propsRecord<string, InputValue>Declaration-property overrides (a strategy's initial_capital, an indicator's precision, …), keyed like the engine's props schema. Ignored by engines without props support.
overlaybooleanForce overlay vs. separate pane. Default: read from indicator(overlay=…).
pane'price' | 'new'Explicit pane placement.
titlestringDisplay title override.

See API reference for the IndicatorHandle you get back, and Quickstart for the end-to-end flow.

On this page