Guides · bonds
One POST returns the full analytics sheet of a fixed-rate bond: clean and dirty price, accrued interest, yield, modified duration, convexity and basis-point value — with the schedule and day-count machinery handled server-side.
Duration itself is one line of math. What is not one line: generating the coupon schedule backwards from maturity, applying the right day count (act/act ISDA vs 30/360 change your accrued), compounding the yield at the coupon frequency, and keeping the settlement date honest. That bookkeeping is where spreadsheet bond math quietly goes wrong — so the request states all of it explicitly.
A 5% annual bond issued 2024-07-01, maturing 2029-07-01, priced at settlement 2026-07-01 with a flat 4% yield:
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-07-01",
"frequency": "annual",
"day_count": "act/act",
"yield_rate": 0.04}'
{
"clean_price": 102.7641,
"dirty_price": 102.7641,
"accrued": 0.0,
"ytm": 0.04,
"modified_duration": 2.754,
"convexity": 10.4298,
"bpv": -0.0283,
"conventions": {
"prices": "per 100 of face value (market quote convention)",
"settlement": "as provided (settlementDays=0, no implicit T+2)",
"ytm": "compounded annual, act/act",
"calendar": "TARGET, unadjusted schedule"
}
}
| Field | Value | Meaning |
|---|---|---|
| modified_duration | 2.754 | ΔP ≈ −D·P·Δy — a +100 bp yield move costs about 2.754% × 102.76 ≈ 2.83 points of price. |
| convexity | 10.4298 | Second-order correction: add ½·C·P·Δy² for larger moves. |
| bpv | -0.0283 | Exact price change for +1 bp of yield, per 100 face. Negative: yields up, price down. Repriced, not approximated. |
| accrued | 0.0 | Settlement falls exactly on a coupon date, so clean = dirty here. Shift settlement a month and they diverge. |
Sanity check the trio: duration × price / 10,000 = 2.754 × 102.76 / 10,000 ≈ 0.0283 — the BPV, with the sign telling you the direction.
Replace yield_rate with a zero_curve (pillars in years + continuously-compounded zero rates) and the bond is discounted off it; the response then also backs out the equivalent YTM:
"zero_curve": [
{"tenor_years": 1, "zero_rate": 0.035},
{"tenor_years": 3, "zero_rate": 0.040},
{"tenor_years": 5, "zero_rate": 0.042}
]
Need the curve itself from market quotes? That is POST /v1/curves/bootstrap — deposits and swap rates in, discount factors and zero rates out.
Settlement is taken literally. No implicit T+2 — you pass the date the trade actually settles. That makes results reproducible instead of "correct on the day you ran it".
YTM compounding follows the coupon frequency. An annual 4% and a semiannual 4% are different yields. The conventions block restates which one you got.
Prices are per 100 of face, market convention, whatever face you pass.
Run this bond 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 an option in 5 lines of Python · Value-at-Risk and Expected Shortfall in one call