📈 lightweight-chartsでPolymarket価格履歴を可視化|TradingView Proの代替を45KBで作る
TradingView Pro(月$30)の代わりを、45KBのJSライブラリと20行のHTMLで作ります。
Polymarketの価格履歴を、ブラウザで本物のTradingView風チャートとして表示する手順です。py-clob-client(Polymarket入門記事参照)で取得したデータをそのまま使えます。
lightweight-chartsって何?
tradingview/lightweight-charts はTradingView公式のオープンソース金融チャートライブラリです。
- 14.8k stars / Apache-2.0
- 45KB(gzip後)— 本家のTradingViewが使ってる重いやつじゃなくて軽量版
- ローソク足・ライン・エリア・ヒストグラムなど金融データ向け描画が全部入り
- CDN経由で読み込めるので、ビルドツール一切不要
普通のChart.jsやPlotlyだと「価格チャート特有の機能」(十字カーソル・スクロール・ズーム・価格ライン)を自分で実装しないといけません。lightweight-chartsはそれらが最初から入ってるのが強み。
事前準備:価格履歴を取得
py-clob-clientの環境で、max期間の価格履歴を取得して可視化しがいのあるデータにします。
# 04_history_max.pyimport json, requests
YES_TOKEN = "31650083965282390269113502048883725495895331661148956202621012482964650485070"
url = "https://clob.polymarket.com/prices-history"params = {"market": YES_TOKEN, "interval": "max", "fidelity": 360} # 6時間単位
r = requests.get(url, params=params, timeout=20)history = r.json().get("history", [])
# lightweight-charts の line/area シリーズは {time, value} 形式out = [{"time": int(pt["t"]), "value": float(pt["p"])} for pt in history]out.sort(key=lambda x: x["time"])
# 重複時刻を削除(lightweight-charts は重複で怒る)seen = set()dedup = []for pt in out: if pt["time"] not in seen: seen.add(pt["time"]) dedup.append(pt)
with open("anthropic_ipo_yes_full.json", "w") as f: json.dump(dedup, f)
print(f"points={len(dedup)}")私の実行結果:
points=78first={'time': 1773230448, 'value': 0.395}last ={'time': 1775887666, 'value': 0.495}min=0.2500 max=0.535078ポイント・$0.25〜$0.535のレンジ。Anthropic IPO前にAnthropicがIPOする確率が、この1ヶ月で25%〜54%の間を動いていたってことです。面白いデータ😳
⚠️ つまずきポイント:
lightweight-chartsのsetData()は時刻昇順&重複なしが必須。これを守らないとValue is nullみたいな謎エラーが出ます。上のスクリプトでsort + dedupしてるのはそのため。
HTML本体(20行で全部)
ここがクライマックス。以下のHTMLをanthropic_ipo_chart.htmlとして保存し、同じフォルダのanthropic_ipo_yes_full.jsonと一緒に置きます。
<!DOCTYPE html><html lang="ja"><head><meta charset="UTF-8"><title>Anthropic IPO before 2027? — Polymarket Price History</title><style> body { margin: 0; padding: 20px; font-family: -apple-system, sans-serif; background: #0d1117; color: #e6edf3; } h1 { font-size: 18px; margin: 0 0 4px; } .sub { color: #7d8590; font-size: 13px; margin-bottom: 12px; } #chart { width: 100%; height: 420px; }</style></head><body><h1>"Anthropic IPO before 2027?" — YES price</h1><div class="sub">Polymarket / clob.polymarket.com/prices-history</div><div id="chart"></div>
<script src="https://unpkg.com/lightweight-charts@5.0.7/dist/lightweight-charts.standalone.production.js"></script><script> const chart = LightweightCharts.createChart(document.getElementById('chart'), { layout: { background: { color: '#0d1117' }, textColor: '#e6edf3' }, grid: { vertLines: { color: '#21262d' }, horzLines: { color: '#21262d' }, }, rightPriceScale: { borderColor: '#30363d' }, timeScale: { borderColor: '#30363d', timeVisible: true }, });
const series = chart.addSeries(LightweightCharts.AreaSeries, { lineColor: '#58a6ff', topColor: 'rgba(88, 166, 255, 0.35)', bottomColor: 'rgba(88, 166, 255, 0.05)', priceFormat: { type: 'price', precision: 3, minMove: 0.001 }, });
// 0.5(五分五分ライン)を点線で引く series.createPriceLine({ price: 0.5, color: '#f85149', lineWidth: 1, lineStyle: LightweightCharts.LineStyle.Dashed, axisLabelVisible: true, title: 'coin flip', });
fetch('anthropic_ipo_yes_full.json') .then(r => r.json()) .then(data => { series.setData(data); chart.timeScale().fitContent(); });</script></body></html>これだけです。bundler要らず。npm要らず。CDNから読み込むだけ。
動作確認(ローカルHTTPサーバー)
file://で直接開くとfetchがCORSで動かないので、Python標準のHTTPサーバーを使います。
cd poly_demopython -m http.server 8765ブラウザで http://localhost:8765/anthropic_ipo_chart.html を開くと:
- ダークテーマのチャート
- 青いエリア塗りでYES価格の推移
- $0.5に赤い点線(coin flipライン)
- 十字カーソル・ズーム・スクロール全部動く
私の環境で動作確認済みです。curlで各ファイルの配信を確認した結果:
html:200 json:200 (CDN) HTTP/2 200全部200で、lightweight-chartsのコードもcreateChart/addSeries/setDataが期待通り呼ばれています。
APIバージョンの落とし穴(v4 → v5)
重要:2025年の後半にlightweight-chartsのv5が出て、APIが変わりました。古い記事のコピペが動かないことが多いです。主な変更:
// ❌ v4以前の書き方(動かない)const series = chart.addAreaSeries({ ... });
// ✅ v5の書き方(今回のコード)const series = chart.addSeries(LightweightCharts.AreaSeries, { ... });v5ではシリーズの種類を第1引数で指定するようになりました。addCandlestickSeries()なども同様にaddSeries(LightweightCharts.CandlestickSeries, ...)です。エラーで動かない時は、まずここを疑ってください。
ローソク足にする(発展)
「YES価格の推移をOHLCローソク足で見たい」という場合。prices-historyは中値しか返さないので、fidelityを細かくして自分でOHLC集計する必要があります:
import pandas as pd
df = pd.DataFrame(history)df["dt"] = pd.to_datetime(df["t"], unit="s")df = df.set_index("dt")
# 1日単位でOHLC集計ohlc = df["p"].resample("1D").ohlc().dropna()ohlc.columns = ["open", "high", "low", "close"]ohlc["time"] = (ohlc.index.astype("int64") // 10**9).astype(int)
out = ohlc[["time", "open", "high", "low", "close"]].to_dict("records")HTMLでは:
const series = chart.addSeries(LightweightCharts.CandlestickSeries, { upColor: '#26a69a', downColor: '#ef5350', borderVisible: false, wickUpColor: '#26a69a', wickDownColor: '#ef5350',});これでPolymarketのローソク足チャートが完成します。TradingView Proが月$30、これは$0。30倍×∞の節約。
つまずきポイント集
| 症状 | 原因 | 対処 |
|---|---|---|
Value is null | 時刻重複 or 昇順じゃない | sort + dedup |
| チャートが真っ白 | file://で開いた | python -m http.server |
addAreaSeries is not a function | v5 API変更 | addSeries(LightweightCharts.AreaSeries, ...) |
| 時刻がズレる | unix秒 vs ミリ秒 | 秒を渡す(int(pt["t"])) |
| CDNが読み込まれない | ブロッカー / 社内ネット | npm i lightweight-charts でローカル配置 |
何に使える?
- Polymarket価格履歴をブログ記事に埋め込む:Remix/Next.js製ブログなら同じ方法でMDX内にインタラクティブチャートを置けます
- トップウォレットの取引タイミング可視化:ウォレットの履歴を取って、価格チャートにマーカーを重ねる
- バックテスト結果の可視化:損益曲線をlightweight-chartsで見せる
- FREDマクロデータとの重ね合わせ:
fredapiから引いたFed金利推移と政治系確率を同じチャート上に
まとめ
- lightweight-charts + Polymarket CLOB API + 20行のHTML でTradingView Pro代替が完成
- v5のAPI変更(
addSeries(Type, ...))だけ注意 - $0/月で、本物のTradingViewチャート実装が手に入る
file://で開くとfetchが動かないので**python -m http.server必須**
チャート自体はTradingView公式のライブラリなので、見た目もインタラクションも本家譲りです。本物を無料で使い倒しましょう🔥
参考リンク
🎁おすすめツール・サービス
※上記リンクにはプロモーション(広告)が含まれています
量子相場謀略|ホソノP
ブログでは書けない本音のトレード戦略とEA開発の裏側を公開。 データに基づいた検証で、再現性のある手法だけをお届けします。