開発financial-dataメモ

EDINET四半期データビューアの設計とデータパイプライン

昨日までに年次データの可視化ページが動いていた。今日は「四半期も見たい」から始まって、データの取り方・渡し方で3回方針が揺れ、最終的に計画書と指示書を書き上げるところまで進んだ。コードは1行も書いていない。設計だけで半日が溶けた日。


Turso Embedded Replicaの使い分けを整理した

朝一番の疑問は「edinet-apiディレクトリで取得したデータを、mdx-playgroundディレクトリでどう読むのか」だった。ローカルにSQLiteファイルがあり、Tursoのクラウドにもデータがある。turso-replicas というディレクトリも存在する。3つの場所にデータが散らばっている状態を整理するところから始めた。

確認した結果、構成は以下の通り。

  • edinet-api: EDINET DB APIを叩いてデータを取得し、ローカルSQLiteに保存。turso db push でクラウドに同期
  • turso-replicas: Embedded Replicaのローカルキャッシュ。クラウドDBのミラーとして各プロジェクトから読み取り用に使う
  • mdx-playground: 表示側。クラウドのTursoDB(またはレプリカ)からデータを引いてJSONに変換し、フロントに渡す

プロジェクト間でデータを共有するには、クラウド側を経由するのが正解。edinet-api側でクラウドに同期した後、mdx-playground側でクラウドから sync すれば最新データがローカルレプリカに降りてくる。


四半期ビューアの計画を立てた

年次データは既に2社分(会計ソフトA、会計ソフトB)がチャート表示できている。四半期を追加する方針を固めるため、計画書を作った。

骨子は以下の通り。

  • 右カラムに「年次 / 四半期」のタブ切替を追加
  • 四半期タブには6つのチャートを2x3グリッドで並べる(売上高、営業利益+営業利益率、経常利益・純利益、BS、CF、純利益単独四半期)
  • データは data/edinet/E35325_quarterly.json のようなJSONファイルとして静的配置
  • 既存の BaseComboChart コンポーネントをそのまま再利用

Codexレビューで計画を修正した

Codexにプランを投げたところ、致命的な指摘が2つ返ってきた。

1つ目は累計→単独値変換のテスト不足。年次データでは113件のテストを書いたのに、四半期にはテストがない。「Q1+Q2+Q3+Q4の合計が年次PLに一致するか」を自動検証すべきだという指摘。これはそのまま計画に追加した。

2つ目は四半期EPSの扱い。四半期報告のEPSは累計値で、単純に差し引いても正しい単独四半期EPSにならない。加重平均株式数が四半期ごとに変わるからだ。この指摘を受けて、6つ目のチャートをEPSから「純利益(単独四半期)」に差し替えた。年次タブにEPSチャートがあるので、そちらで確認すれば足りる。


データパイプラインの設計で3回揺れた

この日一番時間を使ったのが、四半期データをフロントまでどう届けるかの方式選定だった。3つの案を行ったり来たりした。

案1: Turso sync → JSON生成スクリプト

最初に固まった案。edinet-api側でAPIデータをTursoに格納済みなので、mdx-playground側でTursoクラウドから sync し、Pythonスクリプトで累計→単独値変換してJSONを吐く。

edinet-api → Turso クラウドDB → mdx-playground側でsync → Python → JSON → Vue composable

データの一元管理ができる。ただし、Tursoトークンが .env にあるのでClaude Codeが直接スクリプトを実行できない。

案2: Python直接JSON生成(Turso不要)

途中で「確認しながら進めたい」と考え直した。Tursoを経由せず、EDINET DB APIを直接Pythonスクリプトで叩いてJSONを生成する案。ビルド不要で pnpm dev のホットリロードで即反映される点が魅力だった。

ただ冷静に考えると、edinet-api側に既にTursoへの格納パイプラインがある。同じAPIを二重に叩く意味がない。

案3(採用): edinet-api側でTurso格納 → mdx-playground側でJSON生成

結局、案1に戻った。ただし、mdx-playground側のClaude Codeが自力でTursoDB接続するのが手間だったので、edinet-api側のClaude Codeに指示書を渡してJSONを出力してもらう方式に落ち着いた。

edinet-api側Claude Code: Turso → 累計→単独値変換 → JSON出力
↓(JSONファイルをmdx-playground/apps/web/data/edinet/ に配置)
mdx-playground側Claude Code: JSONをimportしてVueで表示

揺れた原因を振り返ると、「どこでデータ変換するか」と「誰がスクリプトを実行するか」が別の問題なのに、一緒に考えていたからだった。データの一元管理はTurso、変換の実行はedinet-api側のセッション、表示はmdx-playground側のセッション。役割を分けたら迷いが消えた。


セッション間連携の指示書を書いた

edinet-api側のClaude Codeに渡す指示書を memo/2026-04-12/edinet-quarterly-data-export-instruction.md に作成した。盛り込んだ要素は以下の通り。

  • 対象企業のEDINETコードと期末月
  • APIエンドポイントのURL
  • 出力JSON形式(年次JSONと同じ { "data": [...] } 構造に quarter フィールドを追加)
  • 累計→単独値の変換ルール(P/L・CFは差し引き、BSはそのまま)
  • フィールド一覧と優先度
  • 検証ポイント(Q合計が年次に一致するか、BS貸借が合うか)

別セッションのClaude Codeに正確な仕事をしてもらうには、出力形式と検証条件を明示した指示書がいる。口頭で伝えると、フィールド名の揺れや変換ルールの曖昧さが入り込む。


銘柄追加の手順を整理した

現在Tursoに入っているのは会計ソフトA(E33390)と会計ソフトB(E35325)の2社のみ。今後銘柄を追加するときの手順も計画書に盛り込んだ。

  1. EDINET検索APIでEDINETコードを調べる(認証不要)
  2. edinet-api側の store_to_turso.py にコードを追加して6エンドポイント分を取得・格納
  3. mdx-playground側でJSON生成スクリプトを実行
  4. types/edinet.tsEDINET_COMPANIES 配列に企業メタデータを追加

手順をドキュメント化しておくと、次に銘柄を追加するときに「何をやるんだっけ」と手が止まらない。


今日の学び

  • データの一元管理と変換の実行場所は別の問題。Turso(一元管理)を使うかどうかと、どのセッションでスクリプトを走らせるかは独立した判断。混ぜて考えると方針が揺れる
  • Codexレビューは設計段階で入れると効く。テスト不足とEPS問題は、実装後に気づいていたら手戻りが大きかった。コードを書く前に計画書をレビューに出したのは正解
  • 別セッションへの指示書は「出力形式」と「検証条件」を書く。ロジックの説明より、期待する成果物の仕様を正確に伝える方が結果が安定する