跳轉到

ETF 成分股顯示名稱 — Frontend Integration Guide

Backend branch: fixed/etf-constituent-display-name → cortex/dev(merge 後 cortex-api --reload 自動生效;cortex-scheduler 不會 hot-reload,merge 後須重啟,否則排程產生的報告仍沿用舊名稱;PR 連結於 merge 後補上) API base: http://localhost:8000(dev)/ production base 同既有 日期: 2026-10-20 Breaking change: 無(欄位名稱、型別皆不變;只有「值的語意」改變)


1. 改了什麼

ETF 持股相關 API 的 constituent_name 欄位名稱與型別不變(仍是 string | null),值的語意改變:

舊 新
constituent_name 的值 各投信回報的原始名稱(同一支股票在不同 ETF 可能不同) 股票主檔名稱(taiwan.stocks.name)
對不到主檔的成分股 投信原始名稱 投信原始名稱(不變)

「對不到主檔」指沒有對應台股代碼的成分股,例如海外股、債券、期貨、現金;以及主檔沒有該代碼、或主檔名稱為空字串的列。這些仍顯示投信回報的原始名稱。

取值規則(後端單一定義):

constituent_name = COALESCE(NULLIF(taiwan.stocks.name, ''), etf_holdings.constituent_name)
JOIN: taiwan.stocks.stock_code = etf_holdings.constituent_stock_code(LEFT JOIN)

資料庫內 taiwan.etf_holdings.constituent_name 的原始值不改,只有對外輸出換成主檔名稱。


2. 為什麼改

同一支股票在不同投信的持股表有不同名稱。2026-10-19 實測 GET /api/etf-holdings/stock-actions/ranking:2454 在同一頁的買超榜第 2 名顯示「聯發科技」、賣超榜第 1 名顯示「聯發科」,使用者看到同一支股票兩個名字。

原因是跨 ETF 彙總時取第一筆遇到的名稱,而 2454 在持股表有「聯發科」「聯發科技」「MEDIATEK INC」三種寫法;股票主檔只有「聯發科」。改為一律輸出主檔名稱後,同一個 constituent_ticker 只會有一種名稱。


3. 受影響的端點

constituent_name 的值語意統一改變的端點(皆在 /api/etf-holdings 之下):

Endpoint 欄位位置
GET /api/etf-holdings/recap/daily etfs[].added[]/removed[]/quantity_changes[] 的 constituent_name(day 與 week 等 period 皆適用)
GET /api/etf-holdings/stock-actions/ranking buy_rankings[]/sell_rankings[] 的 constituent_name
GET /api/etf-holdings/stock-actions/{raw_code} top-level constituent_name(該個股識別資訊)
GET /api/etf-holdings/{etf_ticker} holdings[] 的 constituent_name
GET /api/etf-holdings/{etf_ticker}/history snapshots[].holdings[] 的 constituent_name
GET /api/etf-holdings/{etf_ticker}/changes added[]/removed[]/quantity_changes[] 的 constituent_name
GET /api/etf-holdings/{etf_ticker}/changes/recent stocks[] 的 constituent_name
GET /api/etf-holdings/{etf_ticker}/estimated-costs stocks[] 的 constituent_name

不受影響:GET /api/etf-holdings/performance(不輸出成分股名稱)。

各端點的欄位表見 docs/api-reference.md 對應段落的 constituent_name 列(說明已統一為「股票主檔名稱;對不到主檔時為投信回報的原始名稱」)。

AI 報告內容

籌碼/週期 recap 與主動式 ETF 日報、AETF 報告的文字內容裡出現的成分股名稱,也改用主檔名稱。這些報告是新產生時才套用新規則,已產生的報告不重產:

  • 主動式 ETF 日報、籌碼日報:下一次排程產生的新日期報告起使用主檔名稱(前提:merge 後已重啟 cortex-scheduler——它不會 hot-reload,未重啟則排程報告繼續沿用舊名稱);merge 當下最新一份(2026-10-19)仍是舊內容。
  • AETF 報告:使用者按「分析」重新產生後才是新內容。

歷史日期

主檔只存目前名稱。曾經改名的公司,查詢舊日期的持股也會顯示現在的主檔名稱。


4. 前端影響

不需要改程式。 目前前端對 constituent_name 的讀取都只用於顯示;列的 key、分組、排序、跳轉都用 raw_code 或 constituent_ticker,不依賴名稱字串。

注意事項:

  • 不要拿 constituent_name 當 key、分組鍵或跨端點比對的依據(名稱仍可能因主檔更新而改變,且海外股/債券等沒有主檔的成分股仍是投信原始名稱)。身分比對請用 raw_code/constituent_ticker。
  • 若有 e2e/snapshot 測試寫死了特定投信的原始名稱(如「聯發科技」),需更新為主檔名稱(如「聯發科」)。

範例(2026-10-19,2454)

{
  "raw_code": "2454",
  "constituent_ticker": "2454.TW",
  "constituent_name": "聯發科",
  "asset_type": "stock"
}

買超榜與賣超榜同時出現 2454 時,兩邊的 constituent_name 一致為「聯發科」。對不到主檔的成分股(例如海外股)constituent_name 維持投信回報的原始名稱。


5. 前端遷移 checklist

  • [ ] grep 前端 repo 的 constituent_name,確認所有讀取都只用於顯示(key/分組/排序用 raw_code/constituent_ticker)
  • [ ] 更新寫死特定投信原始名稱的 e2e/snapshot 測試期望值
  • [ ] 手動驗證:/stock-actions/ranking(day、week)的 buy_rankings 與 sell_rankings 合併後,同一個 constituent_ticker 只有一種 constituent_name
  • [ ] 手動驗證:/recap/daily(day、week)各 ETF 的 added/removed/quantity_changes 中,同一個 constituent_ticker 只有一種 constituent_name
  • [ ] 不需要改 TypeScript type(constituent_name: string | null 不變)

6. 參考

  • Backend branch: fixed/etf-constituent-display-name
  • 後端規格: docs/api-reference.md 各 /api/etf-holdings 端點的 constituent_name 列
  • 相關前端契約: ETF 日期契約