在两个国家之间结算交易的券商后台,必须把结算日放在两国都营业的一天,所以每种货币对应国家的节假日都会让日期顺延。Narwhal 会返回每个国家的节假日,并附带适用范围和行政区划;一个简短的脚本就能把整份交易清单对照两套日历,并标出所有与单纯按工作日计算结果不同的交易。
跨境交易为什么需要两套节假日日历
结算 USD/JPY 交易的券商后台,需要找到日本和美国都营业的一天。只要窗口期内任一国家有节假日,只按工作日计数就会出错,而差一天的结算指令要么失败,要么迟到。节假日接口一次只回答一个国家,所以后台要对每一条腿分别请求,再合并结果。下面的请求询问日本在 2026 年 11 月 23 日是否有节假日。
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/calendars/holidays/JPN/on/2026-11-23"{
"country": "JPN",
"coverage": [
{
"scope": "national_public",
"subdivision_codes": []
}
],
"holidays": [
{
"date": "2026-11-23",
"name": "Labor Thanksgiving Day",
"holiday_key": "labor_thanksgiving_day",
"local_name": "勤労感謝の日",
"scope": "national_public",
"subdivision_codes": []
}
]
}返回的条目是 Labor Thanksgiving Day,scope 为 national_public,subdivision_codes 列表为空表示全国适用。对美国 11 月 26 日发出同样的请求,会返回 scope 为 federal_government 的 Thanksgiving Day。每个国家的列表都有自己的 scope,所以后台要记录自己依据的是哪一份列表。只按工作日计数的话,11 月 23 日周一仍会被当作结算日。
让交易清单对照两套日历
脚本按每笔交易两种货币所属国家的日历来结算,并把仅按工作日计数得到的日期与实际日期并排列出。两者不同的交易会标记为 CHECK,这就是运营负责人要复核的清单。
- 指定每条腿所属的国家
JPY列出日本和美国,GBP列出英国(交易台所在的行政区划为GB-ENG)和美国。 - 每年只加载一次
holidays获取一个国家某一年的列表并缓存起来,所以几百笔交易的清单也只需发出寥寥几次请求。临近 12 月 31 日的交易,在逐日推进到下一年时才会加载下一年的数据。 - 跳过周末和任一国家的休市日
closures返回落在所列任一国家当天的节假日,只有这份列表为空的日子才计入 N 天。带有行政区划列表的节假日,只有当交易台所在的区划在列表中时才会使交易台休市。import os from datetime import date, timedelta from functools import cache import requests HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} @cache def holidays(country, year): r = requests.get( f"https://api.narwhalapi.com/v1/calendars/holidays/{country}/{year}", headers=HEADERS, timeout=10, ) r.raise_for_status() return r.json()["holidays"] def closures(day, places): out = [] for country, region in places.items(): for h in holidays(country, day.year): # an empty subdivision list means the holiday applies nationwide if h["date"] == day.isoformat() and (not h["subdivision_codes"] or region in h["subdivision_codes"]): out.append(f"{country} {h['name']}") return out def settle(trade, n, places): day, held = trade, [] while n > 0: day += timedelta(1) if day.weekday() >= 5: continue shut = closures(day, places) if shut: held.append(f"{day:%d %b} {'; '.join(shut)}") else: n -= 1 return day, held JPY = {"USA": None, "JPN": None} GBP = {"GBR": "GB-ENG", "USA": None} # country -> subdivision of the desk blotter = [ ("USD/JPY", date(2026, 11, 20), 2, JPY), ("USD/JPY", date(2026, 11, 24), 2, JPY), ("GBP/USD", date(2026, 12, 23), 2, GBP), ] for pair, trade, n, places in blotter: day, held = settle(trade, n, places) plain, _ = settle(trade, n, {}) flag = "CHECK" if day != plain else "same" print(f"{pair} {trade} T+{n} settles {day}, weekdays only {plain} [{flag}]", "; ".join(held))
USD/JPY 2026-11-20 T+2 settles 2026-11-25, weekdays only 2026-11-24 [CHECK] 23 Nov JPN Labor Thanksgiving Day
USD/JPY 2026-11-24 T+2 settles 2026-11-27, weekdays only 2026-11-26 [CHECK] 26 Nov USA Thanksgiving Day
GBP/USD 2026-12-23 T+2 settles 2026-12-29, weekdays only 2026-12-25 [CHECK] 25 Dec GBR Christmas Day; USA Christmas Day; 28 Dec GBR Boxing Day第一笔交易在 11 月 20 日周五,仅按工作日计算会在 11 月 24 日周二结算。由于日本 11 月 23 日周一休市,第二天顺延到 11 月 25 日周三。第二笔交易被美国的 Thanksgiving Day 顺延,第三笔则因两国的 Christmas Day 以及英国的 Boxing Day 顺延到 12 月 28 日周一。这份清单中的每一行都与单纯按工作日计算的结果不同。
后台仍需人工核对的事项
| 检查 | 来源 |
|---|---|
| 周末 | 跳过周六和周日的循环 |
| 各货币所属国家的节假日 | 节假日接口,每条腿查一个国家 |
| 交易台所在地区的地区性节假日 | 将 subdivision_codes 与交易台的行政区划比对 |
| 交易所或支付系统的休市日 | 把该场所自己的列表加入循环检查的集合 |
| 天数,T+1 还是 T+2 | 产品和交易场所的规则,API 不作规定 |
最后两行仍由后台负责,因为节假日列表属于国家,而不属于某个交易场所。
交易日期附近有休市日时提醒交易员
GET /v1/calendars/holidays/{country}/next?from_date=2026-11-20 会在 holiday 对象中返回该日期当天或之后的第一个节假日。日本返回的是 11 月 23 日,美国返回的是 11 月 26 日,两者都落在 T+2 窗口内。每次录入交易时,对每条腿各调用一次,并告知交易员即将有休市日。判断日期本身时,请使用整年的列表。
这份列表与交易所或支付系统的日历一致吗?
它列出一个国家的节假日,附带适用范围和行政区划;只在交易所或支付系统存在的休市日不在其中。2026 年的美国列表有 11 个条目,其中没有 4 月 3 日的 Good Friday,而部分交易所在这一天休市。请把交易场所的休市日加入循环检查的集合。
某个国家当年没有日历时会怎样?
API 会返回 404 问题响应,代码为 calendar_not_published。英国 2028 年的请求就是这样。raise_for_status() 会让脚本停下,对于不容出错的指令,这是安全的行为。请决定是退回到按工作日计算并标记该日期,还是等待。
货币对应当跳过哪些日子?
任一国家休市的日子都要跳过。USD/JPY 交易要等到东京和美国都营业的一天。T+1 还是 T+2,以及中间那一天有无例外,都由市场规则决定,API 不会给出,所以请核对产品的惯例。
发布于。