はじめに
金融系のチャートを実装するとき、選択肢って意外と悩むんですよね。Chart.jsは汎用的だけどキャンドルスティックには向いてないし、D3.jsは自由度が高すぎて実装コストがかかる。
そんなとき見つけたのがLightweight Charts。TradingViewが開発している金融チャート特化のライブラリで、GitHubスター数1万3千超え、月間83万ダウンロードという実績を持っています。
個人的に「これは良い」と思ったのは、わずか35KBという軽量さ。金融チャートってデータ量も多くなりがちなので、ライブラリ自体が軽いのはかなりありがたいです。
とはいえ、読むより触った方が早いと思います。createChartでチャートを作り、addSeriesとsetDataでデータを流し込むだけの手軽さを、ボタンで動かしながら確認できるサンプルを用意しました。先に挙動を見たい方はこちらからどうぞ。
特徴・メリット
圧倒的な軽量さ
Lightweight Chartsの最大の特徴は、その名の通り軽量であること。ミニファイ+Gzip圧縮で約35KB。同種のライブラリと比べるとかなり小さいです。
ページの読み込み速度に影響を与えない設計になっているので、複数のチャートを並べて表示するようなケースでも安心して使えます。
HTML5 Canvas ベースの高速描画
Canvas技術を使っているため、数千本のローソク足があってもスムーズに描画できます。リアルタイムのストリーミング更新にも対応しているので、取引所のリアルタイムデータを流し込むような用途にもバッチリです。
6種類の金融チャートタイプ
金融チャートに必要なタイプは一通り揃っています。
- Candlestick(ローソク足): 株価やFXの定番
- Line(折れ線): シンプルな価格推移表示
- Area(エリア): 塗りつぶしで視覚的に分かりやすい
- Bar(バー): 高値・安値・始値・終値を表示
- Baseline(ベースライン): 基準線からの乖離を表示
- Histogram(ヒストグラム): 出来高表示などに
TradingViewの信頼性
開発元がTradingViewというのは大きな安心材料ですね。4万社以上の企業と1億人以上のトレーダーに使われているプラットフォームを作っている会社なので、金融チャートのノウハウは間違いありません。
Apache License 2.0
商用利用OKのApache License 2.0で公開されています。ただし、TradingViewへのリンク表記が必要になる点は注意が必要です。
インストール方法
npm経由(推奨)
npm install lightweight-charts
TypeScriptの型定義も含まれているので、そのまま使えます。
CDN経由
手軽に試したいならCDNでも。
<script src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script>
CDNの場合はwindow.LightweightChartsとしてアクセスできます。
Lightweight Chartsのサンプルを動かす
Lightweight Chartsの基本は、createChartでチャート本体を作り、chart.addSeries(LineSeries, ...)のようにシリーズを追加してからsetDataで配列を渡すだけです。下のサンプルはボタンで「上昇トレンド」「下降トレンド」「レンジ相場」の3パターンのデータに切り替えられるようにしてあります。ボタンを押すたびにlineSeries.setData()が呼ばれ、チャートの描画がその場で更新される様子を確認できます。
要点だけ抜き出すと、次のようになります。
import { createChart, LineSeries } from 'lightweight-charts'
const chart = createChart(document.getElementById('chart'), {
width: 600,
height: 320,
})
// ラインシリーズを追加してデータを設定
const lineSeries = chart.addSeries(LineSeries, { color: '#2962FF' })
lineSeries.setData([
{ time: '2024-01-01', value: 100 },
{ time: '2024-01-02', value: 103 },
{ time: '2024-01-03', value: 101 },
])
chart.timeScale().fitContent()
実際に触って動かせるのが下のサンプルです。ボタンを押すとデータセットが切り替わり、チャートが再描画されます。
3つのボタンはいずれも同じlineSeriesに対してsetDataを呼び直しているだけです。実際のアプリでは、このmakeData()の部分をAPIから取得した実データに差し替えれば、そのままチャートに反映できます。LineSeriesをCandlestickSeriesに、valueをopen/high/low/closeに変えると、次で紹介するローソク足チャートの形になります。
基本的な使い方
シンプルな折れ線チャート
まずは一番シンプルな例から。
import { createChart, LineSeries } from 'lightweight-charts';
// コンテナ要素を指定してチャート作成
const chart = createChart(document.getElementById('chart'), {
width: 600,
height: 400,
});
// ラインシリーズを追加
const lineSeries = chart.addSeries(LineSeries);
// データを設定
lineSeries.setData([
{ time: '2024-01-01', value: 100 },
{ time: '2024-01-02', value: 105 },
{ time: '2024-01-03', value: 102 },
{ time: '2024-01-04', value: 110 },
{ time: '2024-01-05', value: 108 },
]);
これだけでインタラクティブなチャートが完成します。ズームやパンも標準で動作するのが嬉しいところ。
ローソク足チャート
金融チャートの本命、キャンドルスティック。
import { createChart, CandlestickSeries } from 'lightweight-charts';
const chart = createChart(document.getElementById('chart'), {
width: 800,
height: 500,
layout: {
background: { color: '#1a1a2e' },
textColor: '#d1d4dc',
},
grid: {
vertLines: { color: '#2B2B43' },
horzLines: { color: '#2B2B43' },
},
});
const candleSeries = chart.addSeries(CandlestickSeries, {
upColor: '#26a69a',
downColor: '#ef5350',
borderVisible: false,
wickUpColor: '#26a69a',
wickDownColor: '#ef5350',
});
candleSeries.setData([
{ time: '2024-01-01', open: 100, high: 105, low: 98, close: 103 },
{ time: '2024-01-02', open: 103, high: 108, low: 101, close: 107 },
{ time: '2024-01-03', open: 107, high: 110, low: 104, close: 105 },
{ time: '2024-01-04', open: 105, high: 112, low: 103, close: 111 },
{ time: '2024-01-05', open: 111, high: 115, low: 109, close: 113 },
]);
ダークテーマで陽線・陰線の色を指定するとそれっぽい見た目になります。
リアルタイム更新
取引所のデータをリアルタイムで反映したい場合はupdateメソッドを使います。
// 新しいデータポイントを追加/更新
candleSeries.update({
time: '2024-01-06',
open: 113,
high: 118,
low: 112,
close: 116,
});
setData()は全データを置き換えるのでパフォーマンスに影響しますが、update()は最新データの追加・更新だけなので軽量です。
出来高ヒストグラムとの組み合わせ
実際のトレード画面では価格チャートと出来高を一緒に表示することが多いですよね。
import { createChart, CandlestickSeries, HistogramSeries } from 'lightweight-charts';
const chart = createChart(document.getElementById('chart'), {
width: 800,
height: 500,
});
// 価格用のキャンドルスティック
const candleSeries = chart.addSeries(CandlestickSeries);
// 出来高用のヒストグラム(別のpriceScaleを使用)
const volumeSeries = chart.addSeries(HistogramSeries, {
color: '#26a69a',
priceFormat: {
type: 'volume',
},
priceScaleId: '',
});
volumeSeries.priceScale().applyOptions({
scaleMargins: {
top: 0.8,
bottom: 0,
},
});
// データ設定
candleSeries.setData([/* 価格データ */]);
volumeSeries.setData([
{ time: '2024-01-01', value: 1000000, color: '#26a69a' },
{ time: '2024-01-02', value: 1500000, color: '#26a69a' },
// ...
]);
実践的なユースケース
仮想通貨価格トラッカー
ビットコインやイーサリアムの価格をリアルタイム表示するアプリを作るなら、WebSocketと組み合わせるのが定番です。
// 取引所のWebSocketに接続
const ws = new WebSocket('wss://stream.binance.com/ws/btcusdt@kline_1m');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
const candle = data.k;
candleSeries.update({
time: candle.t / 1000,
open: parseFloat(candle.o),
high: parseFloat(candle.h),
low: parseFloat(candle.l),
close: parseFloat(candle.c),
});
};
WebSocketの通信自体はブラウザの環境依存で埋め込みサンプルにはできませんが、ポイントとなっているcandleSeries.update()の挙動だけは手元で確認できます。setData()が全データの再描画なのに対し、update()は最新の1本を追加・更新するだけなので、ストリーミング用途に向いています。下のサンプルはボタンを押すたびに新しい1分足を生成してupdate()に渡し、ローソク足チャート(CandlestickSeries)が右端に伸びていく様子を再現したものです。
// 新しい1本を追加/更新(setDataと違い全再描画しない)
candleSeries.update({
time: Math.floor(Date.now() / 1000),
open: 30000,
high: 30150,
low: 29900,
close: 30080,
});
「次の1分足を追加」を連打すると、update()が呼ばれるたびにチャートの右端に新しいローソク足が積み上がっていくのが分かります。実際の取引所連携では、このtimeとopen/high/low/closeをWebSocketから受け取った値に差し替えるだけで、そのままリアルタイムチャートとして動きます。
株価分析ダッシュボード
複数の銘柄を比較表示したり、移動平均線を重ねて表示したりといった使い方もできます。
// 移動平均線を追加
const maSeries = chart.addSeries(LineSeries, {
color: '#2196F3',
lineWidth: 2,
});
// 移動平均データを計算して設定
const maData = calculateMovingAverage(priceData, 20);
maSeries.setData(maData);
CandlestickSeriesとLineSeriesは同じチャートに何本でも重ねて追加できます。下のサンプルは、ローソク足の上に移動平均線を重ねた状態から、ボタンで移動平均線だけを表示/非表示に切り替えられるようにしたものです。maSeries.applyOptions({ visible })を呼ぶだけで、データを消さずに表示だけをオン・オフできる点がポイントです。
movingAverage(5)の5を20や50に変えると、より滑らかな長期の移動平均線に切り替わります。複数の期間のLineSeriesを同時にaddSeriesすれば、短期・長期の移動平均を重ねて表示するダッシュボードも同じ要領で作れます。
ポートフォリオ管理アプリ
複数の資産の推移をBaselineチャートで表示すると、基準値からの乖離が分かりやすくなります。投資パフォーマンスの可視化に向いています。BaselineSeriesはaddSeriesで追加でき、baseValueで指定した基準値より上を陽線側の色、下を陰線側の色で自動的に塗り分けてくれるのが特徴です。
// 基準値0からの乖離をプラス/マイナスで塗り分け
const baselineSeries = chart.addSeries(BaselineSeries, {
baseValue: { type: 'price', price: 0 },
topLineColor: '#26a69a',
topFillColor1: 'rgba(38, 166, 154, 0.3)',
bottomLineColor: '#ef5350',
bottomFillColor1: 'rgba(239, 83, 80, 0.3)',
});
「資産A」「資産B」を切り替えると、同じbaselineSeriesに対してsetData()が呼び直され、基準値(0)を境に塗り分けられる面グラフが別のリターン推移に切り替わります。複数の資産をタブで切り替えるようなポートフォリオ画面は、この仕組みをそのまま応用できます。
Reactで使う場合
Reactで使う場合は、useEffectでチャートのライフサイクルを管理します。
import { useEffect, useRef } from 'react';
import { createChart, LineSeries } from 'lightweight-charts';
function Chart({ data }) {
const chartContainerRef = useRef(null);
const chartRef = useRef(null);
useEffect(() => {
if (!chartContainerRef.current) return;
const chart = createChart(chartContainerRef.current, {
width: chartContainerRef.current.clientWidth,
height: 400,
});
const lineSeries = chart.addSeries(LineSeries);
lineSeries.setData(data);
chartRef.current = chart;
// リサイズ対応
const handleResize = () => {
chart.applyOptions({
width: chartContainerRef.current.clientWidth
});
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
chart.remove();
};
}, [data]);
return <div ref={chartContainerRef} />;
}
まとめ
Lightweight Chartsは、金融チャートに特化した軽量ライブラリとして、かなり優秀な選択肢です。
- わずか35KBという軽量さ
- TradingView製の信頼性
- リアルタイム更新対応
- 6種類のチャートタイプ
- モバイルフレンドリー
Chart.jsでキャンドルスティックを実装しようとして苦労した経験がある人には、特におすすめできます。金融系のアプリやダッシュボードを作る際は、まずLightweight Chartsを検討してみてください。
公式ドキュメントのサンプルも充実しているので、眺めるだけでも何ができるかイメージが湧くと思います。
公式サイト: https://www.tradingview.com/lightweight-charts/ GitHub: https://github.com/tradingview/lightweight-charts
