跳轉到

台股 15 個每日資料 flow

本文件描述 scheduler 在 Asia/Taipei 時區執行的 15 個資料 flow。每個 flow 有自己的排程、重試、稽核紀錄與失敗邊界;不存在「15 個全部完成後才一起往下跑」的全域 gate。

排程與驗證契約

# Flow Owner 排程(台北時間) 直接依賴 完成驗證
1 roster + industry Cortex 07:00;08:00 重試;同目標日成功後停止 無 TWSE、TPEx 名冊分區完成;證據不完整時不得停用既有股票
2 commodities Cortex 07:00;23:00 recovery 無 FRED/Yahoo 各自依來源交易日語意保存最新資料
3 institutional Cortex 16:30 起每 30 分鐘;最後 23:00;同目標日成功後停止 無 官方交易日同時存在 TWSE、TPEx 法人分區
4 Taiwan OHLC Cortex 14:00–17:50 每 10 分鐘探測,同官方批次成功後跳過;18:10 起每 30 分鐘至 23:10 roster 當日 TWSE/TPEx 均就緒才進 canonical range;保留既有 OHLC 修復,歷史 SES 仍需明確要求
5 market daily Cortex 17:40 起每 30 分鐘;最後 23:10 無 index 為 available/derived_available,turnover 與 breadth 均為 available
6 valuation Cortex valuation 18:10、20:10、23:00;monthly revenue 於每月 1–15 日 23:20 探測、週日 06:10 做窗口外修訂 audit;quarterly income 於法定財報窗口每日 23:25 探測、週日 06:20 做窗口外修訂 audit;startup 在窗口內補探測 roster、OHLC(衍生層) 官方交易日存在 valuation row;歷史 recovery 走 FinMind 指定日期補抓;announcement job 只有資料實際變更才重寫 financial domain
7 TX futures Cortex 18:10、19:10、23:00;同目標日成功後停止 無 FinMind TX 法人未平倉資料狀態為 available
8 ex-dividend forecast Cortex 18:20、21:30 roster TWSE、TPEx provider coverage 以同一 snapshot date 原子保存;已結束月份的歷史股利 coverage 同步補齊
9 market surveillance Cortex 18:40、21:30 roster(代碼正規化) 注意/處置來源獨立同步,能力狀態寫入 sync_status
10 day trade Cortex 20:15、21:30、23:00 無 兩交易所完成 T、T+1、T+2 revision window,另保留 bootstrap window
11 margin Cortex 20:30、21:30、23:00;同一目標交易日成功後跳過後續觸發 roster 個股 margin 分區與市場總額分區皆可用;不等待 day-trade flow;尚未成功才補跑,跳過時不新增執行紀錄或通知
12 short + borrow Cortex 20:40;22:40 強制第二批 無 官方 short 與 borrow-sell 兩個狀態皆為 available
13 ETF holdings Cortex 16:30 catalog/full batch;16:40–19:50 每 10 分鐘;20:00、20:05、21:30、23:00;次日 07:30、09:30;startup roster、provider catalog 每日先刷新 provider catalog 並稽核 active ETF coverage;enabled issuer 已進入 terminal 狀態
14 broker branch Data Hub acquisition;Cortex mirror Hub 21:30;Cortex 01:00 Hub complete batch Cortex 僅 mirror Hub 已完成的批次,不在 Cortex 重做 acquisition
15 government banks Data Hub acquisition;Cortex mirror Hub 23:45;Cortex 01:00 Hub complete batch Cortex 僅 mirror Hub 已完成的批次,不在 Cortex 重做 acquisition

衍生資料依賴

flowchart LR
    roster[1 roster] --> ohlc[4 OHLC]
    roster --> valuation[6 valuation]
    ohlc --> technical[technical domain]
    market[5 market daily] --> technical
    ohlc --> financial[financial domain]
    valuation --> financial
    institutional[3 institutional] --> chip[chip domain]
    institutional --> regime[market regime]
    market --> regime
    ohlc --> regime
    futures[7 TX futures] --> chip
    margin[11 margin] --> chip
    short[12 short / borrow] --> chip
    roster --> chip
    chip --> cross[cross-domain SES]
    ohlc --> etf[13 active-ETF facts / recap]
    etfhold[13 ETF holdings] --> etf
  • OHLC 自 14:00 獨立探測,market-daily 維持 17:40;17:40 兩者仍可平行,最後完成者觸發 technical readiness 檢查。提早取得 OHLC 不代表 technical/financial 所需的其他輸入已齊。
  • 18:10 的 valuation 與 TX futures 是兩個平行 job。Financial 只等 OHLC + valuation;chip 只等自己的輸入。
  • Margin 不等待 day-trade。兩者同屬晚間來源,但失敗與重試互不牽連。
  • Technical、financial、chip、market-regime 與 active-ETF 各自有 readiness 邊界。OHLC readiness 以 canonical sync_status 成功為準,不接受只有 ^TWII 或少量 ticker 的 partial row。Technical 與 financial 完成後各自送出自己的 recap analysis,不等待 chip。
  • 每個可能最後完成的 domain/source 都會重試同一個 idempotent cross-domain writer;writer 以既有 PostgreSQL advisory lock 序列化,避免同日互相覆寫。Cross-domain 寫入後立即執行 Story Strategy finalizer;來源未齊或 publisher busy 時啟動既有 bounded retry。
  • Technical、financial、market-regime 會把實際消費的來源內容 fingerprint 寫入 derived_materialization_state。每次計算前後都重讀 fingerprint;期間有來源 commit 時把本次標成 failed,下一個來源觸發或 recovery 會重跑。同鍵 valuation 修訂與不可靠的 transaction-start updated_at 不會再被誤判為 fresh。
  • Technical/financial 的 recap analysis 必須讓該 domain 回傳 status=success 才能把 derived run 標為成功;payload、LLM 或 cache persistence failure 都保留 failed 狀態供 recovery 重試。
  • ETF holdings 或 OHLC 修訂只刷新受影響的 active-ETF facts 與六個交易日 recap;不重播 technical/financial/chip/Story 共用 bundle。LLM 失敗只影響 recap,不回滾 holdings 或 facts。

執行與恢復語意

OHLC 官方公布窗口與當日排程

來源 官方檔案產製窗口(台北時間) 現用公開 JSON
TWSE 約 14:00 一般交易;15:30 加入零股、盤後定價;17:30 加入鉅額交易 exchangeReport/MI_INDEX?response=json&date=YYYYMMDD&type=ALLBUT0999
TPEx 首批產製表列 13:50、檔名說明標 14:00;含盤後批次產製表列 14:55、17:45 www/zh-tw/afterTrading/otc?date=YYYY/MM/DD&type=EW&response=json
  • 來源:TWSE 每日收盤行情、TPEx 上櫃股票基本資料。這些是官方檔案產製時間,不是免費 JSON API 的保證完成時間。首輪據兩市場首批窗口設在 14:00,之後依實際回應日期、schema 與非空資料判斷就緒,不能宣稱 API 每天 14:00 一定齊備。
  • 2026-10-14 20:29 唯讀實測現用 JSON:兩市場 HTTP 200、回應日期均為 20261014,既有 strict parser 通過 TWSE 1,381 筆、TPEx 1,012 筆。此證據只能確認該時刻可用,不能回推當天第一次公布時分;每輪的 update_runs/task_runs 與 OHLC official sources ready 日誌可核對實際探測結果。
  • 開始/結束時間、官方批次窗口與探測間隔集中於 services/daily_update_window.py,cron 與入口讀取相同定義。10 分鐘是本系統在延遲與請求量間的實作選擇,不是交易所公布頻率或官方承諾。14:55、17:45 批次在下一個探測時段 15:00、17:50 處理。
  • 14:00–17:50 在既有 flow/date lease 內,先查該官方批次開始後是否已有成功的 OHLC flow;有則記 skipped,不抓官方端點、不建立 range、不觸發下游。查詢使用 run 的開始時間,避免上一批工作跨過新批次時刻才完成,誤認新批次已處理。
  • 官方有效空資料(resolved_empty/unresolved_no_rows)記 skipped,Telegram 明確顯示「來源端未更新」並等下一輪,17:50 後亦同;不建立正式 OHLC range,避免「尚未公布」凍結成不可重試的 listing evidence。日期不符、schema 不符、連線與解析失敗不論時段均記 failed;canonical 更新本身的錯誤也立即記失敗。摘要只在同 flow/目標日確有成功時,將正常 skipped 視為中性;始終未成功、failed/running/upstream-failure skip 仍會影響整體狀態。通過探測後,canonical acquisition 仍重新抓取並驗證自己的 immutable evidence,探測結果不直接入庫。
  • 首批 OHLC 是當時的官方快照,成交量仍可能隨盤後/鉅額批次修訂;17:50 涵蓋 TPEx 17:45 批次,晚間 18:10、18:40……23:10 繼續同日修訂。已完成的 range 不會阻擋下一輪取得新快照;尚未完成的 range 沿用既有凍結證據與恢復語意。
  • 全部批次順利完成時,早段最多 5 輪 canonical 更新(14:00、15:00、15:30、17:30、17:50),加既有晚間 11 輪,共 16 輪,較原本 12 輪最多增加 4 輪;失敗的工作仍可重試。依 PR review 的 10/14 唯讀容量估算,stage bar+membership 約 4.8 MB/輪,以每年 245 個交易日估算新增約 4.7 GB/年。這是容量估計,不是實測年度用量;本次不引入資料清理或保留期變更。
  • 此入口只接受當下台北日期的官方交易日,14:00 前、官方休市與跨午夜過期目標均不執行,不因來源晚到改抓前日。交易日 calendar envelope 可含上一交易日後的休市日,以保留公司行為證據;不包含更早的交易日。
  • 17:40 前若 OHLC 尚未進入當日,入庫前會查前一官方交易日的 technical/financial fresh marker、chip chain 成功紀錄、各 SES domain 日期,以及既有 cross-domain writer 的待更新清單。尚未完成就記 skipped,讓前一日仍可依既有最新日規則完成;17:40 起不再因這個新增條件延期。這些都是唯讀檢查,不補算歷史、不清除 dirty state;已進入當日則照常修訂。沿用現有 cross-domain eligibility 語意,不另定義歷史 NULL-vintage 修復或跨來源鎖定契約。
  • 等待時,update_runs.message 與 task_runs.error_message 記錄上述檢查順序中的第一個阻擋項目及日期,例如 financial@2026-10-14 not fresh;Story domain 檢查也保留各 domain 最新日期。這不是所有阻擋項目的完整清單;先修復該項後,下一輪才能確認後續條件。
  • 此等待入口不重驅 D-1 的任何 SES producer。 若 derived 持續 failed/stale,且沒有其他既有流程使它恢復 fresh,14:00–17:30 會持續 skipped,當日最早退回 17:40 才能依原條件進行 OHLC 更新,並非每天保證提早。2026-10-15 唯讀核對 financial@2026-10-14 仍因 financial inputs changed during materialization 停在 failed(最後錯誤為 10/15 08:18,台北時間);若本版當日已部署且狀態未恢復,就會發生上述延期。公告 flow 競態與是否增加重試另由 #1910 追蹤,本 PR 不增加重算或自動重試。
  • SCHEDULED_CLOSE 的公司行為處理沿用既有 per-ticker action child 與 parent finalization,允許必要的歷史 OHLC 修復;不因一檔需要 child 就將整個市場永久停在 pending。既有 delta 分類仍將歷史 SES replay 留為 manual_required,一般 SES 只允許最新有效日。
  • Startup/夜間 unfinished discovery 保留原有歷史 OHLC 中斷續跑語意及 factor/manual-replay 篩選;本次只調整當日 OHLC 啟動窗口,不重設歷史修復政策。歷史 OHLC 修復/續跑不等於歷史 SES 重算授權。

補跑與修訂通知

  • 純補跑的 roster_industry、institutional、tx_futures、margin 在同 flow/目標日已有成功紀錄後,於 lease 內停止後續來源抓取,不新增來源 run 或 Telegram。法人/台指期的既有 chip、market-regime 與 cross-domain readiness 檢查仍可獨立恢復失敗或 stale 的衍生工作,chip/market-regime 沿用各自去重及 run 紀錄;cross-domain 僅在既有 eligibility 查詢發現缺少 coverage 或較新輸入時執行,不因來源 cron 重複呼叫 writer 與 Story finalizer。Story 發布失敗仍由既有 bounded retry、startup 與定時刷新恢復。失敗、等待與其他目標日不會阻擋補跑。法人還須確認本輪 TWSE、TPEx 寫入均成功,不能只靠舊資料判斷本次成功。
  • OHLC、市場日資料、估值、當沖、short/borrow、除權息、注意/處置公告、月營收、季報、商品及 ETF 保留既有修訂抓取時段;Hub 每日鏡像亦保留,依實際新增/較新 revision/對帳刪除判斷是否更新。OHLC 早段同官方批次成功的跳過規則亦保留,不增加 canonical 抓取頻率。
  • 實際內容未變時,run 保持 success,Telegram 顯示 ℹ️ Cortex 來源端未更新,包含來源與目標日;有效但尚未發布目標日資料則為 skipped 並說明來源日期/缺口。每次均通知,不做同來源/同日去重,也不限制次數。 連線、解析、來源不完整等真錯誤仍為 failed。
  • 比較的是寫入範圍內的實際內容,不以抓取筆數、抓取時間或先前成功紀錄當作修訂證據。商品同時比較行情及近期指標;ETF 比較持股新增/修改/刪除,名冊中繼資料不在此計數範圍。公告無當日新公告是有效結果,不強制要求公告日等於交易日。
  • ETF 未發布/來源日期不符不再當作抓取失敗;同輪有真實失敗仍優先報錯。既有完整性警示維持警示語意,不能以零變更或未發布掩蓋;同輪有未發布與警示仍為 skipped 並同時說明。長期未補齊且本日已抓取而節流的缺口維持 failed 告警,明示本輪未重新抓取,不能宣稱剛向來源確認未更新。無待抓取缺口的輪次明示「無新增補齊資料」,不宣稱已向來源確認未更新。
  • 來源資料相同不代表衍生資料已完成;OHLC、估值與日資料仍保留原有 freshness/下游恢復路徑,估值未變時不再強制重算 financial。

各 flow 的恢復邊界

  • daily_flow_* source wrapper 以 flow + official target date 取得 PostgreSQL advisory lock,避免同一交易日的 cron、startup 與多 process 重複執行。Commodity cron/catchup 亦共用當日 commodities lease;surveillance、ETF 與 Hub 保留各自 runner 與 single-instance 控制。
  • 每次執行寫入 update_runs 與 task_runs。一個 flow 失敗只把自己的 run 標成 failed,其他 flow 繼續。
  • Startup、--run-now 與每日 08:10 recovery 使用相同 source wrappers。它們掃描設定的 lookback 官方交易日,只補沒有成功 flow + date run 的來源;同一天的來源平行執行。每個日期在來源掃描後另做 technical/financial/market-regime freshness 檢查,因此來源已成功但 derived 缺漏、失敗或 stale 時仍會獨立補跑。
  • Valuation 的當日入口使用 TWSE/TPEx 最新快照;recovery 遇到較舊官方交易日則呼叫 FinMind historical backfill 的單日區間,避免拿最新快照假裝補歷史日期。
  • 每個 retry 都重新跑同一個 idempotent runner。Market-daily 各分區在後續 source_error/no_data/pending_source 時保留已 available 的值,其他成功分區仍可修訂;本輪錯誤仍記 failed。注意/處置公告獨立保存成功端點,任何端點抓取/解析失敗仍讓該 run failed,之後可重試。Partial market-chip upsert 只更新該來源擁有的欄位;失敗嘗試由 update_runs 保存,已是 available 的來源分區不會被降級成 no_data/source_error。
  • ETF 16:30 full batch、startup full batch 與所有 retry window 共用 daily-data-flow:etf_holdings:<official date> PostgreSQL advisory lease;full 尚未完成時 retry 直接跳過,不會覆寫同一 ETF/日期的結果。
  • Day-trade 歷史 replay 對 revision_stage/is_final 採單調更新;較舊 anchor 可以更新來源數值,但不能把既有 stage 2 final row 降成 stage 0/1。
  • 無資料變更的 OHLC 成功重試會保留既有 sync_status.updated_at 內容版本;狀態或錯誤改變仍會推進 timestamp。
  • Monthly revenue 與 quarterly income 保留獨立公告型入口,失敗與 valuation 互不牽連。公告窗口每日探測缺漏,週日 audit 捕捉窗口外更正;upsert 先做欄位差異判斷,只有實際新增/修訂才強制重跑 financial readiness。Startup 只在當下落於公告窗口時補一次,不在窗口外額外全量抓取。
  • 每個可到達的 strategy writer 之前都執行 hash protected rule-catalog import;catalog 未變更時為 no-op。

公告型來源查證

  • 月營收的正式來源是 MOPS 現行快照 t187ap05_L.csv/t187ap05_O.csv。證券交易法第 36 條要求每月 10 日以前申報上月營運;自 2026 會計年度起,保險業及具保險子公司的公開發行公司得延至 15 日。因此 scheduler 在每月 1–15 日探測,完整涵蓋一般與特殊期限。法規來源:證券交易法第 36 條、特殊適用範圍辦法第 3 條。
  • 季損益的正式來源是 MOPS 現行快照 t187ap14_L.csv/t187ap14_O.csv。一般公司 Q1/Q2/Q3 是季末後 45 日、年度是年度終了後 3 個月;金控 Q1/Q3 最晚 5/30、11/29,金融業 Q2 最晚 8/31。Scheduler 因此使用 1/1–3/31、4/1–5/30、7/1–8/31、10/1–11/29 四段窗口;固定截止日遇休市時,窗口結束日依 TWSE 官方日曆順延至下一交易日。期限表來源:TWSE 財務報告申報注意事項。
  • 2026-10-14 唯讀核對四個正式 CSV:上市/上櫃月營收皆為 2026-09 資料、出表日 2026-10-13;上市/上櫃季損益皆為 2026 Q2、出表日 2026-10-14。這些 endpoint 是會重新出表的全市場現行快照,不提供逐公告 webhook,所以採窗口 polling 加內容差異判斷;週日 audit 負責窗口外更正。23:20/23:25 是 Cortex 的操作時間,安排在 23:10 最後一輪日資料 flow 之後,並非外部法定時間。

週更邊界

  • 週五 20:00 同時啟動近 30 日 institutional 維護與 TDCC ownership probe。兩者各自寫 task 狀態;institutional 失敗不會阻止 TDCC。
  • TDCC 尚未發布時,沿用動態 DateTrigger:每次完成後約 30 分鐘再試,總預算 60 小時。完成條件是本週 ownership date 到齊、institutional 已到該 ownership date,且 chip snapshot 已反映該版本。
  • 週 recap 仍以官方當週最後交易日與所需日更/夜間輸入判斷,不額外綁最新 TDCC。

操作檢查

  1. 用 update_runs.job_name = 'daily_flow_<flow>' 檢查 close-time source wrapper;commodity、market surveillance、ETF、Hub 分別查 commodity、market_surveillance、etf_retry、hub_participant_flows。
  2. 用同一 run 的 task_runs 確認實際步驟完成,避免只看 cron 是否 fire。
  3. Technical/financial 查 daily_derived_technical、daily_derived_financial;chip 查 nightly_chip_chain 與 sync_status。
  4. ETF 查 etf_holdings_sync、active-ETF facts 與 recap cache;不得以 MAX(stock_ohlc.timestamp) 當 ETF target date。
  5. Hub flow 先確認 Hub complete batch,再檢查 Cortex 01:00 mirror;Cortex 不直接呼叫外部 acquisition。