Guides · bonds
Dirty price = clean price + accrued interest. Markets quote the clean price; the buyer pays the dirty price at settlement. Below, the same 5% bond is priced at two settlement dates over a REST API — on a coupon date the two prices are identical, three and a half months later they differ by exactly the accrued coupon.
A 5% annual bond issued 2024-07-01, maturing 2029-07-01, at a flat 4% yield, settling 2026-10-15 — 106 days after the July coupon:
curl -s https://quantbox.dev/v1/bonds/price \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"coupon_rate": 0.05,
"issue_date": "2024-07-01",
"maturity_date": "2029-07-01",
"settlement_date": "2026-10-15",
"frequency": "annual",
"day_count": "act/act",
"yield_rate": 0.04}'
Runs on the free tier — 500 calls/month, no credit card. Get a key.
{
"clean_price": 102.4892,
"dirty_price": 103.9413,
"accrued": 1.4521,
"ytm": 0.04,
"modified_duration": 2.4748,
"convexity": 8.7012,
"bpv": -0.0257,
"conventions": {
"prices": "per 100 of face value (market quote convention)",
"settlement": "as provided (settlementDays=0, no implicit T+2)",
"ytm": "compounded annual, act/act",
"zero_curve": "zero rates continuously compounded, act/365",
"calendar": "TARGET, unadjusted schedule"
}
}
102.4892 + 1.4521 = 103.9413. The identity is exact, not approximate — it is how the dirty price is defined.
import requests
KEY = "YOUR_API_KEY" # free key from https://quantbox.dev
bond = {"coupon_rate": 0.05, "issue_date": "2024-07-01",
"maturity_date": "2029-07-01", "frequency": "annual",
"day_count": "act/act", "yield_rate": 0.04}
for settlement in ["2026-07-01", "2026-10-15"]:
r = requests.post("https://quantbox.dev/v1/bonds/price",
headers={"X-API-Key": KEY},
json={**bond, "settlement_date": settlement})
d = r.json()
print(f"{settlement} clean {d['clean_price']:.4f}"
f" accrued {d['accrued']:.4f} dirty {d['dirty_price']:.4f}")
# 2026-07-01 clean 102.7641 accrued 0.0000 dirty 102.7641
# 2026-10-15 clean 102.4892 accrued 1.4521 dirty 103.9413
| Field | 2026-07-01 (coupon date) | 2026-10-15 (mid period) |
|---|---|---|
| clean_price | 102.7641 | 102.4892 |
| accrued | 0.0 | 1.4521 |
| dirty_price | 102.7641 | 103.9413 |
| ytm | 0.04 | 0.04 |
| modified_duration | 2.754 | 2.4748 |
| convexity | 10.4298 | 8.7012 |
| bpv | -0.0283 | -0.0257 |
On 2026-07-01 the coupon has just been paid, so nothing has accrued and clean = dirty = 102.7641. On 2026-10-15 the holder has earned 106 days of the next coupon: clean and dirty split apart by exactly that amount.
Note the clean price itself also moved (102.7641 → 102.4892) at the same 4% yield. That is not accrued — it is the passage of time pulling a premium bond toward par as it gets shorter. Duration and BPV shrink for the same reason.
Accrued interest is the coupon earned pro rata since the last payment date, measured with the bond's day count. Under act/act, from the 2026-07-01 coupon to the 2026-10-15 settlement is 106 actual days, in a coupon period of 365 actual days:
accrued = coupon × days elapsed / days in period
= 5.00 × 106 / 365
= 1.4521 (per 100 of face value)
Change the day count and the accrued changes — under 30/360 the elapsed-day count is computed on idealized 30-day months. That is why the request names the day count explicitly instead of assuming one.
Accrued interest is deterministic: it grows linearly day by day and drops to zero at each coupon, a sawtooth that has nothing to do with market conditions. Quoting the dirty price would make every bond look like it rallies daily and crashes on coupon dates. The clean price strips the sawtooth out, isolating the market-driven component — so quotes are comparable across days. Settlement, however, is cash for value: the seller gets compensated for the coupon they earned but will not receive, which is why you settle dirty.
| Convention | Value |
|---|---|
| prices | per 100 of face value (market quote convention) |
| settlement | as provided (settlementDays=0, no implicit T+2) |
| ytm | compounded annual, act/act |
| zero_curve | zero rates continuously compounded, act/365 |
| calendar | TARGET, unadjusted schedule |
Settlement is taken literally — no implicit T+2. If your trade settles T+2, pass the actual settlement date; the accrued is computed to that date, not to "today".
Run both calls yourself. Key in seconds, 500 free calls a month, full request schema in the docs.
Get a free API keyNo credit card · schemas and error codes in /docs
Related: Price a fixed-rate bond with a REST API · DV01 / BPV of a bond via API · Bond duration, convexity and BPV over HTTP