FA-61101 / Bond day-count conventions / Open access
Discount-basis bill price and bond-equivalent yield: the bill price discounts over a 365-day year · case 01
Bill prices are too high and yields derived from them too low.
ROOT CAUSE
The discount price formula divides by 365 instead of the 360-day discount basis.
VERIFIED REPAIR
Price bills as 100*(1 - d*t/360).
Unsuccessful approach: Using the 365/366 bond-equivalent basis in the price mixes the two conventions.
Case contract
Inputs settlement and maturity [y,m,d] (1 to 364 days apart) and discount rate d. t = days. Price = 100*(1 - d*t/360). Year basis B is 366 if a 29 February lies in (settle, settle+365 days], else 365. For t <= B/2, BEY = B*d/(360 - d*t); otherwise BEY solves the quadratic with a = t/(2B) - 0.25, b = t/B, c = (price-100)/price, taking (-b + sqrt(b^2 - 4ac))/(2a). Return [price rounded 6, BEY rounded 8].
Why this case matters
Bond accrual and pricing systems depend on exact day-count arithmetic; a single-day error changes settlement cash.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
import math
N = 1
observations = []
def solve(settle, maturity, d):
S = datetime.date(*settle)
M = datetime.date(*maturity)
t = (M - S).days
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
horizon = S + datetime.timedelta(days=365)
basis = 366 if any(leap(y) and S < datetime.date(y, 2, 29) <= horizon for y in (S.year, S.year + 1)) else 365
price = 100 * (1 - d * t / 365)
if t <= basis / 2:
bey = basis * d / (360 - d * t)
else:
a = t / (2 * basis) - 0.25
b = t / basis
c = (price - 100) / price
bey = (-b + math.sqrt(b * b - 4 * a * c)) / (2 * a)
return [round(price, 6), round(bey, 8)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression price day basis 1', [[2084, 8, 31], [2085, 3, 2], 0.001], [99.949167, 0.0010144]], ['regression price day basis 2', [[2014, 4, 28], [2014, 10, 28], 0.08], [95.933333, 0.08453969]], ['partial repair probe 1', [[2064, 11, 26], [2065, 4, 18], 0.025], [99.006944, 0.02560146]], ['partial repair probe 2', [[2024, 1, 15], [2024, 7, 16], 0.025], [98.729167, 0.02574383]], ['normal control 1', [[2100, 6, 28], [2100, 9, 27], 0.08], [97.977778, 0.08278521]], ['normal control 2', [[2022, 10, 15], [2023, 4, 15], 0.01], [99.494444, 0.01019041]], ['normal control 3', [[2089, 2, 4], [2089, 5, 6], 0.0525], [98.672917, 0.05394506]], ['normal control 4', [[2023, 3, 28], [2024, 3, 26], 0.0525], [94.691667, 0.0555986]]], [['regression price day basis 1', [[2019, 8, 3], [2020, 2, 1], 0.0525], [97.345833, 0.05483029]], ['regression price day basis 2', [[2077, 7, 12], [2078, 1, 11], 0.025], [98.729167, 0.02567259]], ['partial repair probe 1', [[2072, 9, 10], [2072, 12, 10], 0.01], [99.747222, 0.01016458]], ['partial repair probe 2', [[2089, 6, 1], [2090, 5, 31], 0.0525], [94.691667, 0.05544668]], ['normal control 1', [[2007, 6, 16], [2008, 6, 14], 0.01], [98.988889, 0.01024442]], ['normal control 2', [[2016, 7, 6], [2016, 9, 18], 0.025], [99.486111, 0.02547815]], ['normal control 3', [[2009, 4, 17], [2010, 4, 10], 0.01], [99.005556, 0.01021515]], ['normal control 4', [[2050, 3, 2], [2050, 8, 30], 0.08], [95.977778, 0.0845103]]], [['regression price day basis 1', [[2007, 10, 28], [2008, 4, 7], 0.08], [96.4, 0.08437068]], ['regression price day basis 2', [[2090, 6, 3], [2090, 9, 2], 0.001], [99.974722, 0.00101415]], ['partial repair probe 1', [[2021, 8, 8], [2022, 2, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 2', [[2028, 2, 28], [2028, 8, 29], 0.0435], [97.78875, 0.04522504]], ['normal control 1', [[2071, 1, 31], [2072, 1, 30], 0.025], [97.472222, 0.02583812]], ['normal control 2', [[2096, 2, 11], [2096, 8, 6], 0.025], [98.770833, 0.02573297]], ['normal control 3', [[2035, 6, 26], [2035, 9, 25], 0.0435], [98.900417, 0.0447167]], ['normal control 4', [[2042, 9, 30], [2043, 9, 29], 0.001], [99.898889, 0.00101466]]], [['regression price day basis 1', [[2028, 12, 28], [2029, 6, 22], 0.01], [99.511111, 0.0101887]], ['regression price day basis 2', [[2090, 11, 19], [2091, 11, 18], 0.08], [91.911111, 0.08638888]], ['partial repair probe 1', [[2028, 12, 28], [2029, 2, 28], 0.0525], [99.095833, 0.05371484]], ['partial repair probe 2', [[2040, 2, 29], [2040, 6, 8], 0.025], [99.305556, 0.02552448]], ['normal control 1', [[2035, 7, 31], [2036, 1, 30], 0.025], [98.729167, 0.02574383]], ['normal control 2', [[2027, 2, 1], [2027, 8, 3], 0.025], [98.729167, 0.02567259]], ['normal control 3', [[2100, 6, 28], [2101, 6, 27], 0.0525], [94.691667, 0.05544668]], ['normal control 4', [[2006, 9, 28], [2006, 12, 28], 0.08], [97.977778, 0.08278521]]], [['regression price day basis 1', [[2100, 2, 28], [2100, 8, 29], 0.01], [99.494444, 0.01019041]], ['regression price day basis 2', [[2024, 10, 6], [2025, 4, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 1', [[2043, 10, 2], [2044, 9, 30], 0.0435], [95.601667, 0.0457395]], ['partial repair probe 2', [[2024, 2, 28], [2024, 8, 29], 0.01], [99.491667, 0.01021861]], ['normal control 1', [[2040, 9, 30], [2041, 3, 31], 0.0435], [97.800833, 0.0450959]], ['normal control 2', [[2053, 7, 5], [2053, 10, 4], 0.01], [99.747222, 0.01016458]], ['normal control 3', [[2067, 11, 30], [2068, 5, 31], 0.025], [98.729167, 0.02574383]], ['normal control 4', [[2092, 9, 21], [2093, 3, 25], 0.001], [99.948611, 0.0010144]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression price day basis 1 | [99.949863, 0.0010005] | [99.949167, 0.0010144] | Failed |
| regression price day basis 2 | [95.989041, 0.08333336] | [95.933333, 0.08453969] | Failed |
| partial repair probe 1 | [99.020548, 0.02560146] | [99.006944, 0.02560146] | Failed |
| partial repair probe 2 | [98.746575, 0.02574383] | [98.729167, 0.02574383] | Failed |
| normal control 1 | [98.005479, 0.08278521] | [97.977778, 0.08278521] | Failed |
| normal control 2 | [99.50137, 0.01019041] | [99.494444, 0.01019041] | Failed |
| normal control 3 | [98.691096, 0.05394506] | [98.672917, 0.05394506] | Failed |
| normal control 4 | [94.764384, 0.05480556] | [94.691667, 0.0555986] | Failed |
SHA-256 / 89afac3d4593475d413c7d480761d0f7c33ea005fc9a7ba1fdce954fe022bcc7
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
import math
N = 1
observations = []
def solve(settle, maturity, d):
S = datetime.date(*settle)
M = datetime.date(*maturity)
t = (M - S).days
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
horizon = S + datetime.timedelta(days=365)
basis = 366 if any(leap(y) and S < datetime.date(y, 2, 29) <= horizon for y in (S.year, S.year + 1)) else 365
price = 100 * (1 - d * t / basis)
if t <= basis / 2:
bey = basis * d / (360 - d * t)
else:
a = t / (2 * basis) - 0.25
b = t / basis
c = (price - 100) / price
bey = (-b + math.sqrt(b * b - 4 * a * c)) / (2 * a)
return [round(price, 6), round(bey, 8)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression price day basis 1', [[2084, 8, 31], [2085, 3, 2], 0.001], [99.949167, 0.0010144]], ['regression price day basis 2', [[2014, 4, 28], [2014, 10, 28], 0.08], [95.933333, 0.08453969]], ['partial repair probe 1', [[2064, 11, 26], [2065, 4, 18], 0.025], [99.006944, 0.02560146]], ['partial repair probe 2', [[2024, 1, 15], [2024, 7, 16], 0.025], [98.729167, 0.02574383]], ['normal control 1', [[2100, 6, 28], [2100, 9, 27], 0.08], [97.977778, 0.08278521]], ['normal control 2', [[2022, 10, 15], [2023, 4, 15], 0.01], [99.494444, 0.01019041]], ['normal control 3', [[2089, 2, 4], [2089, 5, 6], 0.0525], [98.672917, 0.05394506]], ['normal control 4', [[2023, 3, 28], [2024, 3, 26], 0.0525], [94.691667, 0.0555986]]], [['regression price day basis 1', [[2019, 8, 3], [2020, 2, 1], 0.0525], [97.345833, 0.05483029]], ['regression price day basis 2', [[2077, 7, 12], [2078, 1, 11], 0.025], [98.729167, 0.02567259]], ['partial repair probe 1', [[2072, 9, 10], [2072, 12, 10], 0.01], [99.747222, 0.01016458]], ['partial repair probe 2', [[2089, 6, 1], [2090, 5, 31], 0.0525], [94.691667, 0.05544668]], ['normal control 1', [[2007, 6, 16], [2008, 6, 14], 0.01], [98.988889, 0.01024442]], ['normal control 2', [[2016, 7, 6], [2016, 9, 18], 0.025], [99.486111, 0.02547815]], ['normal control 3', [[2009, 4, 17], [2010, 4, 10], 0.01], [99.005556, 0.01021515]], ['normal control 4', [[2050, 3, 2], [2050, 8, 30], 0.08], [95.977778, 0.0845103]]], [['regression price day basis 1', [[2007, 10, 28], [2008, 4, 7], 0.08], [96.4, 0.08437068]], ['regression price day basis 2', [[2090, 6, 3], [2090, 9, 2], 0.001], [99.974722, 0.00101415]], ['partial repair probe 1', [[2021, 8, 8], [2022, 2, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 2', [[2028, 2, 28], [2028, 8, 29], 0.0435], [97.78875, 0.04522504]], ['normal control 1', [[2071, 1, 31], [2072, 1, 30], 0.025], [97.472222, 0.02583812]], ['normal control 2', [[2096, 2, 11], [2096, 8, 6], 0.025], [98.770833, 0.02573297]], ['normal control 3', [[2035, 6, 26], [2035, 9, 25], 0.0435], [98.900417, 0.0447167]], ['normal control 4', [[2042, 9, 30], [2043, 9, 29], 0.001], [99.898889, 0.00101466]]], [['regression price day basis 1', [[2028, 12, 28], [2029, 6, 22], 0.01], [99.511111, 0.0101887]], ['regression price day basis 2', [[2090, 11, 19], [2091, 11, 18], 0.08], [91.911111, 0.08638888]], ['partial repair probe 1', [[2028, 12, 28], [2029, 2, 28], 0.0525], [99.095833, 0.05371484]], ['partial repair probe 2', [[2040, 2, 29], [2040, 6, 8], 0.025], [99.305556, 0.02552448]], ['normal control 1', [[2035, 7, 31], [2036, 1, 30], 0.025], [98.729167, 0.02574383]], ['normal control 2', [[2027, 2, 1], [2027, 8, 3], 0.025], [98.729167, 0.02567259]], ['normal control 3', [[2100, 6, 28], [2101, 6, 27], 0.0525], [94.691667, 0.05544668]], ['normal control 4', [[2006, 9, 28], [2006, 12, 28], 0.08], [97.977778, 0.08278521]]], [['regression price day basis 1', [[2100, 2, 28], [2100, 8, 29], 0.01], [99.494444, 0.01019041]], ['regression price day basis 2', [[2024, 10, 6], [2025, 4, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 1', [[2043, 10, 2], [2044, 9, 30], 0.0435], [95.601667, 0.0457395]], ['partial repair probe 2', [[2024, 2, 28], [2024, 8, 29], 0.01], [99.491667, 0.01021861]], ['normal control 1', [[2040, 9, 30], [2041, 3, 31], 0.0435], [97.800833, 0.0450959]], ['normal control 2', [[2053, 7, 5], [2053, 10, 4], 0.01], [99.747222, 0.01016458]], ['normal control 3', [[2067, 11, 30], [2068, 5, 31], 0.025], [98.729167, 0.02574383]], ['normal control 4', [[2092, 9, 21], [2093, 3, 25], 0.001], [99.948611, 0.0010144]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression price day basis 1 | [99.949863, 0.0010005] | [99.949167, 0.0010144] | Failed |
| regression price day basis 2 | [95.989041, 0.08333336] | [95.933333, 0.08453969] | Failed |
| partial repair probe 1 | [99.020548, 0.02560146] | [99.006944, 0.02560146] | Failed |
| partial repair probe 2 | [98.75, 0.02574383] | [98.729167, 0.02574383] | Failed |
| normal control 1 | [98.005479, 0.08278521] | [97.977778, 0.08278521] | Failed |
| normal control 2 | [99.50137, 0.01019041] | [99.494444, 0.01019041] | Failed |
| normal control 3 | [98.691096, 0.05394506] | [98.672917, 0.05394506] | Failed |
| normal control 4 | [94.778689, 0.05464966] | [94.691667, 0.0555986] | Failed |
SHA-256 / 35a14d6b1e51f3797c199375aa57b7d680fc8c574e45ae37ce62ce9037be717e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
import math
N = 1
observations = []
def solve(settle, maturity, d):
S = datetime.date(*settle)
M = datetime.date(*maturity)
t = (M - S).days
def leap(y):
return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
horizon = S + datetime.timedelta(days=365)
basis = 366 if any(leap(y) and S < datetime.date(y, 2, 29) <= horizon for y in (S.year, S.year + 1)) else 365
price = 100 * (1 - d * t / 360)
if t <= basis / 2:
bey = basis * d / (360 - d * t)
else:
a = t / (2 * basis) - 0.25
b = t / basis
c = (price - 100) / price
bey = (-b + math.sqrt(b * b - 4 * a * c)) / (2 * a)
return [round(price, 6), round(bey, 8)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression price day basis 1', [[2084, 8, 31], [2085, 3, 2], 0.001], [99.949167, 0.0010144]], ['regression price day basis 2', [[2014, 4, 28], [2014, 10, 28], 0.08], [95.933333, 0.08453969]], ['partial repair probe 1', [[2064, 11, 26], [2065, 4, 18], 0.025], [99.006944, 0.02560146]], ['partial repair probe 2', [[2024, 1, 15], [2024, 7, 16], 0.025], [98.729167, 0.02574383]], ['normal control 1', [[2100, 6, 28], [2100, 9, 27], 0.08], [97.977778, 0.08278521]], ['normal control 2', [[2022, 10, 15], [2023, 4, 15], 0.01], [99.494444, 0.01019041]], ['normal control 3', [[2089, 2, 4], [2089, 5, 6], 0.0525], [98.672917, 0.05394506]], ['normal control 4', [[2023, 3, 28], [2024, 3, 26], 0.0525], [94.691667, 0.0555986]]], [['regression price day basis 1', [[2019, 8, 3], [2020, 2, 1], 0.0525], [97.345833, 0.05483029]], ['regression price day basis 2', [[2077, 7, 12], [2078, 1, 11], 0.025], [98.729167, 0.02567259]], ['partial repair probe 1', [[2072, 9, 10], [2072, 12, 10], 0.01], [99.747222, 0.01016458]], ['partial repair probe 2', [[2089, 6, 1], [2090, 5, 31], 0.0525], [94.691667, 0.05544668]], ['normal control 1', [[2007, 6, 16], [2008, 6, 14], 0.01], [98.988889, 0.01024442]], ['normal control 2', [[2016, 7, 6], [2016, 9, 18], 0.025], [99.486111, 0.02547815]], ['normal control 3', [[2009, 4, 17], [2010, 4, 10], 0.01], [99.005556, 0.01021515]], ['normal control 4', [[2050, 3, 2], [2050, 8, 30], 0.08], [95.977778, 0.0845103]]], [['regression price day basis 1', [[2007, 10, 28], [2008, 4, 7], 0.08], [96.4, 0.08437068]], ['regression price day basis 2', [[2090, 6, 3], [2090, 9, 2], 0.001], [99.974722, 0.00101415]], ['partial repair probe 1', [[2021, 8, 8], [2022, 2, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 2', [[2028, 2, 28], [2028, 8, 29], 0.0435], [97.78875, 0.04522504]], ['normal control 1', [[2071, 1, 31], [2072, 1, 30], 0.025], [97.472222, 0.02583812]], ['normal control 2', [[2096, 2, 11], [2096, 8, 6], 0.025], [98.770833, 0.02573297]], ['normal control 3', [[2035, 6, 26], [2035, 9, 25], 0.0435], [98.900417, 0.0447167]], ['normal control 4', [[2042, 9, 30], [2043, 9, 29], 0.001], [99.898889, 0.00101466]]], [['regression price day basis 1', [[2028, 12, 28], [2029, 6, 22], 0.01], [99.511111, 0.0101887]], ['regression price day basis 2', [[2090, 11, 19], [2091, 11, 18], 0.08], [91.911111, 0.08638888]], ['partial repair probe 1', [[2028, 12, 28], [2029, 2, 28], 0.0525], [99.095833, 0.05371484]], ['partial repair probe 2', [[2040, 2, 29], [2040, 6, 8], 0.025], [99.305556, 0.02552448]], ['normal control 1', [[2035, 7, 31], [2036, 1, 30], 0.025], [98.729167, 0.02574383]], ['normal control 2', [[2027, 2, 1], [2027, 8, 3], 0.025], [98.729167, 0.02567259]], ['normal control 3', [[2100, 6, 28], [2101, 6, 27], 0.0525], [94.691667, 0.05544668]], ['normal control 4', [[2006, 9, 28], [2006, 12, 28], 0.08], [97.977778, 0.08278521]]], [['regression price day basis 1', [[2100, 2, 28], [2100, 8, 29], 0.01], [99.494444, 0.01019041]], ['regression price day basis 2', [[2024, 10, 6], [2025, 4, 5], 0.001], [99.949722, 0.0010144]], ['partial repair probe 1', [[2043, 10, 2], [2044, 9, 30], 0.0435], [95.601667, 0.0457395]], ['partial repair probe 2', [[2024, 2, 28], [2024, 8, 29], 0.01], [99.491667, 0.01021861]], ['normal control 1', [[2040, 9, 30], [2041, 3, 31], 0.0435], [97.800833, 0.0450959]], ['normal control 2', [[2053, 7, 5], [2053, 10, 4], 0.01], [99.747222, 0.01016458]], ['normal control 3', [[2067, 11, 30], [2068, 5, 31], 0.025], [98.729167, 0.02574383]], ['normal control 4', [[2092, 9, 21], [2093, 3, 25], 0.001], [99.948611, 0.0010144]]]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression price day basis 1 | [99.949167, 0.0010144] | [99.949167, 0.0010144] | Passed |
| regression price day basis 2 | [95.933333, 0.08453969] | [95.933333, 0.08453969] | Passed |
| partial repair probe 1 | [99.006944, 0.02560146] | [99.006944, 0.02560146] | Passed |
| partial repair probe 2 | [98.729167, 0.02574383] | [98.729167, 0.02574383] | Passed |
| normal control 1 | [97.977778, 0.08278521] | [97.977778, 0.08278521] | Passed |
| normal control 2 | [99.494444, 0.01019041] | [99.494444, 0.01019041] | Passed |
| normal control 3 | [98.672917, 0.05394506] | [98.672917, 0.05394506] | Passed |
| normal control 4 | [94.691667, 0.0555986] | [94.691667, 0.0555986] | Passed |
SHA-256 / ba12cd7e12747f686c1bbbbc834437936c6bed573cc435bf2d34698e44639c32
Verification & scope
A deterministic toy contract stated explicitly in the contract field; no claim of conformance to any published convention text. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:46:52.099321+00:00.
Case digest / fe575920dbceb19ace405739dc0ba3e0c4b6e925b27f3264b1b1f616d86bf0ce