EDINET API v2 で有価証券報告書を自動取得する(Node.js / TypeScript)

EDINET は金融庁が運営する電子開示システムで、上場企業が提出した有価証券報告書・四半期報告書などを無償で取得できる API を提供している。 個人開発の財務分析ツールを作るにあたって、この API を Node.js / TypeScript で叩いた際のポイントをまとめる。 エンドポイント概要 ベース URL:https://api.edinet-fsa.go.jp/api/v2 用途 エンドポイント 書類一覧 GET /documents.json?date=YYYY-MM-DD&type=2 PDF取得 GET /documents/{docID}?type=2 XBRL取得 GET /documents/{docID}?type=1(ZIP) API キーはクエリパラメータ Subscription-Key で渡す。EDINET のサイト からアカウント登録すると発行される。ハードコードせず process.env.EDINET_API_KEY から読むのはもはや最低限のマナーといえる。 レスポンスの型定義 まず API レスポンスに型をつける。docID(大文字)が EDINET 公式の表記: interface EdinetDocumentResponse { docID: string // EDINET が振る書類ID docTypeCode: string | null secCode: string | null // 証券コード。上場企業以外は null edinetCode: string filerName: string docDescription: string | null submitDateTime: string } クライアントクラスで型を明示しておくと、後続のフィルタリングや保存ロジックで補完が効いて安全になる。 書類一覧の取得とフィルタリング /documents.json は指定日に提出されたすべての書類を返す。有価証券報告書だけを絞り込むには docTypeCode を見る: 120:有価証券報告書 130:訂正有価証券報告書 140:四半期報告書 また secCode が null の書類は上場企業以外なのでスキップする。 const filteredResults = results.filter((r: EdinetDocumentResponse) => { const typeCode = (r.docTypeCode ?? '').replace(/['"]/g, '') return ( r.secCode != null && (typeCode === '120' || typeCode === '130' || typeCode === '140') ) }) docTypeCode に余分なクォートが混入することがある("120" のように入ってくる)ので replace で除去している。実際にハマった。 ...

May 24, 2026 · 2 min

Gemini API で財務書類を「怪しさ判定」する:スコア付き出力の設計

個人開発の EDINET 分析ツールでは、取得した有価証券報告書の PDF を Gemini に渡して「怪しさ判定」をさせている。 単なる要約ではなく、3段階のスコア(normal / caution / danger) を返させる設計にしたので、その仕組みをまとめる。 なぜスコアが必要か 毎日数十〜数百件の書類が提出される。全部読むのは無理なので、AI に「これは要注意」かどうかを仕分けさせたい。 スコアが danger の書類だけ Discord 通知を飛ばす、といった使い方ができる。 プロンプト設計 プロンプトの末尾に必ずスコアを出力させるよう指示する: 分析の最後に必ず以下の形式でスコアを出力してください: SCORE:normal # 特に問題なし SCORE:caution # 気になる点あり・要確認 SCORE:danger # 重大なリスクの可能性 Gemini はマークダウン形式で分析テキストを返した後、最終行に SCORE:danger のような文字列を出力する。 PDF を渡す方法 @google/generative-ai SDK では PDF を base64 で渡せる: const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' }) const result = await model.generateContent([ { inlineData: { mimeType: 'application/pdf', data: pdfBuffer.toString('base64'), }, }, { text: prompt }, ]) 最大 50MB まで渡せるが、大きすぎるとトークン消費が跳ね上がるので注意。 スコアのパース 正規表現で SCORE: 以降を抽出: ...

May 24, 2026 · 1 min

Hono + TypeScript でクリーンアーキテクチャもどきを個人開発に持ち込む

個人開発に「クリーンアーキテクチャ」は過剰では?という気持ちはある。 ただ実際にやってみたら、テストが書きやすい・外部APIの差し替えが楽という恩恵がちゃんとあった。 Hono + TypeScript (ESM) でどう組んだかをメモしておく。 ディレクトリ構成 backend/src/ ├── domain/ # エンティティ・リポジトリ Interface │ ├── entity/ │ └── repository/ ├── usecase/ # ビジネスロジック ├── infrastructure/ # DB・外部API の実装 │ ├── postgres/ │ ├── edinet/ │ └── gemini/ ├── api/ # Hono ルーター └── job/ # JobRunner 依存の方向 api / job ↓ usecase ← domain (Interface) ↓ infrastructure → domain (Interface を実装) usecase は domain の Interface にしか依存しない。 infrastructure が Interface を実装する。これだけ守れば十分。 ...

May 24, 2026 · 2 min