# 캔들 차트·주식 차트 라이브러리: 거래량, 이동평균, 빨강 양봉

> @82chart/stock 으로 캔들·OHLC 차트를 그립니다. 거래량, 이동평균(SMA·EMA), 한국식 색(양봉 빨강·음봉 파랑), 실시간 틱, 확대, 키보드, SSR. 무료 MIT.

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

캔들 차트(봉 차트)란 하루나 1분 같은 구간마다 시가·고가·저가·종가를 막대 하나(캔들)로 그려 가격이 어떻게 움직였는지 보여 주는 주식 차트입니다. 종가가 시가보다 높으면 양봉, 낮으면 음봉이고, 위아래 가는 선(꼬리)이 고가와 저가입니다. OHLC 차트는 같은 네 값을 세로선과 좌우의 짧은 눈금으로 그립니다.

82chart 의 주식 차트는 코어 위에 얹는 별도 패키지 `@82chart/stock` 입니다. 캔들과 OHLC, 아래쪽 거래량, 종가 이동평균(SMA·EMA)을 그리고, 툴팁·키보드·확대·실시간·내보내기·서버 렌더링은 다른 82chart 차트와 똑같이 동작합니다. 기본 색은 한국 증권 앱처럼 **양봉 빨강, 음봉 파랑**입니다.

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

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

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

// 코어의 createChart 로 쓸 때는 한 번 등록합니다
import { createChart, use } from '@82chart/core';
import { stock } from '@82chart/stock';
use(stock); // 'candlestick', 'ohlc'
createChart('#chart', { type: 'candlestick', data });
```

아래 예제는 지어낸 종목의 60거래일 일봉입니다. 마우스를 올리거나 차트를 누른 뒤 ←→ 키로 움직이면 툴팁에 종가·시가·고가·저가·거래량·등락률(전일 대비)과 이동평균 값이 나옵니다. 끌어서 확대할 수 있습니다.

```js
createChart('#chart', {
  type: 'candlestick',
  title: '82전자 (예시 종목)',
  subtitle: '일봉, 60거래일',
  zoom: true,
  stock: { ma: [5, 20] },
  data: {
    series: [{
      name: '82전자',
      data: Array.from({ length: 60 }, (_, i) => {
        // 월~금 60거래일 (2026-07-27 ~ 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,
        };
      }),
    }],
  },
});
```

## 데이터 형식

- 봉 하나는 `{ x, open, high, low, close, volume }` 객체나 API 응답 그대로의 배열 `[날짜, 시가, 고가, 저가, 종가, 거래량]` 입니다. 거래량은 없어도 됩니다.
- `x` 는 날짜 문자열(`'2026-10-21'`), 시각(`'2026-10-21T09:01'`), `Date`, 에포크 밀리초 중 하나입니다.
- x 축은 봉의 목록이라 **주말·휴일에 빈칸이 없습니다**(비거래일 제거). 날짜 눈금은 월이 바뀌는 곳에 찍힙니다.
- 종가가 시가보다 높으면 상승, 낮으면 하락이고, 종가와 시가가 같으면 전일 종가와 비교해 색을 정합니다.
- 첫 시리즈가 가격이고, 그 뒤에 넣은 선 시리즈는 가격 눈금에 함께 그립니다(직접 계산한 지표선 등).

## OHLC 막대와 해외식 색

`type: 'ohlc'` 는 같은 데이터를 OHLC 막대로 그립니다. 해외 사용자에게 보여 줄 화면은 `colors: 'global'`(상승 초록, 하락 빨강)을 쓰세요. 아래는 거래량을 끄고 20일 지수이동평균(EMA)을 넣은 예입니다.

```js
createChart('#chart', {
  type: 'ohlc',
  title: 'OHLC 막대, 해외식 색',
  stock: { colors: 'global', volume: false, ma: [{ period: 20, type: 'ema' }] },
  data: {
    series: [{
      name: '82전자',
      data: Array.from({ length: 60 }, (_, i) => {
        // 위와 같은 60거래일
        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` 을 켜고 `append()` 에 체결 `{ x, price, volume }` 을 넣으면, x 가 마지막 봉과 같을 때는 그 봉의 고가·저가·종가·거래량이 바뀌고, 새 x 이면 새 봉이 열립니다. 완성된 봉 `{ x, open, high, low, close, volume }` 을 넣으면 같은 x 의 봉을 바꾸거나 새로 붙입니다. 분봉이라면 x 에 시각을 넣으면 됩니다.

```js
const chart = createChart('#chart', {
  type: 'candlestick',
  title: '실시간 체결 (예시)',
  realtime: { window: 40 },
  zoom: true,
  stock: { ma: [5] },
  data: {
    series: [{
      name: '82전자',
      data: Array.from({ length: 60 }, (_, i) => {
        // 최근 40거래일만 창에 남습니다 (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,
        };
      }),
    }],
  },
});
// 체결 하나가 마지막 봉을 움직이고(고가·저가·종가·거래량), 10번에 한 번 다음 거래일 봉이 열립니다
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);
```

## 옵션 (stock)

| 옵션 | 기본값 | 설명 |
| --- | --- | --- |
| `ma` | – | 종가 이동평균 `[5, 20]` 또는 `[{ period: 20, type: 'ema', color, name }]`. 빨강·파랑이 아닌 고정 색 |
| `volume` | 거래량이 있으면 켬 | `false` 끔, `{ height: 0.3 }` 그림에서 거래량 영역이 차지하는 비율 |
| `colors` | `'korea'` | `'korea'` 빨강 상승·파랑 하락, `'global'` 초록 상승·빨강 하락 |
| `priceFormat` | `'comma'` | 가격 눈금 형식(71,500). 가격은 만·억으로 줄이지 않습니다. `unit`, `prefix`, `decimals` 는 그대로 적용 |
| `lastPrice` | `true` | 마지막 종가를 가격 축에 표시하고 점선으로 잇기 |

그 밖의 옵션(`title`, `theme`, `zoom`, `realtime`, `height`, `language` …)은 다른 차트와 같습니다. 도우미 함수 `sma(values, period)`, `ema(values, period)` 는 평균 배열(값이 모자라는 앞부분은 `null`)을, `toBar(datum)` 은 봉 하나를 읽어 줍니다.

## 함께 되는 것

- 키보드: 차트에 초점을 두고 ← → 로 봉을 하나씩, Home·End 로 처음과 끝. 화면 읽기 프로그램에는 기간 등락률과 최고·최저가 요약으로 읽힙니다.
- 내보내기: PNG·SVG·CSV·엑셀(xlsx). CSV·엑셀에는 날짜, 시가, 고가, 저가, 종가, 거래량 열이 들어갑니다.
- 서버 렌더링: `import { renderToSVG, use } from '@82chart/core/server'` 에 `use(stock)` 을 하면 DOM 없이 캔들 SVG를 만듭니다.
- 스크립트 태그: `82chart.min.js` 다음에 `82chart-stock.min.js` 를 넣으면 `Chart82.createChart(el, { type: 'candlestick', … })` 가 됩니다([CDN](https://82chart.com/docs/cdn/)).
- 크기: lite 입구와 캔들만 넣으면 gzip 약 30.7 KB, CDN 추가 파일은 약 5.9 KB 입니다([필요한 차트만 불러오기](https://82chart.com/docs/modular-imports/)).

> 없는 것: 추세선 그리기 같은 그리기 도구, 그리고 이동평균·거래량 외의 보조지표(RSI, MACD, 볼린저 밴드 등). 필요하면 `sma`·`ema` 처럼 직접 계산한 값을 선 시리즈로 더할 수 있습니다. 호가창·매매 화면 같은 트레이딩 전용 기능이 필요하면 금융 전용 라이브러리가 맞습니다.

## 자주 묻는 질문

### 왜 상승이 빨강인가요?

한국 증권 앱과 HTS 의 관례(양봉 빨강, 음봉 파랑)를 기본으로 했습니다. 해외 사용자 화면에서는 `stock: { colors: 'global' }` 로 상승 초록, 하락 빨강을 쓰세요.

### 분봉·틱 데이터도 되나요?

됩니다. x 에 시각(ISO 문자열이나 에포크 밀리초)을 넣고, `realtime` 을 켠 뒤 `chart.append({ x, price, volume })` 로 체결을 넣으면 마지막 봉이 움직이고 새 시각이면 새 봉이 열립니다.

### 보조지표(RSI, MACD)는 있나요?

0.5 에는 이동평균(SMA·EMA)과 거래량만 있습니다. `sma`, `ema` 함수나 직접 계산한 값을 선 시리즈로 더하면 가격 눈금 위에 함께 그려집니다.

### 주식 차트 라이브러리를 무료로 상업 서비스에 써도 되나요?

네. `@82chart/stock` 도 코어와 같은 MIT 라이선스라 상업 서비스에 무료로 쓸 수 있고, 키·워터마크·출처 표시 의무가 없습니다.
