npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@chart-engine/core

v0.1.25

Published

Financial charting engine (WASM). Host-driven data — no market APIs. Candles, indicators, drawings, pan/zoom.

Downloads

301

Readme

@chart-engine/core

Your servers, your data — our charts.

Embeddable financial charting engine: WebAssembly core, WebGL renderer (Canvas2D fallback), optional full terminal UI. The library does not contain market data and never calls market APIs. Connect your backend via ExchangeAdapter, embed via iframe/postMessage, or use the built-in mock adapter to verify the install.

npm install @chart-engine/core

Live demo · Embed protocol ce:* 1.5 · Integration guide · MIT


Contents

  1. Overview
  2. Installation
  3. Quick start
  4. Widget constructor
  5. Featuresets
  6. Datafeed API (ExchangeAdapter)
  7. Resolutions, chart types, indicators
  8. Methods
  9. Host embed protocol (ce:* 1.5)
  10. React + Vite
  11. Mobile (WebView)
  12. URL / query flags
  13. Troubleshooting
  14. Versioning
  15. License
  16. Reference UI

0. Reference UI

Target look for parity work (NSE intraday, light theme). These ship in assets/reference/:

Clean 3m candles + volume — HDFCBANK 3m NSE, OHLC legend, BUY/SELL tickets, price line @ 2037.88, volume pane:

HDFCBANK 3m clean reference

Indicator stack + RSI pane — RELIANCE 3m NSE with RSI, EMA, Bollinger Bands, Parabolic SAR, Donchian overlays, volume pane, RSI-14 pane:

RELIANCE 3m indicators reference


1. Overview

Two integration paths, one engine:

| Path | API | Renders | Best for | |------|-----|---------|----------| | Full terminal UI | mountChartApp(container, options) | Iframe (dist/hosted or /ce-hosted) | Apps that want toolbar, drawings, tickets, widgets | | Canvas only | new ChartEngine({ container, … }) | Direct canvas in your page | Apps that draw their own chrome |

Rules:

  • The chart is a rendering surface. Symbols, history, ticks, depth, option chain, session levels, and OMS stay in the host app.
  • Standalone runs on a local mock adapter. Embedded, the host answers ce:request-candles and streams ce:tick.
  • Container must have non-zero width and height before mount, otherwise the chart is empty.

2. Installation

npm install @chart-engine/core

Requires a bundler that supports import.meta.url (Vite / webpack 5 / modern esbuild). ESM only:

import { mountChartApp, ChartEngine, registerAdapter } from "@chart-engine/core";
import { chartEngineHosted } from "@chart-engine/core/vite";

Package contents: dist/ (ESM + types), assets/, vite-plugin.mjs, and dist/hosted/ (built terminal UI, copied from apps/web at build time).


3. Quick start

A. Full UI (recommended)

import { mountChartApp } from "@chart-engine/core";

const widget = mountChartApp(document.getElementById("chart"), {
  symbol: "RELIANCE",
  interval: "5m",
  theme: "dark",
  autosize: true,
  disabled_features: ["widget_bar", "option_chain"],
});

// later
widget.destroy();

No OHLCV to pass for the mock check. Provide a sized container and the chart synthesizes a series for symbol.

B. Canvas only (your chrome)

import { ChartEngine } from "@chart-engine/core";

const engine = new ChartEngine({
  container: document.getElementById("chart"),
  initialAdapter: "mock",
  initialSymbol: "RELIANCE",
  initialTimeframe: "5m",
  onReady: (e) => e.fitAll(),
});

Full terminal UI = mountChartApp. No header/toolbar with bare ChartEngine — that is expected.

C. Your own datafeed

import { registerAdapter, mountChartApp } from "@chart-engine/core";

registerAdapter({
  key: "venue",
  label: "Venue",
  capabilities: { historical: true, live: true, intradayTimeframes: ["1m", "5m", "15m"], orders: "paper" },
  async searchSymbols(query) { return []; },
  async fetchHistory({ symbol, timeframe, limit }) { return []; },
  subscribe(symbol, timeframe, onCandle) {
    return { unsubscribe() {} };
  },
});

mountChartApp(el, { initialAdapter: "venue", symbol: "RELIANCE", interval: "5m" });

4. Widget constructor (mountChartApp)

mountChartApp(container, options) — mirrors the TradingView widget-constructor pattern: one container, one options object, feature flags to show/hide UI.

Returns { engine: null, destroy: () => void }. The UI runs in an iframe, so there is no direct engine handle — drive it via ce:* messages, query flags, or remount. Always call destroy() on unmount.

4.1 Options reference

| Name | Type | Default | Description | |------|------|---------|-------------| | container | HTMLElement \| string | — (required, first arg) | Mount node. Must have non-zero width × height. | | symbol | string | "RELIANCE" | Default symbol. Alias: initialSymbol. | | interval | string | "1m" | Resolution (see §7). Alias: initialTimeframe. Also sent as ?interval= + ?tf=. | | theme | "dark" \| "light" | "dark" | Chart theme. | | locale | string | — | Locale code, passed through to the shell (?locale=). | | autosize | boolean | true | Fill the container (width/height: 100%). | | fullscreen | boolean | false | Fullscreen layout (?fullscreen=1). | | initialAdapter | string | "mock" | Datafeed id (canvas path; iframe uses host protocol). | | features | Partial<Record<Featureset, boolean>> | all on | Map form: { order_panel: false } disables. | | disabled_features | string[] | [] | Featuresets to turn off (canonical or alias). | | enabled_features | string[] | [] | Featuresets to force on (removes from disabled set). | | hostedUrl | string | /ce-hosted/index.html | Override UI URL (advanced; options are appended as query flags). | | timezone | string | — | Accepted for TV parity; passed through where the shell supports it. |

Aliases: initialSymbol → symbol, initialTimeframe → interval.

new ChartEngine() takes instead: container, adapters, initialSymbol, initialTimeframe, initialAdapter, theme, accent, onReady.


5. Featuresets (disabled_features / enabled_features)

Same idea as TradingView disabled_features / enabled_features. Every block is on unless listed in disabled_features. enabled_features re-enables (wins over disabled).

Header

| Featureset | UI | |------------|-----| | header_widget | Entire top toolbar (alias: toolbar) | | header_symbol_search | Symbol search | | header_compare | Compare / overlay | | header_resolutions | Interval control | | header_chart_type | Chart type | | header_indicators | Indicators (alias: indicators) | | header_undo_redo | Undo / redo | | header_screenshot | Screenshot | | header_fullscreen_button | Fullscreen | | header_settings | Settings |

Chart

| Featureset | UI | |------------|-----| | left_toolbar | Drawing tools (alias: drawings) | | legend_widget | OHLC / study legend | | control_bar | Scale / VP / L2 strip | | timeframes_toolbar | Favorite intervals | | replay | Bar replay | | use_webgl | GPU renderer (alias: webgl; disabling appends ?webgl=0 → Canvas2D) |

Trading

| Featureset | UI | |------------|-----| | order_panel | Order ticket (alias: trade) | | buy_sell_buttons | Buy / sell controls |

Side panels

| Featureset | UI | |------------|-----| | widget_bar | Right widget dock (alias: widgets) | | watchlist | Watchlist | | data_window | Data window | | volume_profile | Volume profile (alias: volumeProfile) | | footprint | Footprint | | depth_of_market | L2 depth (alias: depth) | | option_chain | Options strip (alias: options) | | session_levels | PDH / PDL / VWAP (alias: levels) |

Alias table: toolbar → header_widget, drawings → left_toolbar, trade → order_panel, indicators → header_indicators, widgets → widget_bar, volumeProfile → volume_profile, depth → depth_of_market, options → option_chain, levels → session_levels, webgl → use_webgl.

Example — research chart, no trading:

mountChartApp(el, {
  disabled_features: ["order_panel", "buy_sell_buttons", "widget_bar", "option_chain"],
});

Example — map form (equivalent):

mountChartApp(el, {
  features: { order_panel: false, buy_sell_buttons: false },
});

6. Datafeed API (ExchangeAdapter)

Neither the widget nor the canvas build ships quotes. The library calls you; you return data asynchronously. This is the single contract every exchange implements — the engine never talks to a broker directly.

{ time, open, high, low, close, volume }  // time = Unix ms

| Method | Required | Signature | Description | |--------|----------|-----------|-------------| | searchSymbols | yes | (query: string, limit?: number) => Promise<SymbolInfo[]> | Symbol search. | | fetchHistory | yes | (req: { symbol, timeframe, start?, end?, limit? }) => Promise<Candle[]> | Historical bars. end pages older history (infinite scroll left). | | subscribe | yes | (symbol, timeframe, onCandle: (c: Candle) => void) => { unsubscribe: () => void } | Live stream. Call onCandle for every in-progress and closed candle. | | submitOrder | no | (order: OrderRequest) => Promise<OrderResult> | Live/paper orders (only for order-capable adapters). | | cancelOrder | no | (orderId: string) => Promise<void> | Cancel a pending order. | | getPositions | no | (symbol?: string) => Promise<Position[]> | Open positions. | | onPositionUpdate | no | (cb: (ps: Position[]) => void) => () => void | Position stream. |

Adapter metadata:

{
  key: "venue", label: "Venue",
  capabilities: { historical: true, live: true, intradayTimeframes: ["1m", "5m"], orders: "paper" },
  session?: { sessions?: Array<[number, number]>; timezone?: string; aroundTheClock?: boolean },
  priceFormat?: { decimals: number; grouping: "thousand" | "lakh" | "none"; prefix?: string; suffix?: string },
}

Helpers: registerAdapter, unregisterAdapter, getAdapter, listAdapters, mockAdapter. setIndianExchange / getIndianExchange configure lakh grouping. The mock adapter is pre-registered — keep it for install checks, switch via initialAdapter / setExchange(key).


7. Resolutions, chart types, indicators

7.1 Resolutions

1t 1s 5s 15s 30s 1m 3m 5m 15m 30m 1h 2h 4h 1d 1w 1M — 1t is the tick timeframe (host streams ce:tick); the rest are time-based.

7.2 Chart types (setChartType / ce:set-chart-type)

candles bars line area heikin-ashi (heikinashi) hollow-candles (hollow) baseline volume-candles hlc-area (hlc) renko kagi point-and-figure (pnf) line-break (linebreak) range-bars (range).

7.3 Indicators (addIndicator / ce:indicator)

Keys (aliases with -/_ accepted): sma (20), ema (20), ema-ribbon, ma-ribbon, rsi (14), macd (12, 26, 9), bollinger / bollinger_bands (20, 2), keltner (14, 2), donchian (20), supertrend (10, 3), parabolic-sar (0.02, 0.2), vwap, atr (14), stochastic (14, 3, 3), stoch-rsi, adx (14), momentum (10), roc (12), cci (20), williams-r (14), mfi (14), aroon (14), vortex (14), trix (15), ultimate, std-dev (14), volume-profile (24 bins), obv, ichimoku (9, 26, 52, 26), pivot-points, zigzag (5%), vwma (20), hma (16), alma (9, 0.85, 6), alligator (13, 8, 5), fractals (2), dpo (20), force-index (13), tsi (25, 13, 7), chaikin (3, 10).

engine.addIndicator("sma", { period: 20 });
engine.addIndicator("supertrend", { period: 10, multiplier: 3 });

Over ce:*: { action: "add"|"remove"|"clear"|"update", key?, index?, params? }.


8. Methods

mountChartApp exposes only destroy() (iframe boundary). All chart control below is the canvas ChartEngine handle (or the equivalent ce:* message in §9).

| Group | Method | Description | |-------|--------|-------------| | Symbol / feed | setSymbol(symbol) | Load a symbol | | | setTimeframe(tf) | Change interval | | | setExchange(key) | Switch adapter | | | onCandle(cb) | Live-candle hook → () => void | | Chart | setChartType(type) | Series style (§7.2) | | | setTheme("dark"\|"light"), setAccent(color) | Theme | | | fitAll() | Fit data | | | undo() / redo() | History | | Indicators | addIndicator(key, params?) / updateIndicator(i, key, params?) / removeIndicator(i) / listIndicators() | Studies (§7.3) | | Drawings | setDrawingTool(tool) / cancelDrawingTool() | Arm a drawing | | | listDrawings() / deleteDrawing(id) / deleteSelectedDrawing() / selectDrawing(id) | Manage | | | setDrawingColor/Locked/Group/Visible, setMagnetMode, saveDrawings/loadDrawings, saveLayout/loadLayout | Style + persist | | View | toggleGrid/Crosshair/LogScale/Volume/OrderBook/SessionLevels | Appearance | | Replay | startReplay(n) / stopReplay() / replaySeek/StepForward/StepBackward / isReplayActive() | Bar replay | | Backtest | runBacktest(json) / optimizeBacktest(json, fastLo, fastHi, slowLo, slowHi, step) | SMA-cross + optimizer | | Trading | buy(qty?) / sell(qty?) / closePosition() / getPositions() | Paper unless adapter is order-capable | | | placeBuyTrade/placeSellTrade/clearTradeMarkers/getTradeSummary/setOrderBook | Markers | | Data | detectPatterns(window?) | Candlestick patterns | | Lifecycle | screenshot() / getContainer/getCanvas / destroy() | Capture + dispose |

Keyboard (terminal UI): B buy · S sell · 1–9 qty · Esc close ticket.


9. Host embed protocol (ce:* 1.5, iframe / WebView)

For iframe / WebView the parent implements the datafeed over postMessage. Chart asks; host answers. Never put API tokens in the iframe.

Chart                         Your app
  ce:ready  ────────────────►   { version: "1.5" }
            ◄────────────────  ce:init { symbol, timeframe }
  ce:request-candles  ──────►
            ◄────────────────  ce:candles { requestId, candles }
  (live)    ◄────────────────  ce:tick { price, time }

Always reply to ce:request-candles with the same requestId. Shapes: candle { time, open, high, low, close, volume } (epoch ms); tick { price, time?, volume? }.

9.1 You → chart

| type | payload | |------|---------| | ce:init | { symbol?, timeframe?, candles?, theme?, chartType? } | | ce:pong | {} | | ce:candles | { requestId?, symbol, timeframe, candles } | | ce:tick | { price, time?, volume? } | | ce:candle | { candle } (pre-aggregated) | | ce:set-symbol | { symbol, timeframe? } | | ce:set-timeframe | { timeframe } | | ce:set-theme | { theme: "dark" \| "light" } | | ce:set-chart-type | { chartType } (§7.2) | | ce:indicator | { action: "add"\|"update"\|"remove"\|"clear", key?, index?, params? } | | ce:search-results | { requestId?, results } (reply to ce:request-search) | | ce:drawings | { symbol, json } (restore) | | ce:info | { requestId?, symbol, info? } | | ce:error | { requestId?, code, message } (timeout \| no_data \| invalid \| host_lost \| unknown) | | ce:fill / ce:order | { symbol?, side, price?, qty?, label? } markers | | ce:positions | { positions: [{ symbol, side, qty, avgPrice, stopLoss?, takeProfit?, sl?, tp?, unrealizedPnl? }] } | | ce:brackets | { symbol?, sl?, tp?, qty? } SL/TP lines | | ce:depth | { levels: [{ price, bid, ask }] } | | ce:footprint | { cells: [{ t, price, buy, sell }] } | | ce:chain / ce:option-chain | { rows: [{ strike, ce, pe, oi? }] } | | ce:levels | { symbol?, pdh?, pdl?, open?, vwap?, prevClose? } |

9.2 Chart → you

| type | you should | |------|------------| | ce:ready | send ce:init (version: "1.5") | | ce:ping | send ce:pong | | ce:open-search | your picker → ce:set-symbol | | ce:request-search | ce:search-results (optional) | | ce:request-candles | ce:candles (honor before) | | ce:request-info | ce:info (optional) | | ce:request-drawings | ce:drawings (optional) | | ce:trade | place order in your OMS: { symbol, side, orderType, price, qty, sl?, tp? } | | ce:brackets | SL/TP moved | | ce:alert | { title, body, price?, dir? } — persist/notify | | ce:request-depth | ce:depth | | ce:request-footprint | ce:footprint | | ce:request-chain | ce:chain | | ce:request-levels | ce:levels | | ce:select-strike | optional — user tapped options strip | | ce:notify | optional persist ({ symbol, timeframe, chartType, theme, indicators }) | | ce:drawings | persist; restore on request | | ce:error | timeout / no_data / host_lost |

Minimal host:

const ORIGIN = "https://chart-engine-ruby.vercel.app";
const w = document.getElementById("ce").contentWindow;
const send = (type, payload) => w.postMessage({ type, payload }, ORIGIN);

window.addEventListener("message", async (e) => {
  if (e.origin !== ORIGIN) return;
  const { type, payload } = e.data || {};
  if (type === "ce:ready") send("ce:init", { symbol: "RELIANCE", timeframe: "15m", theme: "dark" });
  if (type === "ce:ping") send("ce:pong", {});
  if (type === "ce:request-candles") {
    const candles = await yourApi.getBars(payload.symbol, payload.timeframe, payload.bars);
    send("ce:candles", { requestId: payload.requestId, symbol: payload.symbol, timeframe: payload.timeframe, candles });
  }
  if (type === "ce:open-search") {
    const symbol = await openYourSymbolPicker();
    if (symbol) send("ce:set-symbol", { symbol });
  }
  if (type === "ce:trade") await yourOms.place(payload);
});

Full executable reference: USING.md.


10. React + Vite

Self-host the UI (avoids CDN iframe) with the bundled Vite plugin, which copies dist/hosted → public/ce-hosted:

// vite.config.ts
import { chartEngineHosted } from "@chart-engine/core/vite";
import react from "@vitejs/plugin-react";

export default { plugins: [react(), chartEngineHosted()] };
useEffect(() => {
  const w = mountChartApp(ref.current!, {
    symbol: "RELIANCE",
    interval: "5m",
    disabled_features: ["widget_bar"],
  });
  return () => w.destroy();
}, []);

404 on /ce-hosted/ means the plugin is missing. Canvas-only alternative: new ChartEngine({ container, initialAdapter: "mock" }).


11. Mobile (WebView)

This package is JavaScript; it does not compile to Dart/Swift. Load the chart in a WebView and bridge postMessage:

WebViewController()
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..loadRequest(Uri.parse(
    'https://chart-engine-ruby.vercel.app/?symbol=RELIANCE&interval=5m',
  ));
  • React Native: react-native-webview onMessage + injectedJavaScript
  • iOS: WKWebView + WKScriptMessageHandler
  • Android: WebView + @JavascriptInterface

Do not set chromeless=1 if you need the header/toolbar. Prefer ?disabled_features=order_panel,widget_bar for chrome control.


12. URL / query flags

mountChartApp flags (appended automatically): symbol, interval, tf (= interval), theme, locale, fullscreen=1, disabled_features=a,b, webgl=0 (when use_webgl disabled).

Hosted-shell flags: ?chromeless=1 (chart pane only) · ?pro=1 (reduced chrome) · ?hide_drawings=1 · ?webgl=0 (Canvas2D) · ?origin=https://your.app · ?symbol= ?interval=/?tf=.


13. Troubleshooting

| Issue | Reason / fix | |-------|--------------| | Empty chart | Container height is 0 — give it real width × height; keep autosize: true | | 404 /ce-hosted/ | Add chartEngineHosted() to Vite config | | No header with ChartEngine | Expected — full UI is mountChartApp | | No tools in WebView | chromeless=1 is on — remove it or use disabled_features | | No bars / overlay stays empty | Host did not reply to ce:request-candles (match requestId); orderflow overlays need ce:depth/ce:footprint/ce:chain/ce:levels | | timeout / no_data / host_lost | See ce:error codes; check adapter fetchHistory and ping/pong |


14. Versioning

Semver. Protocol is versioned separately (PROTOCOL_VERSION, exported from the package; current 1.5). Check ce:ready.version / ce:ping in hosts and reject mismatches you cannot handle.


15. License

MIT