# Candlestick and OHLC charts with volume and moving averages

> @82chart/stock: candlesticks and OHLC bars with a volume pane, SMA/EMA, Korean or global colors, realtime ticks, zoom, keyboard access and SSR. Free, MIT.

Source: https://82chart.com/en/docs/stock/

A candlestick chart draws the open, high, low and close of each period (a day, a minute) as one candle, showing how a price moved. A candle that closes above its open is rising, one that closes below is falling, and the thin wicks reach the high and the low. An OHLC chart draws the same four values as a vertical line with short ticks to the left and right.

Stock charts in 82chart come as a separate package on top of the core, `@82chart/stock`: candlesticks and OHLC bars, a volume pane and moving averages of the close (SMA, EMA). Tooltips, keyboard, zoom, realtime, export and server rendering work as on any other 82chart. The default colors follow Korean brokerage apps, **red up and blue down**; `colors: 'global'` switches to green and red.

```bash
npm i @82chart/core @82chart/stock
```

```js
import { createStockChart } from '@82chart/stock';
import '@82chart/core/styles.css';

createStockChart('#chart', {
  title: 'ACME',
  data: { series: [{ name: 'ACME', data: bars }] }, // { x, open, high, low, close, volume }
  stock: { ma: [5, 20, 60] },
});

// with the core createChart, register the types once
import { createChart, use } from '@82chart/core';
import { stock } from '@82chart/stock';
use(stock); // 'candlestick', 'ohlc'
createChart('#chart', { type: 'candlestick', data });
```

The example below is 60 trading days of a made-up share. Hover, or focus the chart and use ← →: the tooltip shows close, open, high, low, volume, the change from the previous close and the moving averages. Drag to zoom.

```js
createChart('#chart', {
  type: 'candlestick',
  title: '82 Electronics (sample)',
  subtitle: 'Daily bars, 60 trading days',
  zoom: true,
  stock: { ma: [5, 20] },
  data: {
    series: [{
      name: '82 Elec.',
      data: Array.from({ length: 60 }, (_, i) => {
        // Mon–Fri, 60 trading days (2026-07-27 to 10-16)
        const day = new Date(Date.UTC(2026, 6, 27 + Math.floor(i / 5) * 7 + (i % 5)));
        const base = 70000 + Math.sin(i / 7) * 4000 + i * 60;
        const open = Math.round((base + Math.sin(i * 1.3) * 700) / 100) * 100;
        const close = Math.round((base + Math.sin(i * 2.1 + 1) * 900) / 100) * 100;
        return {
          x: day.toISOString().slice(0, 10),
          open,
          high: Math.max(open, close) + 100 + ((i * 37) % 5) * 100,
          low: Math.min(open, close) - 100 - ((i * 53) % 5) * 100,
          close,
          volume: 1200000 + ((i * 7919) % 900) * 1000,
        };
      }),
    }],
  },
});
```

## Data format

- A bar is an object `{ x, open, high, low, close, volume }` or a tuple straight from an API, `[date, open, high, low, close, volume]`. Volume is optional.
- `x` is a date string (`'2026-10-21'`), a time (`'2026-10-21T09:01'`), a `Date` or epoch milliseconds.
- The x axis is the list of bars, so **weekends and holidays leave no gaps**. Date labels sit where the month changes.
- A bar is rising when the close is above the open and falling when below; a bar that closes at its open compares with the previous close.
- The first series is the price; further line series are drawn on the price scale (your own indicator lines, for example).

## OHLC bars and global colors

`type: 'ohlc'` draws the same data as OHLC bars. For readers outside Korea use `colors: 'global'` (green up, red down). This one has no volume pane and a 20-day exponential moving average.

```js
createChart('#chart', {
  type: 'ohlc',
  title: 'OHLC bars, global colors',
  stock: { colors: 'global', volume: false, ma: [{ period: 20, type: 'ema' }] },
  data: {
    series: [{
      name: '82 Elec.',
      data: Array.from({ length: 60 }, (_, i) => {
        // the same 60 trading days
        const day = new Date(Date.UTC(2026, 6, 27 + Math.floor(i / 5) * 7 + (i % 5)));
        const base = 70000 + Math.sin(i / 7) * 4000 + i * 60;
        const open = Math.round((base + Math.sin(i * 1.3) * 700) / 100) * 100;
        const close = Math.round((base + Math.sin(i * 2.1 + 1) * 900) / 100) * 100;
        return {
          x: day.toISOString().slice(0, 10),
          open,
          high: Math.max(open, close) + 100 + ((i * 37) % 5) * 100,
          low: Math.min(open, close) - 100 - ((i * 53) % 5) * 100,
          close,
          volume: 1200000 + ((i * 7919) % 900) * 1000,
        };
      }),
    }],
  },
});
```

## Realtime ticks

With `realtime` on, `append()` takes trades `{ x, price, volume }`: when x is the last bar's, that bar's high, low, close and volume move; a new x opens a new bar. A finished bar `{ x, open, high, low, close, volume }` replaces the bar with the same x or is added. For minute bars, put times in x.

```js
const chart = createChart('#chart', {
  type: 'candlestick',
  title: 'Live trades (sample)',
  realtime: { window: 40 },
  zoom: true,
  stock: { ma: [5] },
  data: {
    series: [{
      name: '82 Elec.',
      data: Array.from({ length: 60 }, (_, i) => {
        // the window keeps the latest 40 bars (realtime.window)
        const day = new Date(Date.UTC(2026, 6, 27 + Math.floor(i / 5) * 7 + (i % 5)));
        const base = 70000 + Math.sin(i / 7) * 4000 + i * 60;
        const open = Math.round((base + Math.sin(i * 1.3) * 700) / 100) * 100;
        const close = Math.round((base + Math.sin(i * 2.1 + 1) * 900) / 100) * 100;
        return {
          x: day.toISOString().slice(0, 10),
          open,
          high: Math.max(open, close) + 100 + ((i * 37) % 5) * 100,
          low: Math.min(open, close) - 100 - ((i * 53) % 5) * 100,
          close,
          volume: 1200000 + ((i * 7919) % 900) * 1000,
        };
      }),
    }],
  },
});
// each trade moves the last bar (high, low, close, volume); every 10th opens the next trading day
let day = Date.UTC(2026, 9, 16);
let price = 72000;
let n = 0;
setInterval(() => {
  if (++n % 10 === 0) day += 86400000 * (new Date(day).getUTCDay() === 5 ? 3 : 1);
  price = Math.max(1000, Math.round((price + (Math.random() - 0.5) * 600) / 100) * 100);
  chart.append({ x: new Date(day).toISOString().slice(0, 10), price, volume: Math.round(Math.random() * 40000) });
}, 600);
```

## Options (stock)

| Option | Default | What it does |
| --- | --- | --- |
| `ma` | – | Moving averages of the close: `[5, 20]` or `[{ period: 20, type: 'ema', color, name }]`, in fixed colors that are neither red nor blue |
| `volume` | on when bars have volume | `false` hides the pane; `{ height: 0.3 }` sets its share of the plot |
| `colors` | `'korea'` | `'korea'`: red up, blue down. `'global'`: green up, red down |
| `priceFormat` | `'comma'` | Price labels (71,500); prices are never shortened to 만/억. `unit`, `prefix` and `decimals` apply |
| `lastPrice` | `true` | The last close as a tag on the price axis with a dotted line |

Other options (`title`, `theme`, `zoom`, `realtime`, `height`, `language`, …) work as on any chart. The helpers `sma(values, period)` and `ema(values, period)` return the averages (`null` until there are enough values) and `toBar(datum)` reads one bar.

## What comes with it

- Keyboard: focus the chart, ← → step one bar, Home and End jump to the ends. Screen readers hear a summary with the change over the period, the high and the low.
- Export: PNG, SVG, CSV and Excel (xlsx); CSV and xlsx have date, open, high, low, close and volume columns.
- Server rendering: `use(stock)` with `renderToSVG` from `@82chart/core/server` makes candle SVGs without a DOM.
- Script tag: load `82chart-stock.min.js` after `82chart.min.js`, then `Chart82.createChart(el, { type: 'candlestick', … })` ([CDN](https://82chart.com/en/docs/cdn/)).
- Size: the lite entry with candlesticks is about 30.7 KB gzipped; the extra CDN file about 5.9 KB ([Import only the charts you use](https://82chart.com/en/docs/modular-imports/)).

> Not included: drawing tools and indicators other than moving averages and volume (RSI, MACD, Bollinger bands …). You can add your own computed values, such as `sma` or `ema` output, as line series. For order books and trading screens a dedicated financial library fits better.

## Frequently asked questions

### Why is up red?

It is the Korean convention (brokerage apps and HTS show rising bars red, falling bars blue). For other audiences use `stock: { colors: 'global' }`: green up, red down.

### Does it take minute bars and ticks?

Yes. Put times (ISO strings or epoch milliseconds) in x, turn on `realtime` and pass trades to `chart.append({ x, price, volume })`: the last bar moves, and a new time opens a new bar.

### Are there indicators such as RSI or MACD?

0.5 has moving averages (SMA, EMA) and volume. Add other indicators as line series computed with `sma`, `ema` or your own code; they are drawn on the price scale.

### Is this stock chart library free for commercial use?

Yes. `@82chart/stock` is MIT like the core: free in commercial products, with no key, watermark or attribution requirement.
