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

@mg-exchange/charts

v0.1.1

Published

Professional financial charting library for cryptocurrency exchanges. Canvas 2D + WebGL rendering, 21 indicators, 47 drawing tools, Smart Money Concepts, real-time streaming.

Readme

@mg-exchange/charts

Professional financial charting library for cryptocurrency exchanges.

Zero dependencies. Canvas 2D + WebGL. TypeScript. Works with React, Vue, or vanilla JS.

Live Demo | API Reference | Trading Integration | Examples


Why

  • No production-ready OSS charting library covers: indicators + drawings + multi-pane + real-time + trading
  • Existing open-source options lack drawing tools, multi-pane layouts, or real-time streaming
  • Commercial solutions are expensive and vendor-locked

Exchange Charts fills that gap — free, open-source, production-ready.

Features

Rendering

  • Canvas 2D with optional WebGL acceleration (67x faster at 500K bars)
  • Layered canvases: background, series, crosshair, drawings, UI — only dirty layers re-render
  • 60fps with 100K visible bars, 1M loaded, 5 indicators, 20 drawings

Chart Types

Candlestick, Heikin Ashi, OHLC Bars, Line, Area, Baseline

21 Built-in Indicators

| Category | Indicators | |----------|-----------| | Trend | SMA, EMA, Ichimoku Cloud, TWAP, Supertrend, EMA Ribbon, Parabolic SAR, ADX | | Momentum | RSI, MACD, Stochastic, Williams %R, Rate of Change | | Volatility | Bollinger Bands, ATR, Envelope | | Volume | VWAP, OBV, MFI, Cumulative Volume Delta, Volume Profile | | Smart Money | Order Blocks, Fair Value Gaps, BOS/CHoCH, Market Structure |

47 Drawing Tools

| Category | Tools | |----------|-------| | Lines | Trend Line, Ray, Info Line, Extended Line, Horizontal/Vertical/Cross Line, Polyline | | Channels | Parallel Channel, Regression Channel, Pitchfork | | Fibonacci | Retracement, Extension, Channel, Time Zone, Speed Fan, Circles, Spiral, Arcs, Wedge | | Gann | Box, Square, Fan | | Patterns | XABCD, ABCD, Head & Shoulders, Triangle, Three Drives | | Elliott | Impulse (12345), Correction (ABC), Triangle (ABCDE) | | Shapes | Rectangle, Ellipse, Arc, Arrow, Brush | | Text | Text, Callout, Note, Flag | | Trading | Long/Short Position (TP/SL/P&L), Forecast | | Measure | Price Range, Date Range, Fixed Range Volume Profile |

Drawing tools show real calculations: angle, bars, price change, %, channel width, Fibonacci levels, standard deviation.

Trading Integration

  • Order lines (limit, stop, TP, SL, entry, liquidation, breakeven)
  • Position overlays with P&L zones (Bybit-style)
  • Draggable order lines
  • Customizable trade actions — exchange provides its own UI
  • Serialization: getOrderLines() / loadOrderLines()

More

  • Real-time: WebSocket streaming with bar construction and tick updates
  • Multi-pane: Separate panes for oscillators with resize handles
  • Multi-chart: Grid layouts (2x2, 2x3) with synced crosshair/timeframe
  • Mobile: Pinch-to-zoom, momentum scroll, long-press crosshair
  • Themes: Dark/light, fully customizable
  • Persistence: Serialize/restore drawings, indicators, order lines
  • Price alerts: Directional alerts with callbacks

Install

npm install @mg-exchange/charts

Quick Start

import { Chart } from '@mg-exchange/charts';
import { sma, rsi, bollingerBands } from '@mg-exchange/charts';

const chart = new Chart({
  container: '#chart',
  symbol: 'BTCUSDT',
  timeframe: '1H',
  datafeed: myDatafeed,
  renderer: 'webgl',
});

// Add indicators
chart.addIndicator(sma, { period: 20 });
chart.addIndicator(rsi, { period: 14 });
chart.addIndicator(bollingerBands, { period: 20, stdDev: 2 });

// Drawing tools
chart.setDrawingTool('fib-retracement');

// Events
chart.on('crosshairMove', ({ price, time, bar }) => { /* ... */ });
chart.on('barUpdate', (bar) => { /* real-time update */ });

Datafeed Interface

Implement 3 methods to connect any data source:

import type { Datafeed } from '@mg-exchange/charts';

const myDatafeed: Datafeed = {
  async getBars({ symbol, timeframe, from, to, limit }) {
    const res = await fetch(`/api/klines?symbol=${symbol}&interval=${timeframe}&limit=${limit}`);
    return res.json();
  },

  subscribe({ symbol, timeframe, onBar, onTick }) {
    const ws = new WebSocket(`wss://stream.example.com/${symbol}`);
    ws.onmessage = (e) => {
      const data = JSON.parse(e.data);
      onTick({ time: data.time, price: data.price, volume: data.volume });
    };
    return () => ws.close();
  },

  async searchSymbols(query) {
    return [{ symbol: 'BTCUSDT', name: 'Bitcoin / USDT', exchange: 'Binance' }];
  },
};

Trading API

The chart provides primitives for exchanges to build their own trading UI. The chart does not place orders — it gives you events and rendering tools.

Basic: Order Lines + Position Overlays

import type { OrderLine, PositionOverlayData } from '@mg-exchange/charts';

// Show a limit order on chart
chart.addOrderLine({
  id: 'order-1',
  price: 87500,
  type: 'limit',
  side: 'buy',
  label: 'BUY LIMIT 0.05',
  quantity: 0.05,
});

// Update when price changes
chart.updateOrderLine('order-1', { price: 87400 });

// Show position with TP/SL zones (Bybit-style)
chart.setPositionOverlays([{
  side: 'long',
  entryPrice: 87500,
  quantity: 0.05,
  currentPrice: 87800,
  pnl: 15.0,
  breakeven: 87587.5,
  tpLevels: [{ price: 89250, quantity: 0.05 }],
  slLevels: [{ price: 86625, quantity: 0.05 }],
}]);

// Serialize/restore
const lines = chart.getOrderLines();
chart.loadOrderLines(lines);

Events

// User clicked "+" on price axis or right-click trade menu
chart.on('tradeRequested', ({ side, price, type, action }) => {
  // 'side': 'buy' | 'sell'
  // 'price': clicked price level
  // 'type': 'limit' | 'market'
  // 'action': custom action string (if using custom context menu)
  showMyOrderForm({ side, price, type });
});

// User dragged an order line to a new price
chart.on('orderLineMoved', ({ id, price }) => {
  updateOrderOnServer(id, price);
});

Custom Trade Actions (for exchanges)

Override the default "+" button and right-click menu with your own UI:

chart.setTradeMode(true, {
  // Replace default "+" behavior with your handler
  onTradeAction: ({ price, clientX, clientY, suggestedSide }) => {
    showMyOrderPopup({ price, x: clientX, y: clientY, side: suggestedSide });
  },

  // Or customize the right-click menu items
  contextMenuItems: (price) => [
    { label: `Limit Buy @ ${price.toFixed(2)}`, action: 'limit-buy' },
    { label: `Limit Sell @ ${price.toFixed(2)}`, action: 'limit-sell' },
    { label: 'Place OCO Order', action: 'oco', separator: true },
    { label: 'Set Alert', action: 'alert' },
  ],

  // Callback when user drags order lines
  onOrderLineDrag: (id, newPrice) => {
    modifyOrderOnExchange(id, newPrice);
  },

  // Control individual features
  showPlusButton: true,
  showContextMenu: true,
  draggableOrderLines: true,
});

Granular Control

// Enable trade mode without any built-in UI
chart.setTradeMode(true, {
  showPlusButton: false,
  showContextMenu: false,
  onTradeAction: myHandler,
});

// Listen to raw click events and build completely custom UX
chart.on('click', ({ price, time }) => {
  if (myState.placingOrder) {
    placeOrderAt(price);
  }
});

React Wrapper

import { ChartContainer, useChart } from '@mg-exchange/charts/react';

function TradingChart() {
  const chartRef = useChart();

  return (
    <ChartContainer
      ref={chartRef}
      options={{
        symbol: 'BTCUSDT',
        timeframe: '1H',
        datafeed: myDatafeed,
        theme: 'dark',
      }}
      style={{ width: '100%', height: 600 }}
    />
  );
}

Multi-Chart Layout

import { MultiChart } from '@mg-exchange/charts';

const multi = new MultiChart({
  container: '#charts',
  layout: '2x2',
  datafeed: myDatafeed,
  syncCrosshair: true,
  syncTimeframe: true,
  charts: [
    { symbol: 'BTCUSDT', timeframe: '1H' },
    { symbol: 'ETHUSDT', timeframe: '1H' },
    { symbol: 'SOLUSDT', timeframe: '1H' },
    { symbol: 'BTCUSDT', timeframe: '1D' },
  ],
});

WebGL Rendering

const chart = new Chart({
  // ...
  renderer: 'webgl',
});

// Falls back to Canvas 2D automatically if WebGL2 unavailable
console.log(chart.getRendererBackend()); // 'webgl' or 'canvas2d'

WebGL uses dedicated OHLC shaders — raw price data uploaded to GPU, coordinate math in vertex shader. 67x improvement at 500K bars.

Chart Options

interface ChartOptions {
  container: HTMLElement | string;
  symbol: string;
  timeframe: Timeframe;
  datafeed: Datafeed;
  chartType?: ChartType;
  priceScale?: PriceScaleMode;
  theme?: 'dark' | 'light' | Theme;
  renderer?: 'canvas2d' | 'webgl';
  pricePrecision?: number;
  trading?: Partial<TradeOptions>;
  features?: Partial<ChartFeatures>;
}

Full API Reference

// ── Chart Control ──────────────────────────────────────
chart.setSymbol('ETHUSDT');
chart.setTimeframe('4H');
chart.setChartType('heikin_ashi');
chart.setTheme('light');
chart.goToLive();
chart.exportPNG('chart.png');
chart.destroy();

// ── Indicators ─────────────────────────────────────────
const id = chart.addIndicator(indicator, params);
chart.removeIndicator(id);
chart.setVolumeProfile(true);

// ── Drawings ───────────────────────────────────────────
chart.setDrawingTool('trend-line');
chart.setDrawingTool(null);
chart.clearDrawings();
chart.removeDrawing(id);
chart.updateDrawing(id, { color: '#ff0000' });
chart.toggleDrawingVisible(id);
chart.toggleDrawingLock(id);
chart.reorderDrawing(id, newIndex);
chart.bringDrawingToFront(id);
chart.sendDrawingToBack(id);
const drawings = chart.getDrawings();
chart.loadDrawings(drawings);
chart.getDrawingInstances();
chart.setMagnetMode(true);

// ── Trading ────────────────────────────────────────────
chart.setTradeMode(true, options);
chart.setTradeOptions(options);
chart.addOrderLine(line);
chart.updateOrderLine(id, updates);
chart.removeOrderLine(id);
chart.clearOrderLines();
chart.getOrderLines();
chart.loadOrderLines(lines);
chart.setPositionOverlays(positions);

// ── Alerts ─────────────────────────────────────────────
chart.addAlert(price);
chart.removeAlert(id);

// ── Compare ────────────────────────────────────────────
chart.addCompare('ETHUSDT');
chart.removeCompare('ETHUSDT');

// ── Events ─────────────────────────────────────────────
chart.on('crosshairMove', cb);
chart.on('barUpdate', cb);
chart.on('click', cb);
chart.on('drawingAdded', cb);
chart.on('drawingRemoved', cb);
chart.on('drawingModified', cb);
chart.on('drawingSelected', cb);
chart.on('drawingDeselected', cb);
chart.on('tradeRequested', cb);
chart.on('orderLineMoved', cb);
chart.on('symbolChange', cb);
chart.on('timeframeChange', cb);
chart.on('visibleRangeChange', cb);
chart.on('dataLoaded', cb);
chart.off(event, cb);

Theming

import type { Theme } from '@mg-exchange/charts';

const customTheme: Theme = {
  name: 'midnight',
  bg: '#0a0a0a',
  gridLine: '#1a1a1a',
  bullCandle: '#00ff88',
  bearCandle: '#ff4444',
  bullCandleWick: '#00ff88',
  bearCandleWick: '#ff4444',
  text: '#e0e0e0',
  textSecondary: '#808080',
  crosshairLine: '#555555',
  crosshairLabel: '#333333',
  // ... see Theme interface for all 30+ properties
};

chart.setTheme(customTheme);

Custom Indicators

import type { Indicator } from '@mg-exchange/charts';
import { registerIndicator } from '@mg-exchange/charts';

const myIndicator: Indicator = {
  name: 'My VWMA',
  shortName: 'VWMA',
  description: 'Volume Weighted Moving Average',
  overlay: true,
  params: [{ name: 'period', type: 'number', default: 20, min: 1, max: 500 }],

  calculate(bars, params) {
    const { period } = params;
    return bars.map((_, i) => {
      if (i < period - 1) return { values: [NaN] };
      let sumPV = 0, sumV = 0;
      for (let j = i - period + 1; j <= i; j++) {
        sumPV += bars[j].close * bars[j].volume;
        sumV += bars[j].volume;
      }
      return { values: [sumPV / sumV] };
    });
  },

  plots: [{ type: 'line', color: '#FF6D00', lineWidth: 2 }],
};

registerIndicator(myIndicator);
chart.addIndicator(myIndicator, { period: 20 });

Development

git clone https://github.com/iZonex/mg-exchange-chart.git
cd mg-exchange-chart
npm install
npm run dev          # Dev server with live Binance data
npm run build        # Build library (dist/)
npm run test         # Run all tests
npm run typecheck    # tsc --noEmit
npm run lint         # ESLint

Examples

See the examples/ directory:

License

Apache 2.0