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 | 简体中文

📈 KLineChartQuant

Crisp Rendering · High Performance · Optimized Interaction · Mobile-Friendly

npm version npm downloads license demo

qq tg


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.

✨ Core Features

  • 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 compositeTo copy), 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

🚀 Quick Start

Prerequisites

KLineChart requires a stock data backend. Please ensure kmap and stockbao are in the same directory:

workspace/
├── KLineChartQuant/ # This repository
└── stockbao/    # Data backend repository

1. Clone Repositories

git clone https://github.com/363045841/KLineChartQuant.git
git clone https://github.com/363045841/stockbao.git

2. Start Data Backend

cd KLineChartQuant
npm run stockbao

After startup, the API is available at http://localhost:8000

3. Install and Use

npm install @363045841yyt/klinechart @363045841yyt/klinechart-core

Use the component:

<template>
  <div class="app-container" :data-theme="currentTheme">
    <KlineChart v-model:theme="currentTheme" :custom-data="customData" :settings="chartSettings" />
  </div>
</template>

<script setup lang="ts">
  import { ref } from 'vue'
  import type { ChartSettings } from '@363045841yyt/klinechart-core'
  import { type CustomDataSource, KlineChart } from '@363045841yyt/klinechart'
  import demoData from './demo-data.json'

  const currentTheme = ref<'light' | 'dark'>('dark')

  const customData = ref<CustomDataSource>(demoData as CustomDataSource)

  const chartSettings: ChartSettings = {
    showGridLines: true,
    isAsiaMarket: true,
    showVolumePriceMarkers: false,
    leftAxisType: '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'
import App from './App.vue'

createApp(App).mount('#app')

Slot Usage — Custom Tooltip:

<KlineChart>
  <template #kline-tooltip="{ hoverData, upColor, downColor }">
    <div class="custom-tooltip">
      <div class="custom-tooltip__title">
        <span>{{ hoverData.stockCode }}</span>
        <span>{{ formatTimestamp(hoverData.timestamp, { timeZone: 'Asia/Shanghai' }) }}</span>
      </div>
      <div
        class="custom-tooltip__price"
        :style="{ color: hoverData.close >= hoverData.open ? upColor : downColor }"
      >
        {{ hoverData.close.toFixed(2) }}
      </div>
      <div class="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 }">
  <div class="my-legend">
    <!-- Custom fields added to KLineData[] for PR #98 are exposed through currentBar -->
    <div v-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>
      <span v-if="currentBar.volumeText"> Vol {{ currentBar.volumeText }}</span>
    </div>

    <div v-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 -->
    <div v-for="indicator in indicators" :key="indicator.name" class="my-legend__row">
      <span>{{ indicator.name }}:</span>
      <template v-for="value in indicator.values" :key="value.label">
        <span :style="{ color: value.color }">
          {{ value.label }} {{ value.value.toFixed(3) }}
        </span>
      </template>
    </div>
    <!-- Using comparison commodity data -->
    <div
      v-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>

4. (Optional) Enable MCP / AI Agent Control

npm install @363045841yyt/klinechart-ai-runtime
<template>
  <div class="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<typeof KlineChart> | 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' }
      return executeTool(ctrl, call)
    },
  }
</script>

<style>
  .app-container {
    height: 80vh;
  }
</style>

Then start the MCP server:

cd packages/ai-runtime
pnpm inspect

Connect via MCP Inspector and call chart.zoomToLevel, indicators.add, etc.

📖 More Documentation

  • Rendering Pipeline - Current paint path: FrameTransaction, Scene/Layer, Renderer backends

📋 Component Props

Prop Type Default Description
semanticConfig SemanticChartConfig Semantic configuration (optional). When provided, drives chart data, indicators, markers and chart options
dataFetcher DataFetcher built-in Data fetching function. Defaults to an internal fetcher that proxies /api/stock
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

🗺️ Roadmap

  • 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

📦 Packages

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

🚀 What's New

  • 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

📄 License

MIT