この作品について
相場データ博物館 — 技術的な設計判断のまとめ
なぜ作ったか
相場にまつわるデータを、体感できる形にして公開する個人プロジェクト。 常設展「日経30年絵巻」は、日経平均という誰もが知る指数を、生の数値ではなく 「100万円がいくらになったか」という物語として見せることに主眼を置いている。 実験棟「実弾検証」は、逆に数値の正確さと透明性そのものを設計の中心に据えた。 性質の異なる2つの展示を、同じデータ契約の型(ビルド時に生成した JSON を 静的サイトへ流し込むだけ)で作れることを確かめたかった。
データの誠実さをどう設計したか
日経平均株価は日本経済新聞社が知的財産権を保有しており、商用利用にはライセンス契約が 原則必要という公式スタンスがある。個人・非商用の明確な例外規定は一次確認できなかった ため、リスクをゼロにはできない前提で、次の四段構えを設計した。
- 生の指数値はリポジトリにも配信 JSON にも一切保持しない。全ての値は基準日を100とした正規化派生値のみ
- 粒度を週次まで間引く(約1,600点)。元データベースの代替物にならない規模に抑える
- 各章に叙述・批評テキストを伴う編集著作物として構成し、出所を明記する
- 派生系列は1ファイルに隔離し、指摘があれば当該ファイルの差し替えだけで対応できる構造にする
実験棟側は逆に「何を公開しないか」が設計の中心になる。銘柄・株数・金額・評価額は
公開スキーマにフィールドごと存在させず、さらに禁止パターンの機械検査
(check_no_leak.py)を全ビルドで実行し、既知の漏洩サンプルを
検知できることの自己テストを同梱している。
演出をどう実装したか
常設展のスクロール演出(描き進む折れ線・ズーム・狼狽売りのゴースト線)は、
外部ライブラリを使わず IntersectionObserver +
requestAnimationFrame + Canvas 2D 直描画で自作した。
汎用のスクロールアニメーションライブラリを使わなかった理由は、
「描き進む一本の線」という演出そのものが本作の見せ場であり、
汎用ライブラリを挟むと、かえって制御が回り道になる。
実装中に見つかった不具合が2つある。ひとつは、章のテキストカードが不透明な
背景を持っていたため、背後で固定表示され続けるはずのチャートを完全に覆い隠して
しまっていたこと。もうひとつは、IntersectionObserver の交差通知が
スクロールイベントと非同期にずれるため、大きくジャンプするスクロールで章の
切り替えを取りこぼすことがあったこと。どちらも実際にブラウザで動かして初めて
気づいた類のもので、静的なコードレビューだけでは見つけにくい部分だった。
prefers-reduced-motion が指定されている場合は演出を止め、
各章に完成状態の静的チャートを表示する。JavaScript が無効な環境では、
ビルド時(サーバーサイド)に同じデータから直接 SVG の折れ線を生成し、
<noscript> で出し分けている。Canvas はクライアントで
しか描けないため、「JS が動かなければグラフも消える」を避けるための対応。
技術選定の考え方
サイト生成には Astro、ホスティングには Cloudflare Pages を選んだ。 どちらも他プロジェクトで運用実績があり、新しく学ぶコストがかからない 「枯れた技術」だからという理由が大きい。新規に増える「動く部品」は 実質、自作のスクロール演出ランタイムひとつだけに絞っている。 データ生成は Python(yfinance・pandas・jsonschema)で、これも既存の 株価取得運用の延長線にある。
データ生成スクリプトは冪等性(同じ入力からは同じ出力が得られること)と atomic write(一時ファイルに書いてから置き換える)を徹底し、 生成の唯一の書き手を1スクリプトに固定した。手編集を許すと、 「今表示されている数値の根拠がどこにあるか」が追えなくなるため。