floviq logo floviq
← 筆記 · 2026-05-13 · maker-notes

「三大法人外資買賣超」— 財經新聞這樣寫,我就這樣 code。結果 API 根本沒有這個 key。

「三大法人外資買賣超」— 財經新聞這樣寫,我就這樣 code。結果 API 根本沒有這個 key。

欄位的真實名稱是:外陸資買賣超股數(不含外資自營商)


① 我怎麼踩進去的

在寫 n8n workflow 抓 TWSE T86 資料的時候,我想用欄位名稱做 key lookup。

財經新聞、財報報告、PTT 討論串都把外資動向寫成「外資買賣超」。自然地,我在 T86 response 的 fields 陣列裡搜「外資」兩個字,以為隨便 match 就能找到。

找到幾個 match,挑了最短的那個,繼續往下寫。

workflow 跑起來,推播正常出,沒有報錯。到這裡還沒發現問題。


② 什麼時候照到鏡子

有一天拿回傳資料仔細看,發現某幾個交易日的外資買超數字明顯偏小。對比 TWSE 官網手動查的數字,差了一個量級。

回頭重查 T86 response 的 fields 陣列,才發現完整版本長這樣:

外陸資買賣超股數(不含外資自營商)

15 個字。不是「外資買賣超」,不是「外資淨買超」,也不是「法人外資超」。

(順帶釐清:誤抄全形括號「()」是常見誤踩,TWSE 給的真正是半形「()」。括號類型不同,字串 match 直接 fail。)

我用的那個「最短 match」,是另一個欄位,數量級差了幾十倍。


③ 欄位完整名稱為什麼長這樣

TWSE T86 endpoint 同時追蹤好幾個主體:

  • 外資(含外資自營商)
  • 外資(不含外資自營商)← 這才是財經新聞說的「外資」
  • 外資自營商
  • 投信
  • 自營商

「外陸資」= 外資 + 陸資合并稱呼。「不含外資自營商」= 排除外資旗下自己的自營業務,才是外部法人對台股的真實方向。

所以完整欄位名是 15 個字,不是 5 個字。財經新聞說「外資買賣超」是在講第二項,但 key 名稱跟直覺完全不同。

用 index 而不是 key name 去抓欄位,會更穩:

// T86 fields 陣列第 3 個 index(0-based)
// 確認前先 console.log(fields) 對齊一次
const foreignNetChange = dataRow[fields.indexOf('外陸資買賣超股數(不含外資自營商)')];

④ 為什麼沒有馬上炸

這是讓問題潛伏最久的原因。

T86 資料每天都有外資交易,不管抓到哪個欄位,只要不是空的,推播就會送出一個看起來合理的數字。沒有任何 exception,沒有任何 null check 會觸發。

問題只有在人工對比官網數字時才會現形。自動化流程本身完全不會告訴你「你在讀錯欄位」。


⑤ 這件事讓我意識到什麼

自動化不等於正確。自動化等於「穩定地」做某件事,不管那件事是不是對的。

我拿到一個看起來合理的數字,workflow 跑通了,就繼續往下。沒有去驗原始資料。這個習慣在手動作業的時候會比較快察覺,但在自動化裡,error 可以被靜靜跑幾週都不被注意到。

現在我的做法是:新接一個 API endpoint,一定先把完整 fields 陣列印出來,人工對齊一次官網數字,確認 index 對,再繼續。不用 keyword 猜,用 ground truth 比。

所以包進 n8n workflow 自用,每天 8 點推 Telegram — 是在一次一次對齊之後,才讓它穩定跑的。


※ 本文描述 API 資料欄位結構,不構成投資建議,投資請自行評估風險。