Skip to content
rekurtPublic

About

Framework-agnostic TypeScript candlestick charts with indicators, drawing tools, and React and Vue wrappers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

OpenKline

A fast, framework-agnostic OHLCV charting engine for the web

Canvas-rendered candlesticks, TypedArray data buffers, an explicit auto-follow state machine, keyboard-first UX, and pluggable indicators, drawings & transports — with first-class React and Vue wrappers at full API parity.

CI License: MIT TypeScript Tests Bundle

Live Playground · API Reference · Guides · Comparison · Changelog · All projects by rekurt

OpenKline playground in dark mode showing candlesticks, an SMA overlay, and volume bars from synthetic BTC/USDT demo data

Actual playground screenshot with synthetic demo candles; no live exchange feed. Try the interactive playground.


Table of contents


Why OpenKline

⚡ Built for throughput TypedArray (Float64Array) candle buffers, O(1) append/update, RAF-coalesced tick merging, and a three-layer canvas split so a moving crosshair never repaints the chart.
🧩 Framework-agnostic core All rendering, data and interaction logic lives in @rekurt/openkline-core with zero runtime dependencies. React and Vue are thin, idiomatic wrappers — not reimplementations.
🎯 Full API parity The same declarative props and imperative methods across vanilla, React and Vue. Indicators are plain config objects; chart state round-trips through saveLayoutState / loadState.
⌨️ Keyboard-first & accessible Pan, zoom and navigate without a mouse. Honors prefers-reduced-motion and prefers-color-scheme.
📈 Batteries included 25+ indicators, 10 drawing tools, alerts, compare mode, volume profile, Heikin-Ashi & Renko transforms, SVG/PNG export, and an 'auto' dark/light theme.
🔒 Strict & tested Strict TypeScript (incl. noUncheckedIndexedAccess), 0 lint warnings in CI, and 440+ unit tests covering rendering math, indicators and state.

Packages

Package Repository What it is
@rekurt/openkline-core this repo Framework-agnostic rendering + data + interaction (no React/Vue).
@rekurt/openkline-react rekurt/openkline-react React 18+/19 wrapper — <OHLCVChart> component + useOHLCVChart hook.
@rekurt/openkline-vue rekurt/openkline-vue Vue 3 wrapper — <OHLCVChart> component + useOHLCVChart composable.

The React and Vue wrappers were extracted from this monorepo into their own repositories — each ships its own demo app, tests and CI.


Install

# Vanilla TypeScript / bring-your-own framework
npm install @rekurt/openkline-core

# React
npm install @rekurt/openkline-core @rekurt/openkline-react

# Vue 3
npm install @rekurt/openkline-core @rekurt/openkline-vue

For development from a repository checkout, the wrapper repos use a tested core tarball. Application installations use the npm packages shown above.


Quick start

Vanilla TypeScript

import { OHLCVChart } from '@rekurt/openkline-core';

const container = document.createElement('div');
container.style.cssText = 'width: 100%; height: 400px';
document.body.appendChild(container);

const chart = new OHLCVChart({
  container,
  symbol: 'BTC/USDT',
  resolution: '1H',
  theme: 'auto',
  onError: (err) => console.error('[openkline]', err),
});

// Small synthetic hourly dataset.
chart.setData([
  { o: 42000, h: 42100, l: 41900, c: 42050, v: 1000, t: 1700000000 },
  { o: 42050, h: 42200, l: 42000, c: 42100, v: 1200, t: 1700003600 },
  { o: 42100, h: 42250, l: 42050, c: 42150, v: 1600, t: 1700007200 },
]);

// Replace the current last candle with a synthetic update.
chart.updateLastCandle({
  o: 42100, h: 42300, l: 42050, c: 42200, v: 1800, t: 1700007200,
});

// When removing this view, call chart.destroy().

React

Lives in rekurt/openkline-react.

import { useRef, useMemo } from 'react';
import { OHLCVChart, type OHLCVChartRef } from '@rekurt/openkline-react';
import type { Candle, IndicatorConfig } from '@rekurt/openkline-core';

export function App({ candles }: { candles: Candle[] }) {
  const chartRef = useRef<OHLCVChartRef>(null);

  // Indicators are a plain config array — no `new SMA(20)` in user code.
  const indicators = useMemo<IndicatorConfig[]>(
    () => [
      { type: 'sma', period: 20 },
      { type: 'ema', period: 50 },
      { type: 'bb', period: 20, stdDev: 2 },
    ],
    [],
  );

  return (
    <div style={{ width: '100%', height: 600 }}>
      <OHLCVChart
        ref={chartRef}
        symbol="BTC/USDT"
        resolution="1H"
        data={candles}
        theme="auto"
        chartType="candles"
        indicators={indicators}
        onHover={(info) => console.log('hovered', info?.index)}
        onError={(err) => console.error('[openkline]', err)}
      />
      <button onClick={() => chartRef.current?.goToLive()}>Go live</button>
    </div>
  );
}

Vue 3

Lives in rekurt/openkline-vue.

<script setup lang="ts">
import { ref } from 'vue';
import { OHLCVChart } from '@rekurt/openkline-vue';
import type { Candle, IndicatorConfig } from '@rekurt/openkline-core';

defineProps<{ candles: Candle[] }>();

const chartRef = ref<InstanceType<typeof OHLCVChart>>();
const indicators = ref<IndicatorConfig[]>([
  { type: 'sma', period: 20 },
  { type: 'rsi', period: 14 },
]);
</script>

<template>
  <div style="width: 100%; height: 600px">
    <OHLCVChart
      ref="chartRef"
      symbol="BTC/USDT"
      resolution="1H"
      :data="candles"
      theme="auto"
      chart-type="candles"
      v-model:indicators="indicators"
      @hover="(info) => console.log('hovered', info?.index)"
      @error="(err) => console.error('[openkline]', err)"
    />
    <button @click="chartRef?.goToLive()">Go live</button>
  </div>
</template>

What's in the box

Rendering
  • Candlesticks, volume bars, grid, price/time axes, crosshair with snap-to-candle, current-price label, legend, and a "Go to live" pill.
  • Chart types: candles, line, area (with gradient), OHLC bars, and first-class Heikin-Ashi (chartType: 'heikinashi' — no manual transform).
  • Hi-DPI canvas with a three-layer split (chart / UI / interaction) for cheap crosshair redraws.
  • Multi-pane rendering: sub-pane indicators (RSI, MACD, Stochastic, ATR, WilliamsR, OBV, ADX, CCI) render in auto-sized vertical bands with independent Y-axes, labels and zero-lines.
  • Theme system: dark, light, or 'auto' following prefers-color-scheme.
Data layer
  • CandleBuffer — O(1) append/updateLast, O(n) prepend, backed by Float64Array.
  • CandleMerger — RAF-coalesced realtime tick merging.
  • DataFeed — stale-response protection via a version counter.
  • PollingTransport (HTTP) and WebSocketTransport (abstract base for WS adapters).
  • ExponentialBackoff — jittered reconnect policy.
  • validateCandle / validateCandles — runtime shape & invariant checks.
  • ErrorReporter + onError — structured error dispatch, no silent catches.
Interaction
  • Mouse drag pan with momentum (respects prefers-reduced-motion).
  • Wheel handling with axis priority: trackpad horizontal → pan, vertical → smooth zoom, shift+wheel → pan.
  • Touch: single-finger pan, two-finger pinch-zoom.
  • KeyboardController: ← → pan, ↑ ↓ / + - zoom, Home / End / 0 / F navigation.
  • autoFollow state machine: live updates track the right edge unless the user pans away. Double-click: fit visible.
Indicators & drawings
  • Overlay: SMA, EMA, WMA, HMA, BollingerBands, Keltner, Donchian, VWAP, PivotPoints, Ichimoku, Supertrend, ParabolicSAR, ZigZag.
  • Sub-pane: RSI, MACD, Stochastic, ATR, WilliamsR, OBV, ADX, CCI, MFI, StochRSI, ROC.
  • IndicatorConfig discriminated union + createIndicator factory — user code passes config objects; the core reconciles them.
  • Drawing tools: TrendLine, HorizontalLine, VerticalLine, Ray, Rectangle, FibRetracement, FibExtension, Channel, Arrow — all anchored in buffer space so they stick to candles on pan/zoom. Subclass Indicator or Drawing to add your own.

Architecture

openkline (this monorepo)
└─ packages/core   @rekurt/openkline-core   framework-agnostic engine (zero deps)
   ├─ rendering    ChartEngine, layers, axes, legend, WebGL candle renderer
   ├─ data         CandleBuffer, CandleMerger, DataFeed, transports
   ├─ interaction  Viewport, KeyboardController, autoFollow state machine
   ├─ indicators   25+ indicators + registry + createIndicator factory
   ├─ drawings     buffer-anchored drawing tools + DrawingLayer
   ├─ transforms   Heikin-Ashi, Renko
   └─ export       toSVG, PNG

rekurt/openkline-react   @rekurt/openkline-react   thin React wrapper
rekurt/openkline-vue     @rekurt/openkline-vue     thin Vue 3 wrapper

The wrappers own only framework glue (lifecycle, refs, reactivity). Every pixel and every number comes from the core, which is why parity is "for free."


Develop this monorepo

npm install
npm run dev:playground  # unified demo → http://localhost:5176
npm run dev:core        # vanilla demo → http://localhost:5173

npm run lint            # ESLint, --max-warnings 0
npm run typecheck       # strict tsc across all tsconfigs
npm test                # vitest — 440+ tests
npm run build           # tsup bundle for @rekurt/openkline-core
npm run docs            # TypeDoc → docs/api/

For the React and Vue wrapper demos, see rekurt/openkline-react and rekurt/openkline-vue.

See CONTRIBUTING.md for branch, commit and review conventions, and CLAUDE.md for how AI agents should work here.


Quality bar

  • 440+ unit tests (vitest) over rendering math, indicators, transforms and state.
  • Strict TypeScript, including noUncheckedIndexedAccess.
  • 0 lint warnings in CI (--max-warnings 0).
  • Zero runtime dependencies in the core package.

Roadmap

The current core package is 0.2.0. Indicator sub-panes, price alerts, bar-by-bar replay, compare overlays, and locale-aware formatting with message overrides are implemented; they are no longer future milestones. Compare and volume profile are opt-in controllers. Chart snapshots support persistence; a complete workspace UI and storage integration remain application work.

See the comparison and implementation evidence for availability and integration limits, and the CHANGELOG for release history. The M1 design doc is historical context, not a current delivery schedule. Further milestones have no committed dates here.


License

MIT © OpenKline contributors

About

Framework-agnostic TypeScript candlestick charts with indicators, drawing tools, and React and Vue wrappers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages