TWSE OpenAPI 只給當天資料,歷史要怎麼補?

官方開放資料端點回的是「最新一個交易日」的全市場快照,而且帶 date 參數不會生效——實測加上 ?date=20260601 回來的仍是當天那 1,379 列。所以歷史只有兩種來源:從今天起自己每天抓下來存,或查一份已經累積好的歷史。前者從今天開始算,後者可以直接查到 2004 年。

先確認它真的只有當天(你可以自己驗)

這支端點免註冊、免金鑰,直接 GET 就回 JSON 陣列。實測回 1,379 列,而且整包裡 Date 只有一個值——也就是全市場、單一交易日的快照。加上日期參數也一樣:伺服器回 200,但內容仍是最新那天。

import requests

rows = requests.get(
"https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_ALL",
timeout=30,
).json()

print("列數", len(rows))
print("整包裡有幾個不同的日期:", len({r["Date"] for r in rows}))
print("範例", rows[0]["Date"], rows[0]["Code"], rows[0]["ClosingPrice"])

# 帶日期參數看看:回 200,但日期沒有變
older = requests.get(
"https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_ALL",
params={"date": "20260601"},
timeout=30,
).json()
print("帶日期後的日期集合:", {r["Date"] for r in older})

路線一:從今天開始,自己每天存

排一個收盤後執行的工作,把每天的快照落地。要注意的是,這條路的歷史從你開始跑的那天算起——今天排的工作補不回昨天。另外要自己處理民國年日期與字串型數值,並記得為重跑保留冪等(同一天重抓不要寫成兩份)。

import json, pathlib, requests
from datetime import date

def roc_to_iso(roc: str) -> str:
"""民國年字串 1150811 → 2026-08-11。"""
y = int(roc[:-4]) + 1911
return f"{y}-{roc[-4:-2]}-{roc[-2:]}"

rows = requests.get(
"https://openapi.twse.com.tw/v1/exchangeReport/STOCK_DAY_ALL", timeout=30
).json()

trade_day = roc_to_iso(rows[0]["Date"])
out = pathlib.Path(f"snapshots/{trade_day}.json")
out.parent.mkdir(exist_ok=True)
if out.exists():
print("已經存過,跳過:", trade_day) # 冪等:重跑不會寫成兩份
else:
out.write_text(json.dumps(rows, ensure_ascii=False))
print("已存", trade_day, len(rows), "列")

路線二:直接查已經累積好的歷史

如果你要的是「現在就有 2015 年的資料」,自己累積補不回來。我們這邊的上市日線可回溯到 2004-02-11,涵蓋 1,687 檔、約 520 萬列,日期已經是 ISO 格式、數值已經是數字型別,並且可以直接帶日期區間查詢。

import requests

r = requests.get(
"https://api.twmarketdata.com/v2/datasets/twse-daily-price",
headers={"X-API-Key": "sk_live_你的金鑰"},
params={"symbol": "2330", "start_date": "2026-06-01", "end_date": "2026-07-31"},
timeout=20,
)
r.raise_for_status()
payload = r.json()

print("列數", payload["count"], "資料截止", payload["data_as_of"])
for row in payload["rows"][:3]:
print(row["date"], row["open"], row["close"], row["volume_shares"])

兩條路怎麼選

  • 只需要「從現在開始」的資料、也願意自己維護排程與清洗:路線一就夠,而且完全免費。
  • 需要回溯既有歷史,或不想維護每日排程與重跑補漏:路線二省下的是時間,不是資料——資料本來就是同一個官方來源。
  • 兩條可以並存:先用路線二取回既有歷史,再用路線一自己接著往前累積。

上市與上櫃是兩套,別假設同一支端點

官方的上市與上櫃資料由不同機構、不同端點提供,欄位命名也不一樣。要做全市場分析,兩邊都要接,而且要自己對齊欄位。我們這邊把兩者放進同一套 schema,用 market 欄位標明來源市場,但加總前仍要先確認沒有把同一檔算兩次。

我們沒有的東西,先說清楚

  • 沒有即時報價。這裡是歷史與盤後資料,官方那支開放端點同樣是盤後快照。
  • 自己累積的那條路,我們幫不上——今天沒存的日子,之後誰都補不回來,這是時間的問題不是資料源的問題。
  • 涵蓋範圍以資料集頁上標示的為準,那些數字由資料庫生成,不是手寫的。

常見問題

1官方端點加上 date 參數為什麼沒用?
實測伺服器會回 200,但內容仍是最新那個交易日的快照——加 ?date=20260601 與不加,回來的日期集合完全相同。它的設計就是當期快照,不是歷史查詢介面。
2那我每天自己抓,多久才能累積到夠用的歷史?
從你開始跑的那天算起。想要三年歷史就得跑三年,這條路沒有捷徑——這也是為什麼需要回溯歷史時,得換一個已經累積好的來源。
3官方資料跟你們的資料會不一樣嗎?
來源是同一個。差別在於格式已經整理過(民國年轉 ISO、字串數值轉數字型別)、可以帶日期區間查、上市與上櫃併入同一套 schema。數字本身仍然來自官方。
4日期為什麼是 1150811 這種格式?
那是民國年:115 年 8 月 11 日,也就是 2026-08-11。官方開放資料多半用這個格式,自己抓就要自己轉;轉法在資料清洗那篇有可跑的範例。

想自己查這些資料?免費註冊

相關文章