romaco-charts
v1.0.0-beta.9
Published
A high-performance, modular trading chart library built with TypeScript and HTML5 Canvas.
Maintainers
Readme
Romaco Charts
AI-native trading charts for TypeScript and React, with Canvas2D/WebGPU rendering, built-in indicators and drawings, replay, paper trading, and a structured agent protocol for chart-assisted workflows.
What's new in v1.0.0-beta.9
- Rust/WASM is now the default compute backend. Zero-config inline lazy chunk (~76 KB / gzip ~29 KB), no bundler setup. Pass
engineBackend="ts"to opt out. (BREAKING) - MCP server (
@romaco/mcp) for Claude, Cursor, Claude Code, and any MCP client. Compression-first tools (typical output under 2 KB), gated raw payloads, and a<McpBridge />React component so a local AI agent can drive your live chart. - Cross-cell drawing sync in
TradingTerminalgrid mode. A drawing made on one cell mirrors to every sister cell that shares the same symbol, adapted to each cell's timeframe (TradingView-style). - Chart pop-out into independent browser windows. Any slot can detach onto a second monitor; live drawing sync keeps working across windows; closing the popup restores the chart in place.
- Per-drawing opacity and per-fibo-level colors with a refreshed context menu (slider + per-level color popover).
- Viewport, history backfill, and crosshair polish plus indicator-legend sync across grid cells.
- Drawing UX upgrades: brush quick-access button, hover cursors (crosshair/pointer/move), double-click a drawing to open its settings, spacebar-hold to pan while drawing, and a controllable drawing-toolbar visibility prop.
See the full release notes in CHANGELOG.md or the docs-site changelog.
Installation
npm install romaco-chartsInstall react and react-dom only when you use the React entry point.
Quick start: vanilla TypeScript
import { createChart, allTemplates } from 'romaco-charts'
import type { CandleDataInput } from 'romaco-charts'
const candles: CandleDataInput[] = [
{ time: 1714147200, open: 64100, high: 64520, low: 63840, close: 64310, volume: 1024 },
{ time: 1714147260, open: 64310, high: 64600, low: 64220, close: 64540, volume: 1188 },
]
const chart = createChart('#chart', {
preset: 'dark',
data: candles,
indicators: ['EMA', 'RSI'],
drawings: {
position: 'left',
templates: allTemplates,
},
})
chart.updateData({
time: 1714147320,
open: 64540,
high: 64710,
low: 64480,
close: 64660,
volume: 942,
})Use time as the preferred timestamp field. The library accepts seconds or milliseconds and normalizes both to milliseconds internally.
Quick start: React
import { TradingTerminal } from 'romaco-charts/react'
import type { CandleDataInput } from 'romaco-charts'
const candles: CandleDataInput[] = [
{ time: 1714147200, open: 64100, high: 64520, low: 63840, close: 64310, volume: 1024 },
{ time: 1714147260, open: 64310, high: 64600, low: 64220, close: 64540, volume: 1188 },
]
export function TradingView() {
return (
<div style={{ height: 720 }}>
<TradingTerminal data={candles} symbol="BTC/USDT" />
</div>
)
}Advanced TradingTerminal
import { useMemo, useRef, useState } from 'react'
import { TradingTerminal } from 'romaco-charts/react'
import type { TradingTerminalRef } from 'romaco-charts/react'
import { createNoopRealtimeSubscription } from 'romaco-charts/datafeed'
import type { CandleDataInput } from 'romaco-charts'
const candles: CandleDataInput[] = [
{ time: 1714147200, open: 64100, high: 64520, low: 63840, close: 64310, volume: 1024 },
{ time: 1714147260, open: 64310, high: 64600, low: 64220, close: 64540, volume: 1188 },
]
export function TradingDesk() {
const terminalRef = useRef<TradingTerminalRef>(null)
const [chart, setChart] = useState<TradingTerminalRef['api']>(null)
const datafeed = useMemo(() => ({
async searchSymbols() {
return [{ symbol: 'BTC/USDT', name: 'Bitcoin / Tether', type: 'crypto' as const }]
},
async resolveSymbol(symbol: string) {
return { symbol, supportedResolutions: ['1m', '5m', '15m', '1h', '4h', '1d'] }
},
async getHistory() {
return { bars: candles }
},
subscribeBars() {
return createNoopRealtimeSubscription()
},
}), [])
return (
<div style={{ height: 720 }}>
<button onClick={() => terminalRef.current?.api?.resetZoom()}>
Reset active chart
</button>
<TradingTerminal
ref={terminalRef}
datafeed={datafeed}
symbol="BTC/USDT"
preset="romaco"
onReady={setChart}
/>
</div>
)
}Use data as CandleDataInput[] for manual mode. When datafeed is present, TradingTerminal handles symbol search, history, and realtime internally and data becomes optional.
Beta.6 notes for React consumers:
symbolis reactive in feed-driven mode. Updating the prop after mount reloads history and replaces the realtime subscription for the active chart.onError(error, context)surfaces datafeed failures withcontextas'history','realtime', or'search'.historyBackfillTriggerdefaults to'pan'and loads older history when the user drags left and your datafeed returnsnextCursor.maxBarscaps the total number of bars kept in memory across the initial load and any backfill pages.onTimeframeChangenow emits canonical lowercase values such as1h,4h,1d,1w, and1mo. If your code compared against1Hor1M, update those checks.
Use MinimalChart when you only need the chart surface, Chart when you want a high-level wrapper with common indicators auto-registered, and useRomacoChart() when you need full imperative lifecycle control.
Main usage modes
createChart()for preset-driven setup with a compact config surface.new RomacoChart()for the full imperative API.MinimalChartfor chart-only React embedding with explicit indicator registration.TradingTerminalfor the full plug-and-play React workspace.ChartandRomacoChartReactfor the high-level React chart wrapper.useRomacoChart(),ChartGrid, and packaged UI components fromromaco-charts/reactfor custom React screens.ChartAgentControlleranduseChartAgent()for structured AI-assisted workflows.
Package entry points
| Entry point | Purpose |
| --- | --- |
| romaco-charts | Core class, factory API, presets, indicators, drawings, alerts, and utilities. |
| romaco-charts/react | React chart wrappers, the full TradingTerminal, hooks, ChartGrid, and React-oriented UI wrappers. |
| romaco-charts/agent | Agent controller and typed action/context contracts. |
| romaco-charts/datafeed | IDatafeed and realtime subscription contracts. |
| romaco-charts/drawings | Drawing manager, toolbar, templates, and drawing types. |
| romaco-charts/indicators | Tree-shakeable indicator entry point. |
| romaco-charts/profile | State and visual-state persistence types. |
| romaco-charts/replay | Replay controller types and implementation. |
| romaco-charts/renderers | Standalone renderers and renderer contracts. |
| romaco-charts/ui | Vanilla UI components and tokens. |
| romaco-charts/web-components | Custom element wrapper. |
React surface highlights
MinimalChartis the lean chart-only wrapper. It does not auto-register indicators, so you keep registration explicit.Chartis the convenience wrapper. It auto-registers the default React indicator set and keeps the current "just works" behavior.TradingTerminalmounts the complete terminal UI in one component and exposesonReady, an imperative ref escape hatch, feed-driven history/realtime wiring,onError, automatic history backfill, and a reactivesymbolprop.useRomacoChart()is the low-level hook for custom container ownership, runtime updates, and imperative chart access.
Public surface highlights
- Built-in indicators include
EMA,SMA,MA,BBI,BOLL,SAR,RSI,MACD,KDJ,KD,CCI,DMI,ROC,MTM,TRIX,VOL,OBV,EMV,PVT,VR,AO,WR,PSY,BIAS,DMA,BRAR,CR,AVP, andAVWAP. - Built-in presets include
dark,light,bloomberg,neon,professional,classic, andromaco. - Drawing tools, alerts, paper trading, export, replay, and state persistence are part of the public runtime API.
AI integration
The public agent surface stays on the client. Connect it to any service that returns structured ChartAction payloads.
import { ChartAgentController } from 'romaco-charts/agent'
const controller = new ChartAgentController(chart)
const context = controller.getChartContext()
controller.executeAction({
action: 'addIndicator',
indicatorType: 'EMA',
params: [20],
})The agent entry point also ships typed ChartContext, AgentRequest, AgentResponse, and ChartAction contracts for structured integrations.
Public beta note
This README is the current public reference for the beta package surface. When in doubt, the exported TypeScript entry points and the generated dist/*.d.ts files are the source of truth for the shipped API.
Rust engine (default, zero-config)
Starting with 1.0.0-beta.9, romaco-charts ships a Rust/WebAssembly compute backend embedded as a base64-encoded lazy chunk. Indicator calculations, downsampling, and hit-testing geometry run natively on Rust by default — no configuration, no extra plumbing in your bundler.
import { TradingTerminal } from 'romaco-charts/react';
// That's it. Rust runs automatically the first time the chart
// computes an indicator or downsamples a large series.
<TradingTerminal data={candles} symbol="AAPL" />The lazy chunk (wasm-runtime-*.js, ~76 KB gzipped ~29 KB) is emitted by your bundler and only fetched when the engine adapter is exercised. The main romaco-charts bundle does not grow.
Opt-out: if you want the pure-TypeScript engine (smaller transferred bytes if your app never triggers heavy compute), pass engineBackend="ts":
<TradingTerminal data={candles} engineBackend="ts" />External WASM hosting: to serve the binary from your own CDN or edge worker instead of the embedded base64, pass an explicit URL through the wasm prop:
<TradingTerminal
data={candles}
engineBackend="wasm"
wasm={{
modulePath: 'https://cdn.example.com/romaco_engine_wasm.js',
wasmBinaryPath: 'https://cdn.example.com/romaco_engine_wasm_bg.wasm',
}}
/>The raw dist/wasm/romaco_engine_wasm.js and _bg.wasm files ship in the npm tarball under the romaco-charts/wasm/* exports for that use case.
If the WASM load fails for any reason (CSP, missing application/wasm MIME, broken bundler asset pipeline), every operation falls back silently to the pure-TypeScript adapter — a single console.warn is emitted and the chart keeps working.
License
romaco-charts is source-available under BUSL-1.1. See LICENSE.
