floviq logo floviq
← 筆記 · 2026-05-29 · reference

台股停券預告 BFI84U 端點 — 暫停融券清單、ROC 日期 Parse 坑與 MI_MARGN 註記欄位

除息、ETF 分配收益、股東會等公司事件發生前,TWSE 規定相關證券須在停止過戶前**暫停融券賣出(停券)**一段時間,期間融資買進仍可進行。這份預告清單在 TWSE OpenAPI 有一個獨立端點:BFI84U,TWSE 官方報表名稱即「得為融資融券有價證券停券預告表」。

對工程師而言,這個端點有三個容易踩到的坑——ROC 民國日期解析、Reason 原因值容錯、以及與 MI_MARGN 餘額端點的職責區分。


① BFI84U 是什麼

GET https://openapi.twse.com.tw/v1/exchangeReport/BFI84U

回傳:近期將「暫停融券賣出(停券)」的證券清單,含停券起訖日(停券起日為最後回補日)與原因。對除息/分配收益/股東會事件,期間融資買進不停、僅停融券賣出。

這份清單每日更新、筆數隨事件預告滾動;近期一次實測約數十筆。

此端點位於 TWSE OpenAPI exchangeReport 路徑,性質是事件預告,回答的問題是:「哪些股票,在哪段期間,因為什麼原因,暫停融券賣出(停券)?」它的定位與每日融資融券餘額端點(MI_MARGN)不同:BFI84U 提供提前數日至數週的事件預告,而 MI_MARGN 的「註記」欄只反映次一營業日的融資融券狀態。要提前判斷停券窗,兩者需互補使用,這個時間粒度差異是本文的核心坑之一。


② 欄位結構(JSON 回應)

實測為五個欄位:

Key 名稱中文含義範例值說明
Code證券代號00939 / 1219ETF 與普通股混存
Name證券名稱(依代號)字串
StartDate停券起日(最後回補日)1150529ROC 民國日期,7 碼
EndDate停券迄日1150601ROC 格式 · 但可能為空字串 ""(迄日待公告,常見於減資/長期停券)
Reason原因除息 / 分配收益五種原因(見下)

欄位結構示意(單列,僅示範結構,非任何買賣建議):

{"Code":"00939","Name":"...","StartDate":"1150529","EndDate":"1150601","Reason":"分配收益"}

③ Reason 的五種原因值

近期一次實測中,Reason 的分布以「除息」為大宗,其餘依序為「分配收益」(ETF 收益分配)、「減資」、「現金增資」、「其他」:

Reason 值來源
除息普通股年度或半年度除息(佔多數)
分配收益ETF 收益分配
減資減資
現金增資現金增資
其他非上述四類的暫停情境

「除息」與「分配收益」兩類混在同一份回應內,按 Reason 欄位可區分,但需自行判斷。

重要:這些值是當期清單的實際分布,不是固定不變的欄位定義。「其他」這個值存在,代表 TWSE 保留了一個概括性的歸類。寫自動化邏輯時,不應寫死成「只接受這五個原因字串」——遇到未知值應走容錯邏輯(略過或記錄),而非中斷或靜默丟棄。


④ 三個工程坑

坑 1 · ROC 民國日期(StartDate / EndDate

StartDateEndDate 是 7 碼 ROC 民國格式,如 1150529,代表民國 115 年 05 月 29 日(即西元 2026-05-29)。

直接當西元年解析會得到「西元 1150529」這個無意義的數值。TWSE OpenAPI 體系中多個端點使用 ROC 日期,BFI84U 是其中之一。

轉換邏輯:前 3 碼為民國年,後 4 碼為 MMDD,民國年 + 1911 = 西元年:

// StartDate: "1150529" → 2026-05-29 西元
// EndDate 可能為空字串(迄日待公告)→ 回傳 null,非解析失敗
function parseRocDate(roc7) {
  if (!roc7 || roc7.length !== 7) return null;  // 防呆:空字串或格式異常
  const rocYear = parseInt(roc7.slice(0, 3));    // 115
  const mm = roc7.slice(3, 5);                   // "05"
  const dd = roc7.slice(5, 7);                   // "29"
  const adYear = rocYear + 1911;                 // 2026
  return `${adYear}-${mm}-${dd}`;               // "2026-05-29"
}

EndDate 可能為空字串:實測清單中會有少數幾筆的 EndDate""(多為減資或長期停券),代表「停券中、結束日待定」。上方函式因首行防呆判斷(空字串會被判為否),parseRocDate("") 回傳 null。真正的風險是:若省略這道防呆、直接對空字串做 parseInt 後的日期運算,才會得到 NaN / Invalid Date,導致這幾檔的停券判斷被靜默漏掉。務必在後續比較時把 end === null 當成「迄日待公告、仍在停券期內」處理。

TWSE OpenAPI 整體的日期格式分布(7 碼 ROC / 斜線 ROC / 西元 8 碼等五種並存)詳見 TWSE OpenAPI 日期格式陷阱

坑 2 · MI_MARGN 的「註記」欄與時間粒度差異(最易漏的坑)

MI_MARGN 是 TWSE 每日融資融券餘額端點,回傳的是「某檔今日融資餘額是多少張 / 融券餘額是多少張」。

關鍵在於:MI_MARGN 自身即帶「註記」欄,會標示停券/停資狀態。TWSE 在報表底部明列符號圖例:

符號含義
O停止融資
X停止融券
!停止買賣
@融資分配
%融券分配

實測比對下來,BFI84U 停券清單內的代號,在同一天 MI_MARGN註記 欄都帶有對應符號(除息/分配收益事件對應 X 停止融券)。因此「MI_MARGN 對停券完全沒有跡象、必須靠 BFI84U 才知道」並不成立。

真正的坑是時間粒度差異與欄位語意成本,而非「沒有標記」:

  1. MI_MARGN註記 欄只反映次一營業日的融資融券狀態,且該符號需查圖例(X/O/!)才看得懂;漏讀圖例就會把標記當雜訊。
  2. MI_MARGN餘額數字本身不因停券歸零——它仍是最後一筆餘額快照。若自動化只看餘額數字、不解析 註記 欄,就會把停券期間的數據當成正常餘額照常推播。
  3. 若需提前數日至數週得知停券窗(含完整起訖日區間),MI_MARGN 的「次一營業日」粒度不夠,仍應比對 BFI84U 的事件預告。

因此正確做法是兩者互補:解析 MI_MARGN 時務必讀 註記 欄判斷當日停券/停資狀態,並在需要提前判斷或完整起訖日時比對 BFI84U。

// 判斷某個證券是否在當日停券(暫停融券)期間(偽代碼)
async function isMarginSuspended(code, today) {
  const suspensions = await fetch(BFI84U_URL).then(r => r.json());
  return suspensions.some(row => {
    const start = parseRocDate(row.StartDate);
    const end = parseRocDate(row.EndDate);
    // end === null 代表迄日待公告(仍在暫停期內)
    return row.Code === code && today >= start && (end === null || today <= end);
  });
}
// 取得融資餘額前先過 suspension gate
if (await isMarginSuspended(targetCode, today)) {
  // 跳過此週期的 MI_MARGN 解讀或標記為 suspended
}

這兩個端點互補:BFI84U 是停券事件預告清單(提前數日至數週,含完整停券起訖日區間),MI_MARGN餘額快照 + 次一營業日的 註記 狀態(含 X 停券/O 停資標記)。只讀其中一個,要嘛漏掉提前量(只用 MI_MARGN),要嘛漏掉每日餘額(只用 BFI84U)。

坑 3 · ETF 與普通股混存於同一份回應

BFI84U 的清單同時含普通股(Reason 多為 除息)與 ETF(Reason 多為 分配收益)。ETF 收益分配前的停券和普通股除息前的停券,在法規邏輯上來源不同,但在 BFI84U 中是同一層的 JSON 陣列。

Reason 分類可以區分兩類,但需注意:同一檔 ETF 若在不同月份多次分配,會在清單內出現多筆不同日期的資料列。自動化邏輯若只檢查「是否存在於清單」而不看日期範圍,在多筆情況下需正確對齊 StartDate/EndDate 才能判斷「現在是否仍在暫停期內」。


⑤ 穩定取值建議

BFI84U 每日更新,適合在盤前自動化流程中作為前置檢查關卡。整合要點:

  1. ROC 日期轉換:轉換前先確認前 3 碼為民國年,+ 1911 轉西元;空字串 EndDate 經防呆判斷回傳 null,後續以 end === null 視為「迄日待公告、仍在停券期內」
  2. Reason 容錯:用集合查表而非窮舉所有值,未知值記錄下來、不中斷
  3. MI_MARGN 註記欄解析:依賴融資融券餘額的邏輯,務必解析 MI_MARGN註記 欄(X 停券/O 停資/! 停止買賣)判斷當日狀態;需提前數日預警或完整停券起訖日時再比對 BFI84U
  4. 日期範圍匹配:同一代號可能有多筆,匹配時需同時比對 StartDate ≤ 今日 ≤ EndDate

想把這類台股 API 監控整合進自動化推播流程,floviq 提供的盤前自動化工具模板(portaly.cc/floviq)涵蓋 TWSE 開放 API 資料整合架構,可作為起點參考。


⑥ 已知邊界條件

  • 假日 / 非交易日:BFI84U 回傳的是預告清單,即使非交易日仍可取得,資料為最後更新狀態。確認「今日是否交易日」需搭配交易日曆另行查詢。
  • 筆數每日滾動:清單隨事件預告動態增減,不是固定筆數。距除息日較遠時筆數較少,密集除息季筆數較多。
  • Reason: 其他 存在:這個概括性的值代表非前四類原因的暫停情境,自動化邏輯需能處理此值而不報錯。

⑦ See also


修正紀錄

先前版本有以下更正:

  • 開場/①/②:停的是融券賣出(停券)、融資買進不停 → 非「暫停融資融券買賣」。
  • 坑 2:MI_MARGN 本身即帶 註記 欄標示停券/停資;兩端點差別在時間粒度 → 非「MI_MARGN 無標記」。
  • 坑 1:parseRocDate("") 回傳 null → 非 NaN(僅省略防呆才會得 NaN)。

※ 本文描述 TWSE BFI84U 端點欄位機制、工程坑與停券(暫停融券)預告查詢實況 · 不構成投資建議,投資請自行評估風險。

資料來源:TWSE BFI84U · TWSE MI_MARGN 註記欄圖例