High-performance financial chart library with a single-frame generation time of just 2ms, stable scrolling at 190–200fps in a 200Hz environment, native support for AI Agent control, full-link ResizeObserver-driven crisp rendering, and a pluggable architecture.
English | 简体中文
Crisp Rendering · High Performance · Optimized Interaction · Mobile-Friendly
A lightweight financial K-line charting library focused on quantitative trading scenarios. Agent is a first-class citizen — supports AI Agent direct control of chart operations, providing TradingView-level interaction experience.
- Agent First / MCP Native - Supports AI Agent direct control of charts via the Model Context Protocol. Built-in WebSocket-bridged MCP server enables any MCP client (Inspector, Claude Desktop, Cursor, etc.) to zoom, pan, add/remove indicators, and change theme in real time
- Crisp Rendering - Full-chain ResizeObserver driven, physical pixel alignment, K-lines, wicks, and lines are sharp and clear on all DPR screens
- Plugin Architecture - Renderer plugin-based design, supporting dynamic registration, configuration, and lifecycle management
- Custom Markers - Supports semantic configuration of custom markers and custom information
- High Performance - Smoothly handles tens of thousands of data points, no lag during zoom or pan; supports 190-200fps on 200Hz displays with single-frame generation time as low as 2ms
- Multi-Backend Rendering - Submit drawing primitives once, render via WebGPU, WebGL, or Canvas2D. WebGPU provides hybrid DOM canvas (no
compositeTocopy), single-command-buffer-per-frame submission with 4x MSAA, and per-instance geometry caching via ResourceTable. Automatic fallback chain: WebGPU → WebGL → Canvas2D. Reaching 190fps on 200Hz displays with per-frame GPU time under 1ms - Optimized Interaction - Stable zoom anchor, precise crosshair cursor, smooth drag
- Mobile-Optimized Interaction - Long-press crosshair for data exploration, tap to dismiss, slide to browse data without triggering chart scroll, gesture-based scroll mode
- Multi-Symbol Comparison - Supports unlimited number of instruments for trend comparison
- Multi-Source Aggregation - Supports aggregation and unification of multiple data sources
- Batch Data Export - Select a date range and export multiple stocks' K-line data into a single CSV file, with progress indication
- Custom Tooltip - Fully customizable tooltip via named slots (
#kline-tooltip,#marker-tooltip), with engine-provided hover data, position, and styling
KLineChartQuant is a pnpm monorepo. The framework-agnostic core engine exposes a unified
ChartController (readonly signals + commands); Vue / React / Angular bindings only handle
mounting, event forwarding, and reactivity bridging. AI Agents drive the chart directly
through MCP over a WebSocket bridge.
flowchart TB
subgraph app["UI Layer / Framework Bindings"]
UI["UI Layer"]
VuePkg["@363045841yyt/klinechart<br/>Vue 3 components · useChart"]
ReactPkg["@363045841yyt/klinechart-react<br/>KLineChartWC (wraps Vue-built Web Component)"]
AngularPkg["@363045841yyt/klinechart-angular"]
Agent["AI Agent / MCP Client"]
AiRt["@363045841yyt/klinechart-ai-runtime"]
end
subgraph core["Core Engine @363045841yyt/klinechart-core"]
Ctl["ChartController<br/>signals + commands"]
Chart["Chart facade"]
Kernel["StateKernel<br/>Reactive SSOT"]
Data["Data Layer<br/>SeriesRepository · Buffers"]
Pipe["Rendering Pipeline<br/>FrameTransaction · Scene/Layer"]
GPU["WebGPU / WebGL2 / Canvas2D"]
Plugin["Plugin Subsystem<br/>PluginHost · RendererPlugin"]
Biz["Indicators · Markers · Drawing<br/>Timeshare · Compare · Components"]
end
subgraph conn["Market Data Backends"]
Go["GoTDX-Connecter<br/>gotdx :8080"]
Bn["GoTDX-Connecter<br/>Binance depth :8081"]
Bs["Baostock-Tradingview-Connecter<br/>BaoStock / TradingView :8000"]
end
UI --> VuePkg
UI --> ReactPkg
UI --> AngularPkg
VuePkg -->|"Web Component"| ReactPkg
Agent --> AiRt
VuePkg --> Ctl
ReactPkg --> Ctl
AngularPkg --> Ctl
AiRt -->|WebSocket / MCP| Ctl
Ctl --> Chart
Chart --> Kernel
Chart --> Data
Chart --> Pipe
Chart --> Plugin
Plugin --> Biz
Biz --> Pipe
Pipe --> GPU
Go -->|market data| Data
Bn -->|market data| Data
Bs -->|market data| Data
Kernel --> Data
Kernel --> Pipe
- Core engine — headless chart engine +
ChartController; depends on no UI framework. - StateKernel — single source of truth: readonly signals for reads, actions for writes,
computed()for derivation,effect()for DOM side effects. - Rendering — submit primitives once, render via WebGPU / WebGL2 / Canvas2D with automatic fallback (WebGPU → WebGL → Canvas2D).
- Data layer — unified
SeriesRepository+ incremental buffers + fetch scheduler; multi-source aggregation (gotdx / BaoStock / TradingView / mock) and Binance depth. - Plugin subsystem — PluginHost / HookSystem / EventBus / RendererPluginManager; indicators, markers and drawing tools plug in as Scene Layers.
- React via Web Component —
@363045841yyt/klinechart-react'sKLineChartWCrenders the<kline-chart>Custom Element bundled from the Vue package (@363045841yyt/klinechart/web-component). - MCP / Agent —
@363045841yyt/klinechart-ai-runtimebridges AI tool calls to the controller over WebSocket.
See docs/architecture.md for the full architecture document.
KLineChart requires a market data backend. Supported data sources:
| Data Source | Description | Docs |
|---|---|---|
gotdx | Tongdaxin (GOTDX) quotes: A-share / futures / MAC, served by GoTDX-Connecter | GoTDX-Connecter |
baostock | BaoStock A-share daily / weekly / monthly & minute K-lines, served by Baostock-Tradingview-Connecter | BaoStock |
tradingview | TradingView global instruments, served by Baostock-Tradingview-Connecter | BaoStock |
mock | Debug only: local MOCK-100 / MOCK-10000 K-lines, no backend needed, always online | — |
Backend repos live alongside this one (outside the monorepo).
Clone the data-source backends first (idempotent: skips directories that already exist):
pnpm setupThen run pnpm dev with a -c argument to start the frontend and the selected connecters together:
pnpm dev # frontend only (Vite dev server)
pnpm dev -c all # frontend + all backends (gotdx + binance + baostock)
pnpm dev -c gotdx baostock # frontend + selected backends
pnpm dev -c tdx # aliases supported (tdx / g / b / bnb / all)
pnpm dev -c all --lan # same, dev server bound to 0.0.0.0 (LAN accessible)Common shorthands:
pnpm dev:all # frontend + all backends
pnpm dev:g # frontend + gotdx (Tongdaxin)
pnpm dev:b # frontend + BaoStock / TradingView
pnpm dev:bnb # frontend + Binance depth
pnpm dev:lan:all # frontend (0.0.0.0) + all backendsParallel process logs stay in one terminal and are separated by colored source prefixes: [vite], [gotdx], [binance], and [baostock].
Backend only (no frontend):
pnpm connecter # all backends
pnpm connecter gotdx # gotdx (Tongdaxin) :8080
pnpm connecter baostock # BaoStock / TradingView :8000After pnpm setup, no extra setup is needed. The dev server proxies /api/stock → :8000 (Baostock-Tradingview-Connecter) and /api/public → :8080 (GoTDX-Connecter).
npm install @363045841yyt/klinechart @363045841yyt/klinechart-coreUse the component:
<template>
<divclass="app-container":data-theme="currentTheme">
<KlineChartv-model:theme="currentTheme" :custom-data="customData" :settings="chartSettings" />
</div>
</template>
<script setup lang="ts">import { ref } from'vue'importtype { ChartSettings } from'@363045841yyt/klinechart-core'import { typeCustomDataSource, KlineChart } from'@363045841yyt/klinechart'importdemoDatafrom'./demo-data.json'const currentTheme =ref<'light'|'dark'>('dark')const customData =ref<CustomDataSource>(demoDataasCustomDataSource)const chartSettings:ChartSettings= { showGridLines: true, isAsiaMarket: true, showVolumePriceMarkers: false, mainLeftAxisDisplaySetting: 'none', theme: 'dark', colorPresetSettings: { dark: { candleUpBody: '#e85d04', candleDownBody: '#1b4332', crosshairLine: '#faa307', gridMajor: '#3e2723', }, }, }</script>
<style>.app-container {display: flex;flex-direction: column;height: 80vh; }.app-container[data-theme='dark'] {background: #000;color: #e5e7eb; }</style>Import CSS in main.ts:
import'@363045841yyt/klinechart/style.css'import{createApp}from'vue'importAppfrom'./App.vue'createApp(App).mount('#app')Slot Usage — Custom Tooltip:
<KlineChart><template#kline-tooltip="{ hoverData, upColor, downColor }"><divclass="custom-tooltip"><divclass="custom-tooltip__title"><span>{{ hoverData.stockCode }}</span><span>{{ formatTimestamp(hoverData.timestamp, { timeZone: 'Asia/Shanghai' }) }}</span></div><divclass="custom-tooltip__price"
:style="{ color: hoverData.close >= hoverData.open ? upColor : downColor }"
>
{{ hoverData.close.toFixed(2) }}
</div><divclass="custom-tooltip__detail">
O: {{ hoverData.open.toFixed(2) }}<br/>
H: {{ hoverData.high.toFixed(2) }}<br/>
L: {{ hoverData.low.toFixed(2) }}<br/>
C: {{ hoverData.close.toFixed(2) }}
</div></div></template></KlineChart>Slot Usage — Custom Main-Pane Legend:
Providing #legend fully replaces the default Canvas legend. The slot scope is the full LegendTemplateContext (OHLC, timeshare, main indicators, comparisons, layout, colors).
<template #legend="{ index, currentBar, timeshare, indicators, comparisons, colors }">
<divclass="my-legend">
<!-- Custom fields added to KLineData[] for PR #98 are exposed through currentBar -->
<divv-if="currentBar"class="my-legend__row">
<span:style="{ color: currentBar.color }">
开盘 {{ currentBar.open.toFixed(2) }} 最高 {{ currentBar.high.toFixed(2) }} 最低
{{ currentBar.low.toFixed(2) }} 收盘 {{ currentBar.close.toFixed(2) }}
</span>
<spanv-if="currentBar.volumeText"> Vol {{ currentBar.volumeText }}</span>
</div>
<divv-if="timeshare"class="my-legend__row">
<span:style="{ color: timeshare.changeColor }">
现价 {{ timeshare.price.toFixed(2) }} 涨幅 {{ timeshare.changePercent.toFixed(2) }}%
</span>
</div>
<!-- Using main chart indicator legend data -->
<divv-for="indicator in indicators":key="indicator.name"class="my-legend__row">
<span>{{ indicator.name }}:</span>
<templatev-for="valueinindicator.values" :key="value.label">
<span:style="{ color: value.color }">
{{ value.label }} {{ value.value.toFixed(3) }}
</span>
</template>
</div>
<!-- Using comparison commodity data -->
<divv-for="comparison in comparisons":key="comparison.symbol"class="my-legend__row":style="{ color: comparison.percentColor }"
>
{{ comparison.symbol }}
{{ comparison.percent > 0 ? '+' : '' }}{{ comparison.percent.toFixed(2) }}%
</div>
</div>
</template>npm install @363045841yyt/klinechart-ai-runtime<template>
<divclass="app-container">
<KlineChart ref="chartRef" :mcp="mcpConfig" />
</div>
</template>
<script setup lang="ts">import { ref } from'vue'import { KlineChart } from'@363045841yyt/klinechart'import { executeTool } from'@363045841yyt/klinechart-ai-runtime'const chartRef =ref<InstanceType<typeofKlineChart> |null>(null)const mcpConfig = { wsUrl: 'ws://localhost:8080', autoReconnect: true,onToolCall: (call) => {const ctrl =chartRef.value?.getController?.()if (!ctrl) return { success: false, error: 'Controller not ready' }returnexecuteTool(ctrl, call) }, }</script>
<style>.app-container {height: 80vh; }</style>Then start the MCP server:
cd packages/ai-runtime
pnpm inspectConnect via MCP Inspector and call chart.zoomToLevel, indicators.add, etc.
- Rendering Pipeline - Current paint path: FrameTransaction, Scene/Layer, Renderer backends
| Prop | Type | Default | Description |
|---|---|---|---|
| semanticConfig | SemanticChartConfig | — | Semantic configuration (optional). When provided, drives chart data, indicators, markers and chart options |
| theme | 'light' | 'dark' | — | Chart theme. Use v-model:theme for two-way binding |
| isFullscreen | boolean | — | Controlled fullscreen state. Leave unbound for internal (non-controlled) mode |
| timezone | string | 'Asia/Shanghai' | Time zone for date/time display |
| yPaddingPx | number | 20 | Y-axis padding in pixels |
| minKWidth | number | 1 | Minimum K-line width (logical pixels) |
| maxKWidth | number | 50 | Maximum K-line width (logical pixels) |
| rightAxisWidth | number | 0 | Right price axis width |
| leftAxisWidth | number | 0 | Left price axis width (0 = hidden) |
| bottomAxisHeight | number | 24 | Bottom time axis height |
| priceLabelWidth | number | 60 | Price label extra width for showing change percentage |
| zoomLevels | number | 20 | Total number of zoom levels |
| initialZoomLevel | number | 3 | Initial zoom level (1 ~ zoomLevels) |
| customData | CustomDataSource | — | Inline data bundle: { symbol?, period?, data, comparisons? }. Bypasses the fetcher pipeline entirely. See example above |
| teleportContainer | string | HTMLElement | — | Teleport target for dropdowns/modals (CSS selector or element). Defaults to internal .chart-wrapper |
| mcp | McpConfig | — | MCP/AI runtime bridge config: { wsUrl?, autoReconnect?, onToolCall? }. See @363045841yyt/klinechart-ai-runtime |
- v0.10: AI-native chart support
- K-line zoom anchor stability, improved zoom feel
- Right axis detached from scroll container, completely solving clipping issues
- Blank area drawing support
- Limit vertical pan range to prevent viewport from leaving data
- Drawing system
- Right axis zoom
- Latest price line and right axis label style optimization
- Area primitive tools and rendering
- More advanced drawing tools
- Support for minute, multi-day, monthly, and yearly K-line display
- Support convert the drawing to quant code
| Package | Description | npm |
|---|---|---|
@363045841yyt/klinechart-core | Headless chart engine + controllers | npm |
@363045841yyt/klinechart | Vue 3 bindings | npm |
@363045841yyt/klinechart-react | React bindings | npm |
@363045841yyt/klinechart-angular | Angular bindings | npm |
@363045841yyt/klinechart-ai-runtime | MCP server + AI tool schemas (optional) | npm |
- v0.9.0 Self-developed Core-layer reactive state model migration, timing issues eliminated
- v0.9.0 Single-path Scene renderer + WebGPU backend (hybrid DOM canvas, no compositeTo), FrameTransaction reactivity, device-lost recovery, auto-fallback WebGPU → WebGL → Canvas2D
- v0.8 Symbol comparison, multi-source data aggregation
- v0.7 Renderer registration chain AOP refactoring with decorator syntax, monorepo split, Vue/React bindings (experimental), standalone core package, tokenized color system
- v0.6.10 Unified WebGL rendering context sharing for all panes, plus sub-pane lifecycle refactoring — centralized pane instance management via SubPaneManager with first-class paneId identity
- v0.6.6 Comprehensive rendering optimizations: batched price-to-Y calculations, cached tick positions and geometry, optimized month-key operations; achieves stable 190-200fps on 200Hz displays with frame generation time down to 2ms
- v0.6.3 WebGL rendering for K-lines, volume bars, and MACD bars; significant performance boost across the board
- v0.6.1 Dual-layer canvas architecture: Main + Overlay separation with UpdateLevel filtering, achieves stable 180fps with low jitter on 200Hz displays
- v0.6.0 Stateless indicator pipeline: MA/BOLL/EXPMA/ENE/RSI/CCI/STOCH/MOM/WMSR/KST/FASTK now use unified Calculator → Scheduler → StateStore → Renderer architecture for better performance and maintainability
- v0.5.6 Logarithmic price axis with evenly distributed grid lines at pixel level
- v0.5.2 Advanced drawing tools: parallel channel, regression channel, smooth top/bottom, and non-intersecting channel
- v0.5.0 Complete drawing tool system, supporting line, rectangle, text drawing and style editing
- v0.4 Modern UI, left toolbar, right axis optimization, TradingView-style zoom feel







