• #koyfin
  • #chrome-extension
  • #sqlite
  • #tsv
  • #data-pipeline
未分類

Koyfin Chrome拡張機能とSQLiteインポート - 実装サマリー

実装日: 2025-12-12

概要

KoyfinからダウンロードしたTSVデータをGemini APIを経由せずにSQLiteデータベースに直接保存できるようにした。これによりデータ処理の高速化・コスト削減・データの一元管理を実現。


変更前 vs 変更後

アーキテクチャ比較

【変更前】
┌─────────┐    ┌─────────┐    ┌─────────────┐    ┌────────────┐    ┌─────────┐
│ Koyfin  │ → │  TSV    │ → │ Gemini API  │ → │ TypeScript │ → │  アプリ  │
│ (手動)  │    │ (2ファイル)│    │ (毎回処理)   │    │  (変換後)   │    │         │
└─────────┘    └─────────┘    └─────────────┘    └────────────┘    └─────────┘
                 ↓
           Annual.tsv
           Quarterly.tsv
           (日付ディレクトリで管理)

問題点:
- 毎回Gemini APIを呼ぶ必要がある(コスト・時間)
- Annual/Quarterlyが別ファイルで管理が煩雑
- TSV→TypeScript変換が非決定論的
【変更後】
┌─────────┐    ┌─────────┐    ┌──────────┐    ┌─────────┐
│ Koyfin  │ → │  TSV    │ → │  SQLite  │ → │  アプリ  │
│ (自動)  │    │ (統合)   │    │   (DB)   │    │         │
└─────────┘    └─────────┘    └──────────┘    └─────────┘
                 ↓
           {TICKER}_{DATE}.tsv
           (koyfin-data/に自動保存)

メリット:
- Gemini API不要(高速・無料)
- 1企業1ファイルで管理が簡単
- 決定論的なパース(再現性あり)
- SQLクエリで柔軟なデータ取得

ファイル出力の比較

項目変更前変更後
ファイル数/企業2ファイル1ファイル
ファイル名{TICKER}_{DATE}_Annual.tsv
{TICKER}_{DATE}_Quarterly.tsv
{TICKER}_{DATE}.tsv
保存先ダウンロードフォルダ直下ダウンロード/koyfin-data/
データ形式Annual/Quarterly別々Annual + Quarterly 統合

データ処理の比較

項目変更前変更後
変換処理Gemini APIPythonパーサー
処理時間数秒〜数十秒/企業ミリ秒/企業
コストAPI課金あり無料
再現性AIの解釈による決定論的
出力形式TypeScriptSQLite

実装内容

1. 新規ファイル

ファイル説明
scraper/schema.sqlSQLiteスキーマ定義(4テーブル + 2ビュー)
scraper/tsv_to_sqlite.pyTSV→SQLiteパーサー(単一ファイル)
scraper/import_tsv_dir.pyディレクトリ一括インポート
background.jsChrome拡張のバックグラウンドスクリプト
scraper/data/tsv/TSV保存用ディレクトリ
scraper/data/koyfin.dbSQLiteデータベース

2. 変更ファイル

ファイル変更内容
manifest.jsonv1.2.0→v1.3.0、background service worker追加
content.jsAnnual/Quarterly統合、カスタムフォルダ保存対応

3. SQLiteスキーマ

-- 企業マスタ
companies (id, ticker, name, exchange, sector, industry, ...)

-- 株価スナップショット
quotebox (id, company_id, market_cap, forward_pe, ...)

-- 期間マスタ
financial_periods (id, period_type, period_label, fiscal_year, fiscal_quarter)

-- 財務データ本体(全セクション)
financial_data (id, company_id, period_id, data_type, section, metric_name, metric_value, fetched_at)

保存されるセクション(全9種):

  • highlights
  • income_statement
  • balance_sheet
  • cash_flow
  • multiples
  • enterprise_value
  • profitability
  • roic
  • solvency

4. content.js の主要変更

// 変更前: Annual/Quarterly別々にダウンロード
startBatchDownload() {
  ...
  this.downloadAsFile(data.annual, `${ticker}_${date}_Annual.tsv`);
  this.downloadAsFile(data.quarterly, `${ticker}_${date}_Quarterly.tsv`);
}

// 変更後: 統合TSVをカスタムフォルダにダウンロード
startBatchDownload() {
  ...
  const data = await this.collectAllTablesDataUnified();
  this.downloadAsFile(data, `${ticker}_${date}.tsv`);
}

// 変更前: aタグでダウンロード(保存先指定不可)
downloadAsFile(content, filename) {
  const a = document.createElement('a');
  a.download = filename;
  ...
}

// 変更後: background script経由(カスタムフォルダに保存)
downloadAsFile(content, filename) {
  chrome.runtime.sendMessage({
    action: 'downloadTSV',
    content: content,
    filename: filename,
    subfolder: 'koyfin-data'
  }, ...);
}

使い方

Step 1: Chrome拡張機能で一括ダウンロード

  1. Koyfinでポップアップを開く
  2. ティッカーリストを入力
  3. 「一括ダウンロード」ボタンをクリック
  4. TSVが ダウンロード/koyfin-data/ に自動保存される

Step 2: SQLiteにインポート

cd scraper

# ディレクトリ一括インポート
uv run python import_tsv_dir.py ~/Downloads/koyfin-data

# または単一ファイル
uv run python tsv_to_sqlite.py ~/Downloads/koyfin-data/AAPL_20251212.tsv

Step 3: データ取得(SQLクエリ例)

-- 企業の最新売上を取得
SELECT c.ticker, fp.period_label, fd.metric_value as revenue
FROM financial_data fd
JOIN companies c ON fd.company_id = c.id
JOIN financial_periods fp ON fd.period_id = fp.id
WHERE fd.metric_name = 'Total Revenues'
  AND fd.section = 'income_statement'
  AND fd.data_type = 'annual'
ORDER BY c.ticker, fp.fiscal_year;

-- 複数企業のP/E比較
SELECT c.ticker, fd.metric_value as pe_ratio
FROM latest_financial_data fd
JOIN companies c ON fd.company_id = c.id
JOIN financial_periods fp ON fd.period_id = fp.id
WHERE fd.metric_name = 'Price / Earnings (LTM)'
  AND fp.period_label = 'Current/LTM';

テスト結果

REGNのTSVファイルでテスト実行:

Company: REGN - Regeneron Pharmaceuticals, Inc.
Inserted 3817 financial data records

Records by section:
  balance_sheet: 583
  cash_flow: 528
  enterprise_value: 187
  highlights: 198
  income_statement: 594
  multiples: 132
  profitability: 275
  roic: 605
  solvency: 715

ディレクトリ構成

chrome-extension-kofyin/
├── manifest.json          # v1.3.0 (background追加)
├── background.js          # [NEW] ダウンロードAPI
├── content.js             # 統合TSV対応
├── popup.html
├── popup.js
├── content.css
├── scraper/
│   ├── schema.sql         # [NEW] SQLiteスキーマ
│   ├── tsv_to_sqlite.py   # [NEW] パーサー
│   ├── import_tsv_dir.py  # [NEW] 一括インポート
│   ├── koyfin_scraper.py
│   └── data/
│       ├── koyfin.db      # [NEW] SQLiteデータベース
│       └── tsv/           # [NEW] TSV保存先
└── memo/
    └── 2025-12-12/
        ├── sqlite-design.md
        └── implementation-summary.md  # このファイル

今後の拡張

  1. クエリヘルパー: アプリから簡単にデータ取得できるPython/JSモジュール
  2. 差分更新: 既存データとの差分のみインポート
  3. データ検証: インポート時の整合性チェック
  4. 可視化: SQLiteデータをダッシュボードで表示