A trade made on Wednesday 25 November 2026 settles T+1 on Friday 27 November 2026 for a US stock, and USD/JPY spot trades T+2 settle on Monday 30 November, because Thursday 26 November is a US holiday. Settlement date = trade date plus N business days, skipping weekends and any day a relevant country is closed.
Calculate settlement with the API
T+1 means one business day after the trade date. US stocks and ETFs have settled T+1 since 28 May 2024. FX spot trades generally settle T+2, though the day count is a market convention, so use your venue's rules to choose the settlement period.
- Choose the settlement period Set
daysto the number of business days after the trade. The example uses T+1 for a US stock and T+2 for USD/JPY spot. The trade date is the starting point and does not count toward that period. - Set your API key Get a free API key and keep it in the
NARWHAL_API_KEYenvironment variable. The script reads that variable and sends the key asAuthorization: Bearer YOUR_KEYtohttps://api.narwhalapi.com. - Choose the countries Use
USAfor the US stock example and bothUSAandJPNfor USD/JPY. The script requests public holidays throughGET /v1/calendars/holidays/{country}/{year}. A holiday in any country in the list makes that date unavailable for the count. - Calculate the dates Use the script with the trade date, settlement period and country list. It moves forward a calendar day at a time and counts a day only when it is a weekday with no listed holiday. The cache keeps each country and year's holidays available without another request as the loop moves through the dates.Python, settlement date for a stock and a currency pair
import os from datetime import date, timedelta from functools import cache import requests API = "https://api.narwhalapi.com" HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} @cache # one request per country and year, however many days the loop walks def holidays(country: str, year: int) -> frozenset[str]: r = requests.get(f"{API}/v1/calendars/holidays/{country}/{year}", headers=HEADERS, timeout=10) r.raise_for_status() return frozenset(h["date"] for h in r.json()["holidays"]) def settlement(trade: date, days: int, countries: list[str]) -> date: """The date `days` business days after the trade, skipping a day any listed country is closed.""" day = trade while days > 0: day += timedelta(1) closed = any(day.isoformat() in holidays(c, day.year) for c in countries) if day.weekday() < 5 and not closed: days -= 1 return day trade = date(2026, 11, 25) print("US stock, T+1:", settlement(trade, 1, ["USA"])) print("USD/JPY spot, T+2:", settlement(trade, 2, ["USA", "JPN"]))
The holiday lookup uses the year of the day being considered, so the loop can request the appropriate country list when it reaches another year. The cache belongs to the holiday function, while the settlement function takes each trade's date, day count and countries as inputs. Holiday dates come from the response's holidays list. The function reads each date value and compares it with the date in the loop; a match in any listed country prevents that day from counting toward settlement.
Calculate settlement in a spreadsheet
Excel and Google Sheets can calculate the same business-day count with WORKDAY. Put the closure dates in a range named Holidays, then use the trade date and settlement period in the formula. For a currency pair, merge the holiday lists for both countries into that range.
=WORKDAY(DATE(2026,11,25), 1, Holidays)=WORKDAY(DATE(2026,11,25), 2, Holidays)The Holidays range supplies the dates the formula must skip in addition to weekends. For the US stock example, use the US list. For USD/JPY, include the US and Japan lists, so a closure in either country removes that day from the count.
The formula's settlement period and its holiday range have separate jobs. Changing the period from T+1 to T+2 changes how many business days it counts; changing the range changes which dates are eligible. Use the countries involved in the trade when preparing the range.
Which option to use when
| Situation | Best option | Why |
|---|---|---|
| One trade | WORKDAY in a sheet with a merged holiday list | The formula counts the settlement period using the closure dates you supply. |
| A blotter or nightly settlement job | The Python script | The country list supplies the holidays, and the function calculates settlement for a trade date. |
| An exchange-specific calendar, including Good Friday or early closes | The exchange's own calendar | Narwhal's list contains public holidays; exchange closures can differ. |
Does T+2 skip a holiday in the other currency's country?
Yes. In FX convention, both currencies' business days count, so a holiday in either country is skipped. For USD/JPY, pass both USA and JPN to the function. Using only one country's list leaves the other country's holidays out of the calculation.
The settlement period stays T+2 when a holiday falls between the trade and settlement. The holiday moves the settlement date further along the calendar because it does not use up a business day. Weekends are also skipped, even after the first business day has counted.
What if the trade date itself is a holiday?
The first business day after the trade date becomes day 1. The script begins with the supplied trade date, advances to the following calendar day, then looks for a weekday with no holiday in the country list.
A weekend or another holiday immediately after the supplied date also gets skipped. The function continues until the requested number of business days has counted. This is how the script treats a supplied trade date; the settlement period still comes from the market convention and your venue's rules.
Does the public holiday list match an exchange calendar?
Not always. Narwhal's holiday data contains public holidays by country, and exchange closures can differ. The NYSE closes on Good Friday, 3 April 2026, which is absent from the US federal holiday list in the API.
Use the exchange's own calendar when settlement depends on its specific closures or early closes. A country list supplies the public holidays for the calculation; it does not add an exchange closure that is absent from that list.
Worked example: trade on Wednesday 25 November 2026
Start from Wednesday 25 November 2026. Thursday 26 November is Thanksgiving in the US, so it contributes no business day to either example. Friday 27 November is day 1: the US stock reaches T+1 and settles on that date.
| Date | US stock, T+1 | USD/JPY spot, T+2 |
|---|---|---|
| Wednesday 25 November 2026 | Trade date | Trade date |
| Thursday 26 November 2026 | Skip Thanksgiving | Skip US Thanksgiving |
| Friday 27 November 2026 | Day 1, settlement | Day 1 |
| Saturday 28 November 2026 | Skip weekend | |
| Sunday 29 November 2026 | Skip weekend | |
| Monday 30 November 2026 | Day 2, settlement |
For USD/JPY, Friday supplies the first business day. Saturday and Sunday add nothing to the count, so Monday 30 November supplies day 2. The T+2 settlement date for the 25 November 2026 trade is Monday 30 November 2026.
US stock, T+1: 2026-11-27
USD/JPY spot, T+2: 2026-11-30Published .
