A broker back office settling a trade across two countries must land on a day when both are open, so each currency's holidays move the date. Narwhal returns each country's public holidays with their scope and subdivisions, and a short script can run a whole blotter against both calendars and mark every trade whose date differs from a weekday count.
Why a cross-border trade needs two holiday calendars
A broker back office settling a USD/JPY trade has to find a day on which both Japan and the United States are open. A weekday-only count is wrong whenever either country has a holiday inside the window, and a settlement instruction a day off fails or arrives late. The holiday endpoints answer one country at a time, so the back office asks for each leg and combines the results. This request asks whether Japan has a holiday on 23 November 2026.
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": []
}
]
}The entry is Labor Thanksgiving Day with scope national_public, and an empty subdivision_codes list means it applies nationwide. The same request for the United States on 26 November returns Thanksgiving Day with scope federal_government. Each country's list carries its own scope, so the back office records which list it relies on. A weekday count alone would still call Monday 23 November a settlement day.
Run the blotter through both calendars
The script settles each trade of a blotter against the countries of its two currencies, and reports the date that a weekday-only count would have given beside the real one. A trade where the two differ is marked CHECK, which is the list an operations lead reviews.
- Name the countries of each leg
JPYlists Japan and the United States, andGBPlists the United Kingdom with the desk's subdivisionGB-ENGand the United States. - Load each year once
holidaysfetches a country's list for a year and keeps it, so a blotter of hundreds of trades makes a handful of requests. A trade near 31 December loads the next year when the walk reaches it. - Skip weekends and closures of either country
closuresreturns the holidays that fall on a day in any listed country, and a day counts toward N only when that list is empty. A holiday with a subdivision list closes the desk only when its subdivision is in the list.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 DayThe first trade, on Friday 20 November, would settle on Tuesday 24 November by weekdays alone. Japan is closed on Monday 23 November, so the second day moves to Wednesday 25 November. The second trade is held by the US Thanksgiving Day, and the third by Christmas Day in both countries and by Boxing Day in the United Kingdom, on Monday 28 December. Every line in this blotter differs from a weekday count.
What the back office still checks by hand
| Check | Where it comes from |
|---|---|
| Weekends | The loop, which skips Saturday and Sunday |
| Public holidays of each currency's country | The holiday endpoints, one country per leg |
| A regional holiday at the booking desk | subdivision_codes, compared with the desk's subdivision |
| Closures of an exchange or a payment system | The venue's own list, added to the set the loop checks |
| The number of days, T+1 or T+2 | The product and venue rules, which the API does not set |
The last two rows stay with the back office, because the holiday list belongs to a country and not to a venue.
Warn the trader when a closure sits near the trade
GET /v1/calendars/holidays/{country}/next?from_date=2026-11-20 returns the first holiday on or after that date in a holiday object. For Japan it returned 23 November, and for the United States it returned 26 November, both inside a T+2 window. Run it for each leg when a trade is booked and tell the trader that a closure is coming. Use the year list for the date itself.
Does the list match an exchange or payment calendar?
It lists public holidays for a country, with scope and subdivisions. A closure that exists only at an exchange or a payment system is absent. The US list for 2026 has 11 entries and none on Good Friday, 3 April, a day some exchanges close. Add the venue's closures to the set the loop checks.
What happens when a country has no calendar for the year?
The API returns a 404 problem response with the code calendar_not_published. The United Kingdom's 2028 request did that. raise_for_status() stops the script, which is the safe behaviour for an instruction that must not go out wrong. Decide whether to fall back to weekdays and flag the date, or wait.
Which days should a currency pair skip?
A day is skipped when either country is closed. A USD/JPY trade waits for a day open in both Tokyo and the United States. Check the convention of the product, because T+1 or T+2 and any exception for the intermediate day come from the market rules, which the API does not state.
Published .