按頁讀取觀測值端點,直到游標為空:2025 年 11 月 3 日至 2026 年 10 月 23 日的 USD/IDR 每日匯率共 249 天,按每頁 100 列計算只需 3 次請求。每個帳戶都可以回溯到該資料序列的起點。
用 API 回補
觀測值端點接受日期範圍、頁大小上限和游標。外匯匯率使用 /v1/fx/rates/{base}/observations,CPI 使用 /v1/economics/{country}/cpi/observations,大宗商品 K 線使用 /v1/commodities/spot/{commodity}/{currency}/bars。日期參數依端點不同,為 start 和 end,或 start_date 和 end_date。每個回應都有 next_cursor,最後一頁該值為 null。
- 設定你的 API 金鑰 取得免費 API 金鑰,並將它存放在環境變數
NARWHAL_API_KEY中。指令碼會讀取該變數,並以Authorization: Bearer YOUR_KEY將金鑰傳送至https://api.narwhalapi.com。 - 設定資料序列和日期範圍 範例請求 2025 年 11 月 1 日至 2026 年 10 月 23 日的 USD/IDR,
limit設為 100。傳送上一個回應回傳的游標時,每一頁都要保持相同的篩選條件。 - 把每一頁儲存到檔案 使用該腳本把每筆觀測值作為一行 JSON 附加到
usd_idr.jsonl。只要next_cursor有值就繼續傳送請求,該值為空時停止。import json, os import requests H = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} params = { "currencies": "IDR", "start_date": "2025-11-01", "end_date": "2026-10-23", "limit": 100, } rows, pages, cursor = 0, 0, None with open("usd_idr.jsonl", "a") as out: while True: if cursor: params["cursor"] = ( cursor # the cursor carries the filters; resend them unchanged ) r = requests.get( "https://api.narwhalapi.com/v1/fx/rates/USD/observations", params=params, headers=H, timeout=15, ) r.raise_for_status() body = r.json() for day in body["observations"]: out.write(json.dumps(day) + "\n") rows += 1 pages += 1 cursor = body.get("next_cursor") if not cursor: break print(pages, "pages,", rows, "days") - 查看回傳的日期 對於 2025 年 11 月 1 日至 2026 年 10 月 23 日的範圍,腳本會輸出
3 pages, 249 days。回應的起始日期可能晚於你請求的起始日期,所以除了最後一個日期,也要查看第一個已儲存的日期。
腳本分別統計頁數和天數。它先寫入每筆觀測值,再請求下一頁,游標迴圈結束後輸出合計。檔案以附加模式開啟,每一行儲存一筆觀測值。請求讀取的是以 USD 為基礎貨幣的 IDR 資料序列。
每一頁按一次呼叫從你的額度中扣除,使用免費額度的帳戶每分鐘限 50 次請求。回補多個資料序列時,即使每個序列只需要幾頁,也需要在頁與頁之間留出間隔,才能不超過每分鐘的限制。
回應帶有 X-RateLimit-Remaining。如果某頁請求回傳 429 rate_limit_exceeded,請先依 Retry-After 的值等待,再請求下一頁。402 insufficient_credits 回應表示餘額已用完,請先儲值再繼續。錯誤使用 application/problem+json,並包含 status、code、detail 和 request_id,因此要根據錯誤代碼判斷回補能否繼續。
使用試算表或無程式碼工作流程
幾百列的資料用 Sheets 匯入就足夠了。對於一次性的回補,腳本比迴圈翻頁的工作流程更簡單。如果希望觀測值一到就寫入,請使用檔案方式;Python 範例在整個回補過程中都會附加資料列。
n8n、Make 或 Zapier 也可以用游標迴圈翻頁。工作流程每次傳送游標時都要帶上相同的日期和資料序列篩選條件,並在 next_cursor 為 null 時停止。持續更新的資料流可以先做一次回補,再接上每日資料拉取。
選擇回補方式
| 情況 | 最適合的方式 | 原因 |
|---|---|---|
| 一次性回補單一資料序列一年的資料 | 腳本 | 它逐頁讀取整個範圍,並把資料列附加到檔案 |
| 多個資料序列 | 遍歷各資料序列,並在頁與頁之間暫停 | 暫停可使請求保持在每分鐘限制之內 |
| 持續更新的資料流 | 先回補一次,再每天拉取 | 回補會補上每日拉取開始之前的歷史資料 |
回補中途停止了怎麼辦?
從上次儲存的日期重新開始。腳本每收到觀測值就附加 JSON 行,所以即使工作中斷,已寫入的資料列仍保留在檔案中。把這個已儲存的日期作為繼續該範圍的起點。
儲存的游標可能會過期。如果請求回傳 409 cursor_expired,請不帶游標重新開始,並從上次儲存的日期繼續。游標攜帶了其範圍的篩選條件,所以在翻頁讀取該範圍期間,不要更改這些條件。
每頁最多可以請求多少列?
limit 最大可設為該端點的上限:外匯匯率觀測值為 366,經濟資料觀測值為 1,000,大宗商品 K 線為 500,經濟日曆為 100。預設值為 100。limit 只控制頁大小,你仍然需要沿著 next_cursor 一直讀取,直到回應中沒有下一頁。
為什麼我的回補比請求的起始日期晚開始?
所有帳戶都可讀取完整歷史。回傳的第一個日期顯示序列實際從何時開始,因此請求更早的開始日期並不保證回傳更早的列。
計算範例:2025 年 11 月 1 日至 2026 年 10 月 23 日的 USD/IDR
以 2025 年 11 月 1 日為起始、2026 年 10 月 23 日為結束、頁大小上限 100 來請求 USD/IDR,並用相同的篩選條件依序使用回傳的游標。在這個範圍內,回應共有 3 頁 249 列,所以回補需要 3 次請求。
第一列是 2025 年 11 月 3 日星期一,因為 2025 年 11 月 1 日和 2 日是週末。2025 年 11 月 3 日的 USD/IDR 匯率為 16,710.3,2026 年 10 月 23 日為 18,107.8。
| 項目 | 結果 |
|---|---|
| 請求的範圍 | 2025 年 11 月 1 日至 2026 年 10 月 23 日 |
| 頁大小上限 | 100 列 |
| 該範圍的頁數和請求數 | 3 頁,3 次請求 |
| 該範圍的列數 | 249 |
| 第一筆觀測值 | 2025 年 11 月 3 日:每 1 USD 兌 16,710.3 IDR |
| 最後一筆觀測值 | 2026 年 10 月 23 日:每 1 USD 兌 18,107.8 IDR |
發布於 。