broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(issue, first, settle, rate, months):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    I = datetime.date(*issue)
    Fc = datetime.date(*first)
    S = datetime.date(*settle)
    if not (I <= S <= Fc):
        return 'settlement outside first period'
    freq = 12 // months
    def back(k):
        t = Fc.year * 12 + Fc.month - 1 - k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(Fc.day, mlen(y, m)))
    q = [Fc]
    k = 1
    while q[-1] > I:
        q.append(back(k))
        k += 1
    frac = Fraction(0)
    for j in range(len(q) - 1):
        end, start = q[j], q[j + 1]
        lo = max(start, I)
        hi = min(end, S)
        if hi > lo:
            frac += Fraction((hi - lo).days, (end - start).days)
    return round(float(100 * Fraction(str(rate)) * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression coupon per quasi period 1', [[2005, 9, 29], [2005, 10, 31], [2005, 9, 30], 0.02, 3], 0.005435], ['regression coupon per quasi period 2', [[2041, 9, 29], [2042, 3, 31], [2041, 10, 18], 0.05, 6], 0.260914], ['partial repair probe 1', [[2030, 8, 6], [2031, 11, 1], [2031, 4, 19], 0.0675, 12], 4.734247], ['partial repair probe 2', [[2031, 8, 7], [2033, 2, 28], [2031, 10, 22], 0.02, 12], 0.416438], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2035, 2, 3], [2035, 5, 4], [2035, 2, 3], 0.045, 3], 0.0], ['normal control 2', [[2019, 11, 10], [2020, 3, 3], [2019, 11, 7], 0.045, 6], 'settlement outside first period'], ['normal control 3', [[2007, 12, 27], [2008, 1, 1], [2007, 12, 27], 0.05, 1], 0.0]], [['regression coupon per quasi period 1', [[2040, 8, 29], [2040, 9, 6], [2040, 8, 31], 0.03, 3], 0.016304], ['regression coupon per quasi period 2', [[2030, 7, 25], [2030, 9, 15], [2030, 9, 15], 0.05, 3], 0.706522], ['partial repair probe 1', [[2015, 7, 5], [2018, 1, 31], [2017, 9, 10], 0.02, 12], 4.367123], ['partial repair probe 2', [[2023, 11, 5], [2025, 4, 30], [2025, 4, 30], 0.03, 12], 4.45082], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2038, 1, 19], [2038, 3, 31], [2038, 1, 19], 0.03, 6], 0.0], ['normal control 2', [[2012, 6, 22], [2012, 7, 20], [2012, 6, 22], 0.0675, 1], 0.0], ['normal control 3', [[2000, 6, 21], [2001, 1, 22], [2000, 12, 7], 0.02, 12], 0.923497]], [['regression coupon per quasi period 1', [[2003, 9, 19], [2003, 9, 30], [2003, 9, 22], 0.03, 1], 0.024194], ['regression coupon per quasi period 2', [[2014, 12, 1], [2014, 12, 28], [2014, 12, 27], 0.03, 1], 0.216667], ['partial repair probe 1', [[2034, 4, 21], [2035, 9, 1], [2035, 6, 28], 0.05, 12], 5.931507], ['partial repair probe 2', [[2007, 7, 11], [2008, 11, 28], [2008, 1, 9], 0.0675, 12], 3.363631], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2001, 12, 2], [2003, 4, 13], [2001, 12, 2], 0.05, 12], 0.0], ['normal control 2', [[2012, 10, 11], [2014, 5, 30], [2012, 10, 8], 0.05, 12], 'settlement outside first period'], ['normal control 3', [[2009, 2, 26], [2009, 11, 12], [2009, 2, 26], 0.05, 3], 0.0]], [['regression coupon per quasi period 1', [[2029, 8, 10], [2029, 9, 30], [2029, 9, 30], 0.0675, 1], 0.925403], ['regression coupon per quasi period 2', [[2014, 9, 3], [2014, 11, 30], [2014, 9, 15], 0.045, 1], 0.145161], ['partial repair probe 1', [[2003, 6, 28], [2006, 2, 11], [2005, 1, 15], 0.0675, 12], 10.468488], ['partial repair probe 2', [[2014, 1, 8], [2016, 8, 1], [2014, 9, 23], 0.0675, 12], 4.771233], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2020, 3, 5], [2021, 2, 28], [2020, 6, 30], 0.03, 12], 0.959016], ['normal control 2', [[2007, 2, 26], [2007, 12, 16], [2007, 2, 23], 0.05, 12], 'settlement outside first period'], ['normal control 3', [[2003, 4, 30], [2003, 7, 31], [2003, 5, 22], 0.05, 12], 0.30137]], [['regression coupon per quasi period 1', [[2034, 6, 17], [2034, 7, 16], [2034, 6, 27], 0.045, 1], 0.125], ['regression coupon per quasi period 2', [[2010, 7, 5], [2010, 8, 1], [2010, 7, 14], 0.03, 6], 0.074586], ['partial repair probe 1', [[2032, 8, 31], [2034, 4, 30], [2032, 12, 30], 0.03, 12], 0.994521], ['partial repair probe 2', [[2026, 2, 25], [2027, 4, 30], [2027, 2, 11], 0.045, 12], 4.327397], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2029, 1, 21], [2029, 5, 29], [2029, 1, 21], 0.02, 6], 0.0], ['normal control 2', [[2019, 5, 3], [2019, 7, 29], [2019, 4, 30], 0.08, 3], 'settlement outside first period'], ['normal control 3', [[2001, 12, 9], [2002, 5, 1], [2001, 12, 6], 0.08, 6], 'settlement outside first period']]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(issue, first, settle, rate, months):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    I = datetime.date(*issue)
    Fc = datetime.date(*first)
    S = datetime.date(*settle)
    if not (I <= S <= Fc):
        return 'settlement outside first period'
    freq = 12 // months
    def back(k):
        t = Fc.year * 12 + Fc.month - 1 - k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(Fc.day, mlen(y, m)))
    q = [Fc]
    k = 1
    while q[-1] > I:
        q.append(back(k))
        k += 1
    frac = Fraction(0)
    for j in range(len(q) - 1):
        end, start = q[j], q[j + 1]
        lo = max(start, I)
        hi = min(end, S)
        if hi > lo:
            frac += Fraction((hi - lo).days, (end - start).days)
    return round(float(100 * Fraction(str(rate)) / (len(q) - 1) * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression coupon per quasi period 1', [[2005, 9, 29], [2005, 10, 31], [2005, 9, 30], 0.02, 3], 0.005435], ['regression coupon per quasi period 2', [[2041, 9, 29], [2042, 3, 31], [2041, 10, 18], 0.05, 6], 0.260914], ['partial repair probe 1', [[2030, 8, 6], [2031, 11, 1], [2031, 4, 19], 0.0675, 12], 4.734247], ['partial repair probe 2', [[2031, 8, 7], [2033, 2, 28], [2031, 10, 22], 0.02, 12], 0.416438], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2035, 2, 3], [2035, 5, 4], [2035, 2, 3], 0.045, 3], 0.0], ['normal control 2', [[2019, 11, 10], [2020, 3, 3], [2019, 11, 7], 0.045, 6], 'settlement outside first period'], ['normal control 3', [[2007, 12, 27], [2008, 1, 1], [2007, 12, 27], 0.05, 1], 0.0]], [['regression coupon per quasi period 1', [[2040, 8, 29], [2040, 9, 6], [2040, 8, 31], 0.03, 3], 0.016304], ['regression coupon per quasi period 2', [[2030, 7, 25], [2030, 9, 15], [2030, 9, 15], 0.05, 3], 0.706522], ['partial repair probe 1', [[2015, 7, 5], [2018, 1, 31], [2017, 9, 10], 0.02, 12], 4.367123], ['partial repair probe 2', [[2023, 11, 5], [2025, 4, 30], [2025, 4, 30], 0.03, 12], 4.45082], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2038, 1, 19], [2038, 3, 31], [2038, 1, 19], 0.03, 6], 0.0], ['normal control 2', [[2012, 6, 22], [2012, 7, 20], [2012, 6, 22], 0.0675, 1], 0.0], ['normal control 3', [[2000, 6, 21], [2001, 1, 22], [2000, 12, 7], 0.02, 12], 0.923497]], [['regression coupon per quasi period 1', [[2003, 9, 19], [2003, 9, 30], [2003, 9, 22], 0.03, 1], 0.024194], ['regression coupon per quasi period 2', [[2014, 12, 1], [2014, 12, 28], [2014, 12, 27], 0.03, 1], 0.216667], ['partial repair probe 1', [[2034, 4, 21], [2035, 9, 1], [2035, 6, 28], 0.05, 12], 5.931507], ['partial repair probe 2', [[2007, 7, 11], [2008, 11, 28], [2008, 1, 9], 0.0675, 12], 3.363631], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2001, 12, 2], [2003, 4, 13], [2001, 12, 2], 0.05, 12], 0.0], ['normal control 2', [[2012, 10, 11], [2014, 5, 30], [2012, 10, 8], 0.05, 12], 'settlement outside first period'], ['normal control 3', [[2009, 2, 26], [2009, 11, 12], [2009, 2, 26], 0.05, 3], 0.0]], [['regression coupon per quasi period 1', [[2029, 8, 10], [2029, 9, 30], [2029, 9, 30], 0.0675, 1], 0.925403], ['regression coupon per quasi period 2', [[2014, 9, 3], [2014, 11, 30], [2014, 9, 15], 0.045, 1], 0.145161], ['partial repair probe 1', [[2003, 6, 28], [2006, 2, 11], [2005, 1, 15], 0.0675, 12], 10.468488], ['partial repair probe 2', [[2014, 1, 8], [2016, 8, 1], [2014, 9, 23], 0.0675, 12], 4.771233], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2020, 3, 5], [2021, 2, 28], [2020, 6, 30], 0.03, 12], 0.959016], ['normal control 2', [[2007, 2, 26], [2007, 12, 16], [2007, 2, 23], 0.05, 12], 'settlement outside first period'], ['normal control 3', [[2003, 4, 30], [2003, 7, 31], [2003, 5, 22], 0.05, 12], 0.30137]], [['regression coupon per quasi period 1', [[2034, 6, 17], [2034, 7, 16], [2034, 6, 27], 0.045, 1], 0.125], ['regression coupon per quasi period 2', [[2010, 7, 5], [2010, 8, 1], [2010, 7, 14], 0.03, 6], 0.074586], ['partial repair probe 1', [[2032, 8, 31], [2034, 4, 30], [2032, 12, 30], 0.03, 12], 0.994521], ['partial repair probe 2', [[2026, 2, 25], [2027, 4, 30], [2027, 2, 11], 0.045, 12], 4.327397], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2029, 1, 21], [2029, 5, 29], [2029, 1, 21], 0.02, 6], 0.0], ['normal control 2', [[2019, 5, 3], [2019, 7, 29], [2019, 4, 30], 0.08, 3], 'settlement outside first period'], ['normal control 3', [[2001, 12, 9], [2002, 5, 1], [2001, 12, 6], 0.08, 6], 'settlement outside first period']]]
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)

prompt:
Accrued interest is freq times too large.

Inputs issue, first coupon and settlement [y,m,d], annual rate and months per period. Settlement must lie in [issue, first] else return "settlement outside first period". Quasi-coupon dates are generated back from the first coupon in steps of months (day clamped to month length) until one is on or before issue. For each quasi period [start, end), accrued days are those in [max(start, issue), min(end, settle)) and are divided by that quasi period length. Accrued = 100*rate/freq*sum, rounded to 6 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(issue, first, settle, rate, months):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    I = datetime.date(*issue)
    Fc = datetime.date(*first)
    S = datetime.date(*settle)
    if not (I <= S <= Fc):
        return 'settlement outside first period'
    freq = 12 // months
    def back(k):
        t = Fc.year * 12 + Fc.month - 1 - k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(Fc.day, mlen(y, m)))
    q = [Fc]
    k = 1
    while q[-1] > I:
        q.append(back(k))
        k += 1
    frac = Fraction(0)
    for j in range(len(q) - 1):
        end, start = q[j], q[j + 1]
        lo = max(start, I)
        hi = min(end, S)
        if hi > lo:
            frac += Fraction((hi - lo).days, (Fc - q[1]).days)
    return round(float(100 * Fraction(str(rate)) / freq * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression quasi period length 1', [[2023, 6, 29], [2024, 2, 29], [2023, 11, 21], 0.03, 6], 1.18753], ['regression quasi period length 2', [[2011, 7, 11], [2012, 11, 30], [2012, 2, 10], 0.0675, 12], 3.953896], ['partial repair probe 1', [[2033, 12, 28], [2034, 1, 30], [2034, 1, 27], 0.0675, 3], 0.550272], ['partial repair probe 2', [[2030, 10, 2], [2030, 10, 30], [2030, 10, 15], 0.08, 6], 0.284153], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2039, 9, 21], [2039, 10, 14], [2039, 9, 21], 0.02, 1], 0.0], ['normal control 2', [[2000, 8, 4], [2001, 7, 12], [2000, 8, 4], 0.03, 6], 0.0], ['normal control 3', [[2000, 11, 4], [2001, 4, 30], [2000, 11, 1], 0.03, 3], 'settlement outside first period']], [['regression quasi period length 1', [[2002, 5, 28], [2003, 8, 22], [2003, 6, 19], 0.0675, 6], 7.160221], ['regression quasi period length 2', [[2010, 9, 29], [2010, 11, 30], [2010, 10, 30], 0.045, 1], 0.387097], ['partial repair probe 1', [[2015, 8, 19], [2015, 9, 30], [2015, 9, 28], 0.045, 12], 0.493151], ['partial repair probe 2', [[2042, 11, 10], [2043, 2, 18], [2042, 11, 30], 0.03, 6], 0.163043], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2040, 2, 3], [2040, 2, 24], [2040, 2, 3], 0.05, 3], 0.0], ['normal control 2', [[2015, 3, 1], [2015, 6, 30], [2015, 3, 1], 0.02, 3], 0.0], ['normal control 3', [[2006, 1, 23], [2006, 1, 31], [2006, 1, 23], 0.02, 3], 0.0]], [['regression quasi period length 1', [[2035, 3, 6], [2035, 8, 30], [2035, 8, 26], 0.0675, 3], 3.190367], ['regression quasi period length 2', [[2008, 5, 29], [2008, 7, 29], [2008, 6, 2], 0.08, 1], 0.086022], ['partial repair probe 1', [[2008, 8, 6], [2008, 9, 3], [2008, 8, 7], 0.0675, 1], 0.018145], ['partial repair probe 2', [[2003, 5, 22], [2003, 6, 30], [2003, 6, 6], 0.03, 3], 0.122283], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2036, 3, 22], [2036, 6, 30], [2036, 3, 19], 0.05, 6], 'settlement outside first period'], ['normal control 2', [[2020, 3, 26], [2020, 9, 14], [2020, 3, 23], 0.05, 6], 'settlement outside first period'], ['normal control 3', [[2027, 2, 9], [2028, 8, 31], [2027, 2, 6], 0.08, 6], 'settlement outside first period']], [['regression quasi period length 1', [[2018, 9, 4], [2018, 10, 31], [2018, 9, 18], 0.03, 1], 0.116667], ['regression quasi period length 2', [[2022, 8, 27], [2023, 4, 29], [2023, 3, 1], 0.03, 6], 1.53013], ['partial repair probe 1', [[2032, 4, 24], [2032, 5, 7], [2032, 5, 1], 0.045, 3], 0.0875], ['partial repair probe 2', [[2004, 3, 2], [2004, 7, 13], [2004, 4, 27], 0.0675, 3], 1.038462], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2026, 11, 19], [2027, 5, 1], [2026, 11, 16], 0.0675, 6], 'settlement outside first period'], ['normal control 2', [[2006, 4, 26], [2006, 5, 30], [2006, 4, 26], 0.045, 3], 0.0], ['normal control 3', [[2010, 6, 26], [2010, 9, 30], [2010, 6, 23], 0.045, 1], 'settlement outside first period']], [['regression quasi period length 1', [[2040, 3, 19], [2040, 9, 24], [2040, 5, 13], 0.02, 3], 0.299212], ['regression quasi period length 2', [[2044, 3, 15], [2045, 3, 1], [2044, 9, 15], 0.02, 6], 1.001261], ['partial repair probe 1', [[2023, 12, 3], [2024, 1, 17], [2024, 1, 17], 0.045, 6], 0.550272], ['partial repair probe 2', [[2044, 5, 5], [2044, 7, 14], [2044, 5, 22], 0.02, 3], 0.093407], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2029, 3, 18], [2029, 4, 9], [2029, 3, 15], 0.08, 1], 'settlement outside first period'], ['normal control 2', [[2015, 6, 22], [2015, 8, 22], [2015, 6, 22], 0.02, 3], 0.0], ['normal control 3', [[2005, 6, 4], [2006, 1, 31], [2005, 6, 4], 0.03, 12], 0.0]]]
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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(issue, first, settle, rate, months):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    I = datetime.date(*issue)
    Fc = datetime.date(*first)
    S = datetime.date(*settle)
    if not (I <= S <= Fc):
        return 'settlement outside first period'
    freq = 12 // months
    def back(k):
        t = Fc.year * 12 + Fc.month - 1 - k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(Fc.day, mlen(y, m)))
    q = [Fc]
    k = 1
    while q[-1] > I:
        q.append(back(k))
        k += 1
    frac = Fraction(0)
    for j in range(len(q) - 1):
        end, start = q[j], q[j + 1]
        lo = max(start, I)
        hi = min(end, S)
        if hi > lo:
            frac += Fraction((hi - lo).days, (end - start).days + 1)
    return round(float(100 * Fraction(str(rate)) / freq * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression quasi period length 1', [[2023, 6, 29], [2024, 2, 29], [2023, 11, 21], 0.03, 6], 1.18753], ['regression quasi period length 2', [[2011, 7, 11], [2012, 11, 30], [2012, 2, 10], 0.0675, 12], 3.953896], ['partial repair probe 1', [[2033, 12, 28], [2034, 1, 30], [2034, 1, 27], 0.0675, 3], 0.550272], ['partial repair probe 2', [[2030, 10, 2], [2030, 10, 30], [2030, 10, 15], 0.08, 6], 0.284153], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2039, 9, 21], [2039, 10, 14], [2039, 9, 21], 0.02, 1], 0.0], ['normal control 2', [[2000, 8, 4], [2001, 7, 12], [2000, 8, 4], 0.03, 6], 0.0], ['normal control 3', [[2000, 11, 4], [2001, 4, 30], [2000, 11, 1], 0.03, 3], 'settlement outside first period']], [['regression quasi period length 1', [[2002, 5, 28], [2003, 8, 22], [2003, 6, 19], 0.0675, 6], 7.160221], ['regression quasi period length 2', [[2010, 9, 29], [2010, 11, 30], [2010, 10, 30], 0.045, 1], 0.387097], ['partial repair probe 1', [[2015, 8, 19], [2015, 9, 30], [2015, 9, 28], 0.045, 12], 0.493151], ['partial repair probe 2', [[2042, 11, 10], [2043, 2, 18], [2042, 11, 30], 0.03, 6], 0.163043], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2040, 2, 3], [2040, 2, 24], [2040, 2, 3], 0.05, 3], 0.0], ['normal control 2', [[2015, 3, 1], [2015, 6, 30], [2015, 3, 1], 0.02, 3], 0.0], ['normal control 3', [[2006, 1, 23], [2006, 1, 31], [2006, 1, 23], 0.02, 3], 0.0]], [['regression quasi period length 1', [[2035, 3, 6], [2035, 8, 30], [2035, 8, 26], 0.0675, 3], 3.190367], ['regression quasi period length 2', [[2008, 5, 29], [2008, 7, 29], [2008, 6, 2], 0.08, 1], 0.086022], ['partial repair probe 1', [[2008, 8, 6], [2008, 9, 3], [2008, 8, 7], 0.0675, 1], 0.018145], ['partial repair probe 2', [[2003, 5, 22], [2003, 6, 30], [2003, 6, 6], 0.03, 3], 0.122283], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2036, 3, 22], [2036, 6, 30], [2036, 3, 19], 0.05, 6], 'settlement outside first period'], ['normal control 2', [[2020, 3, 26], [2020, 9, 14], [2020, 3, 23], 0.05, 6], 'settlement outside first period'], ['normal control 3', [[2027, 2, 9], [2028, 8, 31], [2027, 2, 6], 0.08, 6], 'settlement outside first period']], [['regression quasi period length 1', [[2018, 9, 4], [2018, 10, 31], [2018, 9, 18], 0.03, 1], 0.116667], ['regression quasi period length 2', [[2022, 8, 27], [2023, 4, 29], [2023, 3, 1], 0.03, 6], 1.53013], ['partial repair probe 1', [[2032, 4, 24], [2032, 5, 7], [2032, 5, 1], 0.045, 3], 0.0875], ['partial repair probe 2', [[2004, 3, 2], [2004, 7, 13], [2004, 4, 27], 0.0675, 3], 1.038462], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2026, 11, 19], [2027, 5, 1], [2026, 11, 16], 0.0675, 6], 'settlement outside first period'], ['normal control 2', [[2006, 4, 26], [2006, 5, 30], [2006, 4, 26], 0.045, 3], 0.0], ['normal control 3', [[2010, 6, 26], [2010, 9, 30], [2010, 6, 23], 0.045, 1], 'settlement outside first period']], [['regression quasi period length 1', [[2040, 3, 19], [2040, 9, 24], [2040, 5, 13], 0.02, 3], 0.299212], ['regression quasi period length 2', [[2044, 3, 15], [2045, 3, 1], [2044, 9, 15], 0.02, 6], 1.001261], ['partial repair probe 1', [[2023, 12, 3], [2024, 1, 17], [2024, 1, 17], 0.045, 6], 0.550272], ['partial repair probe 2', [[2044, 5, 5], [2044, 7, 14], [2044, 5, 22], 0.02, 3], 0.093407], ['boundary control 1', [[2024, 1, 10], [2024, 9, 15], [2024, 9, 16], 0.05, 6], 'settlement outside first period'], ['normal control 1', [[2029, 3, 18], [2029, 4, 9], [2029, 3, 15], 0.08, 1], 'settlement outside first period'], ['normal control 2', [[2015, 6, 22], [2015, 8, 22], [2015, 6, 22], 0.02, 3], 0.0], ['normal control 3', [[2005, 6, 4], [2006, 1, 31], [2005, 6, 4], 0.03, 12], 0.0]]]
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)

prompt:
Accruals drift when earlier quasi periods have a different number of days.

Inputs issue, first coupon and settlement [y,m,d], annual rate and months per period. Settlement must lie in [issue, first] else return "settlement outside first period". Quasi-coupon dates are generated back from the first coupon in steps of months (day clamped to month length) until one is on or before issue. For each quasi period [start, end), accrued days are those in [max(start, issue), min(end, settle)) and are divided by that quasi period length. Accrued = 100*rate/freq*sum, rounded to 6 decimals.

split: open-access


prompt:
Prices are discounted for the part of the period that has already elapsed.

Inputs settle, prev and next coupon dates [y,m,d], n remaining coupons (including next), annual coupon rate, annual yield y and frequency. w = days(settle, next)/days(prev, next); c = 100*rate/freq; v = 1/(1+y/freq). Dirty = sum_{k=0}^{n-1} c*v^(k+w) + 100*v^(n-1+w); accrued = c*(1-w); return [dirty, dirty-accrued] each rounded to 6 decimals.

split: open-access


prompt:
Dirty prices ignore the partial first period and jump at each coupon date.

Inputs settle, prev and next coupon dates [y,m,d], n remaining coupons (including next), annual coupon rate, annual yield y and frequency. w = days(settle, next)/days(prev, next); c = 100*rate/freq; v = 1/(1+y/freq). Dirty = sum_{k=0}^{n-1} c*v^(k+w) + 100*v^(n-1+w); accrued = c*(1-w); return [dirty, dirty-accrued] each rounded to 6 decimals.

split: open-access


prompt:
Prices are too low by roughly one period of discounting on the redemption amount.

Inputs settle, prev and next coupon dates [y,m,d], n remaining coupons (including next), annual coupon rate, annual yield y and frequency. w = days(settle, next)/days(prev, next); c = 100*rate/freq; v = 1/(1+y/freq). Dirty = sum_{k=0}^{n-1} c*v^(k+w) + 100*v^(n-1+w); accrued = c*(1-w); return [dirty, dirty-accrued] each rounded to 6 decimals.

split: open-access


prompt:
Clean prices move the wrong way through the coupon period.

Inputs settle, prev and next coupon dates [y,m,d], n remaining coupons (including next), annual coupon rate, annual yield y and frequency. w = days(settle, next)/days(prev, next); c = 100*rate/freq; v = 1/(1+y/freq). Dirty = sum_{k=0}^{n-1} c*v^(k+w) + 100*v^(n-1+w); accrued = c*(1-w); return [dirty, dirty-accrued] each rounded to 6 decimals.

split: open-access


prompt:
Semi-annual and quarterly bonds are discounted at the full annual yield per period.

Inputs settle, prev and next coupon dates [y,m,d], n remaining coupons (including next), annual coupon rate, annual yield y and frequency. w = days(settle, next)/days(prev, next); c = 100*rate/freq; v = 1/(1+y/freq). Dirty = sum_{k=0}^{n-1} c*v^(k+w) + 100*v^(n-1+w); accrued = c*(1-w); return [dirty, dirty-accrued] each rounded to 6 decimals.

split: open-access


prompt:
Bill prices are too high and yields derived from them too low.

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].

split: open-access


prompt:
Bills just over half a 365-day year report a yield from the simple formula.

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].

split: open-access


prompt:
Bills settling late in a leap year after 29 February, or before a coming leap day, get the wrong basis.

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].

split: open-access


prompt:
Bond-equivalent yields for short bills are understated.

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].

split: open-access


prompt:
Long-dated bills report a negative bond-equivalent yield.

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].

split: open-access


prompt:
Reference CPI on the first of a month is not equal to the lagged monthly index.

Inputs a date [y,m,d], a map "YYYY-MM" to CPI level and a base index. RefCPI = CPI(m-3) + (d-1)/days_in_month(m) * (CPI(m-2) - CPI(m-3)), computed in Decimal and rounded half-up to 5 decimals; the index ratio is RefCPI/base rounded half-up to 5 decimals. Return both as strings.

split: open-access


prompt:
The reference index is one month too recent.

Inputs a date [y,m,d], a map "YYYY-MM" to CPI level and a base index. RefCPI = CPI(m-3) + (d-1)/days_in_month(m) * (CPI(m-2) - CPI(m-3)), computed in Decimal and rounded half-up to 5 decimals; the index ratio is RefCPI/base rounded half-up to 5 decimals. Return both as strings.

split: open-access


prompt:
Interpolation weights are wrong in months whose length differs from the prior month.

Inputs a date [y,m,d], a map "YYYY-MM" to CPI level and a base index. RefCPI = CPI(m-3) + (d-1)/days_in_month(m) * (CPI(m-2) - CPI(m-3)), computed in Decimal and rounded half-up to 5 decimals; the index ratio is RefCPI/base rounded half-up to 5 decimals. Return both as strings.

split: open-access


prompt:
Reference indexes and the ratios computed from them are low by up to one unit in the fifth decimal.

Inputs a date [y,m,d], a map "YYYY-MM" to CPI level and a base index. RefCPI = CPI(m-3) + (d-1)/days_in_month(m) * (CPI(m-2) - CPI(m-3)), computed in Decimal and rounded half-up to 5 decimals; the index ratio is RefCPI/base rounded half-up to 5 decimals. Return both as strings.

split: open-access


prompt:
Periods starting on a Friday and ending on a Monday count the wrong business day.

Inputs start and end [y,m,d], a holiday list (may contain weekend dates and duplicates) and an annual rate in percent. bd counts weekdays in [start, end) that are not holidays. Factor = (1 + rate/100)^(bd/252). Return [bd, factor rounded to 8 decimals].

split: open-access


prompt:
Holidays on weekends and duplicated holiday entries remove business days twice.

Inputs start and end [y,m,d], a holiday list (may contain weekend dates and duplicates) and an annual rate in percent. bd counts weekdays in [start, end) that are not holidays. Factor = (1 + rate/100)^(bd/252). Return [bd, factor rounded to 8 decimals].

split: open-access


prompt:
Accrual factors disagree with the business-day basis on every span containing weekends.

Inputs start and end [y,m,d], a holiday list (may contain weekend dates and duplicates) and an annual rate in percent. bd counts weekdays in [start, end) that are not holidays. Factor = (1 + rate/100)^(bd/252). Return [bd, factor rounded to 8 decimals].

split: open-access


prompt:
Accrual factors are understated for long spans at high rates.

Inputs start and end [y,m,d], a holiday list (may contain weekend dates and duplicates) and an annual rate in percent. bd counts weekdays in [start, end) that are not holidays. Factor = (1 + rate/100)^(bd/252). Return [bd, factor rounded to 8 decimals].

split: open-access


prompt:
Accrual on a step date uses the old rate.

Inputs prev and next coupon dates, settlement in [prev, next], a list of [date, rate] steps (unordered; a step applies on and after its date), the base rate before any step, and frequency. Each accrued day d in [prev, settle) earns the rate in force on d. Accrued = 100/freq * sum(rates)/days(prev, next), rounded to 6.

split: open-access


prompt:
Accrued interest after a step-up charges the new rate for days before the step.

Inputs prev and next coupon dates, settlement in [prev, next], a list of [date, rate] steps (unordered; a step applies on and after its date), the base rate before any step, and frequency. Each accrued day d in [prev, settle) earns the rate in force on d. Accrued = 100/freq * sum(rates)/days(prev, next), rounded to 6.

split: open-access


prompt:
An unsorted step list lets an earlier step override a later one.

Inputs prev and next coupon dates, settlement in [prev, next], a list of [date, rate] steps (unordered; a step applies on and after its date), the base rate before any step, and frequency. Each accrued day d in [prev, settle) earns the rate in force on d. Accrued = 100/freq * sum(rates)/days(prev, next), rounded to 6.

split: open-access


prompt:
Accrued interest is one day of coupon too high.

Inputs prev and next coupon dates, settlement in [prev, next], a list of [date, rate] steps (unordered; a step applies on and after its date), the base rate before any step, and frequency. Each accrued day d in [prev, settle) earns the rate in force on d. Accrued = 100/freq * sum(rates)/days(prev, next), rounded to 6.

split: open-access


prompt:
Accrued interest near the end of a 184-day period exceeds the half-year coupon.

Inputs prev and next coupon dates, settlement in [prev, next) and annual rate (semi-annual coupons). c = 100*rate, days = days(prev, settle). If days >= 183 accrued = c/2 - c*days(settle, next)/365, else accrued = c*days/365. Round to 6 decimals.

split: open-access


prompt:
Settlements exactly 183 days into the period use the wrong formula.

Inputs prev and next coupon dates, settlement in [prev, next) and annual rate (semi-annual coupons). c = 100*rate, days = days(prev, settle). If days >= 183 accrued = c/2 - c*days(settle, next)/365, else accrued = c*days/365. Round to 6 decimals.

split: open-access


prompt:
Accrued interest follows an actual/actual pattern instead of the 365-day basis.

Inputs prev and next coupon dates, settlement in [prev, next) and annual rate (semi-annual coupons). c = 100*rate, days = days(prev, settle). If days >= 183 accrued = c/2 - c*days(settle, next)/365, else accrued = c*days/365. Round to 6 decimals.

split: open-access


prompt:
Trades before weekends and holidays settle too early.

Inputs a trade date (a business day), a lag n and two holiday lists. A business day is a weekday that is a holiday in neither calendar. Settlement is the n-th business day strictly after trade (trade date for n=0). Return [y,m,d].

split: open-access


prompt:
Settlements land on currency holidays.

Inputs a trade date (a business day), a lag n and two holiday lists. A business day is a weekday that is a holiday in neither calendar. Settlement is the n-th business day strictly after trade (trade date for n=0). Return [y,m,d].

split: open-access


prompt:
Settlement is one business day early.

Inputs a trade date (a business day), a lag n and two holiday lists. A business day is a weekday that is a holiday in neither calendar. Settlement is the n-th business day strictly after trade (trade date for n=0). Return [y,m,d].

split: open-access


prompt:
Bonds with a short last period overpay the final coupon.

Inputs the last regular coupon date prev, maturity (prev < maturity <= prev + 2 periods), months per period and annual rate. Quasi dates are prev shifted forward k*months with the prev day clamped to month length. c = 100*rate/freq. Short final period (maturity <= q1): c*days(prev,mat)/days(prev,q1). Long final period: c*(1 + days(q1,mat)/days(q1,q2)). Round to 6 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(prev, maturity, months, rate):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    P = datetime.date(*prev)
    M = datetime.date(*maturity)
    freq = 12 // months
    def fwd(k):
        t = P.year * 12 + P.month - 1 + k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(P.day, mlen(y, m)))
    c = 100 * Fraction(str(rate)) / freq
    q1 = fwd(1)
    if M <= q1:
        frac = Fraction((M - P).days, (q1 - P).days)
    else:
        q2 = fwd(2)
        frac = 1 + Fraction((M - q1).days, (q1 - P).days)
    return round(float(c * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression long stub extension denominator 1', [[2015, 5, 30], [2017, 1, 1], 12, 0.05], 7.958904], ['regression long stub extension denominator 2', [[2017, 7, 31], [2017, 9, 30], 1, 0.045], 0.75], ['partial repair probe 1', [[2033, 2, 28], [2034, 11, 6], 12, 0.03], 5.063014], ['partial repair probe 2', [[2017, 11, 30], [2019, 10, 26], 12, 0.045], 8.568493], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2042, 3, 31], [2042, 7, 7], 6, 0.0725], 1.941257], ['normal control 2', [[2014, 4, 7], [2014, 10, 7], 6, 0.045], 2.25]], [['regression long stub extension denominator 1', [[2016, 10, 30], [2017, 8, 24], 6, 0.045], 3.67623], ['regression long stub extension denominator 2', [[2045, 9, 30], [2046, 9, 30], 6, 0.05], 5.0], ['partial repair probe 1', [[2023, 9, 30], [2024, 3, 27], 3, 0.045], 2.212912], ['partial repair probe 2', [[2034, 7, 4], [2034, 10, 5], 3, 0.045], 1.137228], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2013, 4, 3], [2013, 11, 23], 12, 0.03], 1.923288], ['normal control 2', [[2018, 6, 30], [2018, 9, 30], 3, 0.05], 1.25]], [['regression long stub extension denominator 1', [[2019, 2, 28], [2019, 8, 29], 6, 0.05], 2.513587], ['regression long stub extension denominator 2', [[2017, 12, 1], [2018, 3, 30], 3, 0.03], 0.986413], ['partial repair probe 1', [[2039, 6, 30], [2040, 3, 13], 6, 0.05], 3.510929], ['partial repair probe 2', [[2013, 10, 29], [2014, 12, 28], 12, 0.03], 3.493151], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2026, 7, 31], [2026, 8, 27], 1, 0.0725], 0.52621], ['normal control 2', [[2018, 7, 21], [2018, 8, 3], 6, 0.03], 0.105978]], [['regression long stub extension denominator 1', [[2020, 9, 7], [2021, 7, 20], 6, 0.0725], 6.284647], ['regression long stub extension denominator 2', [[2034, 11, 18], [2035, 11, 10], 6, 0.03], 2.934783], ['partial repair probe 1', [[2005, 6, 30], [2007, 6, 30], 12, 0.045], 9.0], ['partial repair probe 2', [[2037, 5, 26], [2038, 8, 20], 12, 0.03], 3.706849], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2014, 4, 29], [2014, 5, 3], 1, 0.0725], 0.080556], ['normal control 2', [[2006, 1, 11], [2006, 7, 11], 6, 0.03], 1.5]], [['regression long stub extension denominator 1', [[2009, 2, 28], [2009, 4, 5], 1, 0.05], 0.524194], ['regression long stub extension denominator 2', [[2005, 11, 30], [2006, 1, 5], 1, 0.03], 0.298387], ['partial repair probe 1', [[2023, 4, 28], [2024, 1, 14], 6, 0.05], 3.565574], ['partial repair probe 2', [[2023, 6, 20], [2024, 6, 20], 6, 0.045], 4.5], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2042, 12, 1], [2043, 3, 10], 12, 0.03], 0.813699], ['normal control 2', [[2030, 6, 29], [2030, 8, 27], 3, 0.03], 0.480978]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(prev, maturity, months, rate):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    P = datetime.date(*prev)
    M = datetime.date(*maturity)
    freq = 12 // months
    def fwd(k):
        t = P.year * 12 + P.month - 1 + k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(P.day, mlen(y, m)))
    c = 100 * Fraction(str(rate)) / freq
    q1 = fwd(1)
    if M <= q1:
        frac = Fraction((M - P).days, (q1 - P).days)
    else:
        q2 = fwd(2)
        frac = 1 + Fraction((M - q1).days, (M - P).days)
    return round(float(c * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression long stub extension denominator 1', [[2015, 5, 30], [2017, 1, 1], 12, 0.05], 7.958904], ['regression long stub extension denominator 2', [[2017, 7, 31], [2017, 9, 30], 1, 0.045], 0.75], ['partial repair probe 1', [[2033, 2, 28], [2034, 11, 6], 12, 0.03], 5.063014], ['partial repair probe 2', [[2017, 11, 30], [2019, 10, 26], 12, 0.045], 8.568493], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2042, 3, 31], [2042, 7, 7], 6, 0.0725], 1.941257], ['normal control 2', [[2014, 4, 7], [2014, 10, 7], 6, 0.045], 2.25]], [['regression long stub extension denominator 1', [[2016, 10, 30], [2017, 8, 24], 6, 0.045], 3.67623], ['regression long stub extension denominator 2', [[2045, 9, 30], [2046, 9, 30], 6, 0.05], 5.0], ['partial repair probe 1', [[2023, 9, 30], [2024, 3, 27], 3, 0.045], 2.212912], ['partial repair probe 2', [[2034, 7, 4], [2034, 10, 5], 3, 0.045], 1.137228], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2013, 4, 3], [2013, 11, 23], 12, 0.03], 1.923288], ['normal control 2', [[2018, 6, 30], [2018, 9, 30], 3, 0.05], 1.25]], [['regression long stub extension denominator 1', [[2019, 2, 28], [2019, 8, 29], 6, 0.05], 2.513587], ['regression long stub extension denominator 2', [[2017, 12, 1], [2018, 3, 30], 3, 0.03], 0.986413], ['partial repair probe 1', [[2039, 6, 30], [2040, 3, 13], 6, 0.05], 3.510929], ['partial repair probe 2', [[2013, 10, 29], [2014, 12, 28], 12, 0.03], 3.493151], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2026, 7, 31], [2026, 8, 27], 1, 0.0725], 0.52621], ['normal control 2', [[2018, 7, 21], [2018, 8, 3], 6, 0.03], 0.105978]], [['regression long stub extension denominator 1', [[2020, 9, 7], [2021, 7, 20], 6, 0.0725], 6.284647], ['regression long stub extension denominator 2', [[2034, 11, 18], [2035, 11, 10], 6, 0.03], 2.934783], ['partial repair probe 1', [[2005, 6, 30], [2007, 6, 30], 12, 0.045], 9.0], ['partial repair probe 2', [[2037, 5, 26], [2038, 8, 20], 12, 0.03], 3.706849], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2014, 4, 29], [2014, 5, 3], 1, 0.0725], 0.080556], ['normal control 2', [[2006, 1, 11], [2006, 7, 11], 6, 0.03], 1.5]], [['regression long stub extension denominator 1', [[2009, 2, 28], [2009, 4, 5], 1, 0.05], 0.524194], ['regression long stub extension denominator 2', [[2005, 11, 30], [2006, 1, 5], 1, 0.03], 0.298387], ['partial repair probe 1', [[2023, 4, 28], [2024, 1, 14], 6, 0.05], 3.565574], ['partial repair probe 2', [[2023, 6, 20], [2024, 6, 20], 6, 0.045], 4.5], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2042, 12, 1], [2043, 3, 10], 12, 0.03], 0.813699], ['normal control 2', [[2030, 6, 29], [2030, 8, 27], 3, 0.03], 0.480978]]]
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)

prompt:
Long final coupons are misstated when consecutive notional periods have different lengths.

Inputs the last regular coupon date prev, maturity (prev < maturity <= prev + 2 periods), months per period and annual rate. Quasi dates are prev shifted forward k*months with the prev day clamped to month length. c = 100*rate/freq. Short final period (maturity <= q1): c*days(prev,mat)/days(prev,q1). Long final period: c*(1 + days(q1,mat)/days(q1,q2)). Round to 6 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(prev, maturity, months, rate):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    P = datetime.date(*prev)
    M = datetime.date(*maturity)
    freq = 12 // months
    def fwd(k):
        t = P.year * 12 + P.month - 1 + k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(P.day, mlen(y, m)))
    c = 100 * Fraction(str(rate)) / freq
    q1 = fwd(1)
    if M <= q1:
        frac = Fraction((M - P).days, (q1 - P).days)
    else:
        q2 = fwd(2)
        frac = Fraction((M - P).days, (q1 - P).days)
    return round(float(c * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression long stub single fraction 1', [[2035, 6, 25], [2037, 5, 16], 12, 0.05], 9.452055], ['regression long stub single fraction 2', [[2013, 7, 11], [2014, 5, 2], 6, 0.045], 3.629834], ['partial repair probe 1', [[2005, 2, 20], [2006, 2, 13], 6, 0.05], 4.904891], ['partial repair probe 2', [[2040, 1, 21], [2040, 2, 28], 1, 0.05], 0.517241], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2008, 9, 30], [2008, 12, 30], 3, 0.0725], 1.8125], ['normal control 2', [[2025, 9, 27], [2025, 10, 9], 3, 0.03], 0.098901]], [['regression long stub single fraction 1', [[2038, 10, 31], [2039, 10, 28], 6, 0.05], 4.959239], ['regression long stub single fraction 2', [[2025, 11, 30], [2026, 1, 20], 1, 0.045], 0.629032], ['partial repair probe 1', [[2041, 2, 27], [2041, 6, 6], 3, 0.045], 1.247283], ['partial repair probe 2', [[2030, 7, 31], [2031, 10, 5], 12, 0.045], 5.311475], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2024, 9, 16], [2025, 1, 19], 6, 0.0725], 2.503453], ['normal control 2', [[2014, 9, 6], [2014, 9, 25], 6, 0.045], 0.236188]], [['regression long stub single fraction 1', [[2022, 4, 15], [2022, 5, 30], 1, 0.045], 0.556452], ['regression long stub single fraction 2', [[2013, 8, 31], [2014, 4, 8], 6, 0.0725], 4.393342], ['partial repair probe 1', [[2014, 3, 31], [2015, 2, 11], 6, 0.0725], 6.293956], ['partial repair probe 2', [[2033, 12, 30], [2034, 11, 30], 6, 0.045], 4.131148], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2034, 2, 20], [2034, 5, 6], 6, 0.045], 0.93232], ['normal control 2', [[2024, 7, 29], [2024, 10, 3], 6, 0.0725], 1.300272]], [['regression long stub single fraction 1', [[2021, 3, 9], [2022, 3, 8], 6, 0.045], 4.487569], ['regression long stub single fraction 2', [[2039, 11, 25], [2040, 10, 27], 6, 0.045], 4.14538], ['partial repair probe 1', [[2042, 4, 1], [2042, 7, 18], 3, 0.0725], 2.147418], ['partial repair probe 2', [[2028, 1, 17], [2028, 9, 11], 6, 0.045], 2.934783], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2014, 8, 7], [2015, 1, 10], 6, 0.0725], 3.07337], ['normal control 2', [[2037, 6, 29], [2037, 8, 31], 3, 0.045], 0.77038]], [['regression long stub single fraction 1', [[2028, 2, 29], [2028, 8, 29], 3, 0.0725], 3.625], ['regression long stub single fraction 2', [[2027, 4, 28], [2027, 9, 25], 3, 0.045], 1.846467], ['partial repair probe 1', [[2023, 10, 31], [2025, 9, 7], 12, 0.0725], 13.427397], ['partial repair probe 2', [[2030, 9, 30], [2031, 5, 15], 6, 0.05], 3.125], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2005, 3, 31], [2005, 7, 28], 12, 0.0725], 2.363699], ['normal control 2', [[2036, 3, 31], [2037, 12, 28], 12, 0.03], 5.235616]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
from fractions import Fraction
N = 1
observations = []
def solve(prev, maturity, months, rate):
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    P = datetime.date(*prev)
    M = datetime.date(*maturity)
    freq = 12 // months
    def fwd(k):
        t = P.year * 12 + P.month - 1 + k * months
        y, m = t // 12, t % 12 + 1
        return datetime.date(y, m, min(P.day, mlen(y, m)))
    c = 100 * Fraction(str(rate)) / freq
    q1 = fwd(1)
    if M <= q1:
        frac = Fraction((M - P).days, (q1 - P).days)
    else:
        q2 = fwd(2)
        frac = Fraction((M - P).days, (q2 - P).days) * 2
    return round(float(c * frac), 6)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression long stub single fraction 1', [[2035, 6, 25], [2037, 5, 16], 12, 0.05], 9.452055], ['regression long stub single fraction 2', [[2013, 7, 11], [2014, 5, 2], 6, 0.045], 3.629834], ['partial repair probe 1', [[2005, 2, 20], [2006, 2, 13], 6, 0.05], 4.904891], ['partial repair probe 2', [[2040, 1, 21], [2040, 2, 28], 1, 0.05], 0.517241], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2008, 9, 30], [2008, 12, 30], 3, 0.0725], 1.8125], ['normal control 2', [[2025, 9, 27], [2025, 10, 9], 3, 0.03], 0.098901]], [['regression long stub single fraction 1', [[2038, 10, 31], [2039, 10, 28], 6, 0.05], 4.959239], ['regression long stub single fraction 2', [[2025, 11, 30], [2026, 1, 20], 1, 0.045], 0.629032], ['partial repair probe 1', [[2041, 2, 27], [2041, 6, 6], 3, 0.045], 1.247283], ['partial repair probe 2', [[2030, 7, 31], [2031, 10, 5], 12, 0.045], 5.311475], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2024, 9, 16], [2025, 1, 19], 6, 0.0725], 2.503453], ['normal control 2', [[2014, 9, 6], [2014, 9, 25], 6, 0.045], 0.236188]], [['regression long stub single fraction 1', [[2022, 4, 15], [2022, 5, 30], 1, 0.045], 0.556452], ['regression long stub single fraction 2', [[2013, 8, 31], [2014, 4, 8], 6, 0.0725], 4.393342], ['partial repair probe 1', [[2014, 3, 31], [2015, 2, 11], 6, 0.0725], 6.293956], ['partial repair probe 2', [[2033, 12, 30], [2034, 11, 30], 6, 0.045], 4.131148], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2034, 2, 20], [2034, 5, 6], 6, 0.045], 0.93232], ['normal control 2', [[2024, 7, 29], [2024, 10, 3], 6, 0.0725], 1.300272]], [['regression long stub single fraction 1', [[2021, 3, 9], [2022, 3, 8], 6, 0.045], 4.487569], ['regression long stub single fraction 2', [[2039, 11, 25], [2040, 10, 27], 6, 0.045], 4.14538], ['partial repair probe 1', [[2042, 4, 1], [2042, 7, 18], 3, 0.0725], 2.147418], ['partial repair probe 2', [[2028, 1, 17], [2028, 9, 11], 6, 0.045], 2.934783], ['boundary control 1', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['boundary control 2', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['normal control 1', [[2014, 8, 7], [2015, 1, 10], 6, 0.0725], 3.07337], ['normal control 2', [[2037, 6, 29], [2037, 8, 31], 3, 0.045], 0.77038]], [['regression long stub single fraction 1', [[2028, 2, 29], [2028, 8, 29], 3, 0.0725], 3.625], ['regression long stub single fraction 2', [[2027, 4, 28], [2027, 9, 25], 3, 0.045], 1.846467], ['partial repair probe 1', [[2023, 10, 31], [2025, 9, 7], 12, 0.0725], 13.427397], ['partial repair probe 2', [[2030, 9, 30], [2031, 5, 15], 6, 0.05], 3.125], ['boundary control 1', [[2024, 1, 31], [2024, 4, 30], 6, 0.05], 1.236264], ['boundary control 2', [[2024, 1, 31], [2024, 7, 31], 6, 0.05], 2.5], ['normal control 1', [[2005, 3, 31], [2005, 7, 28], 12, 0.0725], 2.363699], ['normal control 2', [[2036, 3, 31], [2037, 12, 28], 12, 0.03], 5.235616]]]
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)

prompt:
The final coupon of a long last period is too large by the day-count mismatch of the extension.

Inputs the last regular coupon date prev, maturity (prev < maturity <= prev + 2 periods), months per period and annual rate. Quasi dates are prev shifted forward k*months with the prev day clamped to month length. c = 100*rate/freq. Short final period (maturity <= q1): c*days(prev,mat)/days(prev,q1). Long final period: c*(1 + days(q1,mat)/days(q1,q2)). Round to 6 decimals.

split: open-access


prompt:
Periods ending on the 31st are one day short.

Inputs two dates [y,m,d]. If D1 is 31 it becomes 30. If D2 is 31 it becomes 1 and M2 increases by one (the formula absorbs a month 13). Return 360*(Y2-Y1)+30*(M2-M1)+(D2-D1).

split: open-access


prompt:
Periods starting on the 31st are one day short.

Inputs two dates [y,m,d]. If D1 is 31 it becomes 30. If D2 is 31 it becomes 1 and M2 increases by one (the formula absorbs a month 13). Return 360*(Y2-Y1)+30*(M2-M1)+(D2-D1).

split: open-access


prompt:
Secondary-market prices ignore interest earned before the buyer settled.

Inputs issue, maturity and settlement dates, coupon and yield (decimals). The instrument pays 100*(1 + coupon*T/360) at maturity where T = days(issue, maturity). Dirty = redemption/(1 + y*R/360) with R = days(settle, maturity); accrued = 100*coupon*A/360 with A = days(issue, settle). Return [dirty, dirty-accrued] rounded to 6.

split: open-access


prompt:
Prices are too low for seasoned certificates.

Inputs issue, maturity and settlement dates, coupon and yield (decimals). The instrument pays 100*(1 + coupon*T/360) at maturity where T = days(issue, maturity). Dirty = redemption/(1 + y*R/360) with R = days(settle, maturity); accrued = 100*coupon*A/360 with A = days(issue, settle). Return [dirty, dirty-accrued] rounded to 6.

split: open-access


prompt:
Clean prices are wrong except at the midpoint.

Inputs issue, maturity and settlement dates, coupon and yield (decimals). The instrument pays 100*(1 + coupon*T/360) at maturity where T = days(issue, maturity). Dirty = redemption/(1 + y*R/360) with R = days(settle, maturity); accrued = 100*coupon*A/360 with A = days(issue, settle). Return [dirty, dirty-accrued] rounded to 6.

split: open-access


prompt:
Clean prices exceed dirty prices.

Inputs issue, maturity and settlement dates, coupon and yield (decimals). The instrument pays 100*(1 + coupon*T/360) at maturity where T = days(issue, maturity). Dirty = redemption/(1 + y*R/360) with R = days(settle, maturity); accrued = 100*coupon*A/360 with A = days(issue, settle). Return [dirty, dirty-accrued] rounded to 6.

split: open-access


prompt:
Unadjusted-accrual swaps accrue on adjusted dates and vice versa.

Inputs an unadjusted schedule (first element is the accrual start), holidays and a flag. Business days are weekdays not in holidays; adjustment is modified following. For each period the payment date is the adjusted end date; accrual days use adjusted start and end if the flag is set, otherwise the unadjusted dates. Return [[payment date, accrual days], ...].

split: open-access


prompt:
Payments fall on weekends and holidays.

Inputs an unadjusted schedule (first element is the accrual start), holidays and a flag. Business days are weekdays not in holidays; adjustment is modified following. For each period the payment date is the adjusted end date; accrual days use adjusted start and end if the flag is set, otherwise the unadjusted dates. Return [[payment date, accrual days], ...].

split: open-access


prompt:
Unadjusted accrual periods gain or lose days whenever the payment date moves.

Inputs an unadjusted schedule (first element is the accrual start), holidays and a flag. Business days are weekdays not in holidays; adjustment is modified following. For each period the payment date is the adjusted end date; accrual days use adjusted start and end if the flag is set, otherwise the unadjusted dates. Return [[payment date, accrual days], ...].

split: open-access


prompt:
Converting an Act/360 rate to Act/365 lowers it instead of raising it.

Inputs a nominal rate, from/to day-count year basis (360 or 365), from/to compounding frequency (0 = continuous). First rescale the nominal rate by to_basis/from_basis, then convert compounding through the effective annual rate: EAR = (1+r/m)^m - 1 or e^r - 1; target nominal = m*((1+EAR)^(1/m)-1) or ln(1+EAR). Return rounded to 10 decimals.

split: open-access


prompt:
Continuously compounded outputs are too high.

Inputs a nominal rate, from/to day-count year basis (360 or 365), from/to compounding frequency (0 = continuous). First rescale the nominal rate by to_basis/from_basis, then convert compounding through the effective annual rate: EAR = (1+r/m)^m - 1 or e^r - 1; target nominal = m*((1+EAR)^(1/m)-1) or ln(1+EAR). Return rounded to 10 decimals.

split: open-access


prompt:
Converting from continuous compounding understates the effective rate.

Inputs a nominal rate, from/to day-count year basis (360 or 365), from/to compounding frequency (0 = continuous). First rescale the nominal rate by to_basis/from_basis, then convert compounding through the effective annual rate: EAR = (1+r/m)^m - 1 or e^r - 1; target nominal = m*((1+EAR)^(1/m)-1) or ln(1+EAR). Return rounded to 10 decimals.

split: open-access


prompt:
Semi-annual and monthly targets are divided by their frequency.

Inputs a nominal rate, from/to day-count year basis (360 or 365), from/to compounding frequency (0 = continuous). First rescale the nominal rate by to_basis/from_basis, then convert compounding through the effective annual rate: EAR = (1+r/m)^m - 1 or e^r - 1; target nominal = m*((1+EAR)^(1/m)-1) or ln(1+EAR). Return rounded to 10 decimals.

split: open-access


prompt:
Combined basis and compounding conversions drift from the contract value.

Inputs a nominal rate, from/to day-count year basis (360 or 365), from/to compounding frequency (0 = continuous). First rescale the nominal rate by to_basis/from_basis, then convert compounding through the effective annual rate: EAR = (1+r/m)^m - 1 or e^r - 1; target nominal = m*((1+EAR)^(1/m)-1) or ln(1+EAR). Return rounded to 10 decimals.

split: open-access


prompt:
Periods ending on a leap day count one fewer stub day or one fewer whole year.

Inputs start < end [y,m,d]. Count whole years n stepping back from the end date (an end of 29 February maps to 28 February in non-leap years) while the stepped date is not before start. The stub runs from start to the end stepped back n years; its denominator is 366 if a 29 February lies in (start, stub end], else 365. Return n + stub days/denominator rounded to 9 decimals.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(a, b):
    A = datetime.date(*a)
    B = datetime.date(*b)
    def leap(y):
        return (y % 4 == 0 and y % 100 != 0) or y % 400 == 0
    def back_years(n):
        y = B.year - n
        if B.month == 2 and B.day == 29 and not leap(y):
            return datetime.date(y, 2, 28)
        return datetime.date(y, B.month, B.day)
    n = 0
    while back_years(n + 1) >= A:
        n += 1
    stub_end = back_years(n)
    has29 = any(leap(y) and A < datetime.date(y, 2, 29) <= stub_end for y in range(A.year, stub_end.year + 1))
    den = 366 if leap(stub_end.year) else 365
    return round(n + (stub_end - A).days / den, 9)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression stub denominator source 1', [[2032, 5, 5], [2036, 10, 2]], 4.410958904], ['regression stub denominator source 2', [[2052, 9, 30], [2060, 10, 9]], 8.024657534], ['partial repair probe 1', [[1999, 8, 31], [2007, 4, 1]], 7.584699454], ['partial repair probe 2', [[1996, 12, 22], [2004, 2, 29]], 7.18630137], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2045, 1, 30], [2052, 5, 23]], 7.309589041], ['normal control 2', [[2001, 6, 1], [2003, 5, 15]], 1.953424658]], [['regression stub denominator source 1', [[2055, 10, 31], [2062, 2, 9]], 6.276712329], ['regression stub denominator source 2', [[2020, 6, 30], [2021, 9, 8]], 1.191780822], ['partial repair probe 1', [[1991, 12, 29], [1993, 10, 14]], 1.792349727], ['partial repair probe 2', [[2007, 3, 19], [2008, 2, 29]], 0.948087432], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2090, 4, 30], [2094, 9, 11]], 4.367123288], ['normal control 2', [[2020, 2, 15], [2024, 2, 29]], 4.038251366]], [['regression stub denominator source 1', [[2048, 11, 1], [2050, 11, 11]], 2.02739726], ['regression stub denominator source 2', [[2068, 4, 18], [2069, 12, 1]], 1.621917808], ['partial repair probe 1', [[2048, 12, 15], [2055, 4, 3]], 6.298630137], ['partial repair probe 2', [[2003, 7, 18], [2008, 2, 29]], 4.617486339], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2021, 2, 21], [2024, 2, 29]], 3.019178082], ['normal control 2', [[2014, 5, 4], [2016, 2, 29]], 1.821917808]], [['regression stub denominator source 1', [[2080, 5, 22], [2086, 7, 16]], 6.150684932], ['regression stub denominator source 2', [[2032, 4, 16], [2038, 9, 3]], 6.383561644], ['partial repair probe 1', [[1992, 7, 29], [1997, 7, 8]], 4.942465753], ['partial repair probe 2', [[2000, 12, 6], [2008, 2, 29]], 7.230136986], ['boundary control 1', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['boundary control 2', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['normal control 1', [[2002, 2, 11], [2008, 2, 29]], 6.046575342], ['normal control 2', [[2079, 4, 12], [2082, 5, 2]], 3.054794521]], [['regression stub denominator source 1', [[2024, 2, 29], [2027, 7, 20]], 3.389041096], ['regression stub denominator source 2', [[2016, 5, 31], [2018, 11, 21]], 2.476712329], ['partial repair probe 1', [[2027, 8, 10], [2028, 2, 29]], 0.554644809], ['partial repair probe 2', [[2067, 10, 31], [2069, 10, 1]], 1.918032787], ['boundary control 1', [[2024, 1, 1], [2025, 1, 1]], 1.0], ['boundary control 2', [[2023, 2, 28], [2024, 2, 29]], 1.0], ['normal control 1', [[2009, 2, 17], [2016, 2, 29]], 7.030136986], ['normal control 2', [[2012, 2, 21], [2020, 2, 29]], 8.021857923]]]
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)

prompt:
Stubs that contain a leap day from the previous year, or none at all, use the wrong year length.

Inputs start < end [y,m,d]. Count whole years n stepping back from the end date (an end of 29 February maps to 28 February in non-leap years) while the stepped date is not before start. The stub runs from start to the end stepped back n years; its denominator is 366 if a 29 February lies in (start, stub end], else 365. Return n + stub days/denominator rounded to 9 decimals.

split: open-access


prompt:
Stubs in periods of more than a year use 366 because of leap days in the whole years.

Inputs start < end [y,m,d]. Count whole years n stepping back from the end date (an end of 29 February maps to 28 February in non-leap years) while the stepped date is not before start. The stub runs from start to the end stepped back n years; its denominator is 366 if a 29 February lies in (start, stub end], else 365. Return n + stub days/denominator rounded to 9 decimals.

split: open-access


prompt:
Settling on a coupon date charges a full period of accrued interest.

Inputs issue date, ascending coupon schedule (last = maturity) and settlement. Settlement before issue returns "not issued"; on or after maturity returns "matured". Otherwise return [period start, next coupon] where a settlement on a coupon date belongs to the following period and the first period starts at issue.

split: open-access


prompt:
Accrual in an irregular first period starts on a date other than issue.

Inputs issue date, ascending coupon schedule (last = maturity) and settlement. Settlement before issue returns "not issued"; on or after maturity returns "matured". Otherwise return [period start, next coupon] where a settlement on a coupon date belongs to the following period and the first period starts at issue.

split: open-access


prompt:
Trades in the first coupon period are refused.

Inputs issue date, ascending coupon schedule (last = maturity) and settlement. Settlement before issue returns "not issued"; on or after maturity returns "matured". Otherwise return [period start, next coupon] where a settlement on a coupon date belongs to the following period and the first period starts at issue.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(start, tenor, holidays, principal, rate):
    S = datetime.date(*start)
    H = {datetime.date(*h) for h in holidays}
    def biz(x):
        return x.weekday() < 5 and x not in H
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    def last_biz(y, m):
        x = datetime.date(y, m, mlen(y, m))
        while not biz(x):
            x -= datetime.timedelta(days=1)
        return x
    def mf(x):
        f = x
        while not biz(f):
            f += datetime.timedelta(days=1)
        if f.month != x.month:
            f = x
            while not biz(f):
                f -= datetime.timedelta(days=1)
        return f
    t = S.year * 12 + S.month - 1 + tenor
    y, m = t // 12, t % 12 + 1
    if S.day == mlen(S.year, S.month):
        M = last_biz(y, m)
    else:
        M = mf(datetime.date(y, m, min(S.day, mlen(y, m))))
    interest = round(principal * rate * (M - S).days / 360, 2)
    return [[M.year, M.month, M.day], interest]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression end-end trigger 1', [[2026, 5, 29], 2, [], 1000000, 0.0425], [[2026, 7, 31], 7437.5]], ['regression end-end trigger 2', [[2019, 3, 29], 2, [[2019, 5, 28], [2019, 5, 27], [2019, 5, 31]], 1000000, 0.0425], [[2019, 5, 30], 7319.44]], ['partial repair probe 1', [[2030, 7, 29], 3, [], 1000000, 0.053], [[2030, 10, 29], 13544.44]], ['partial repair probe 2', [[2029, 11, 28], 6, [], 1000000, 0.053], [[2030, 5, 28], 26647.22]], ['normal control 1', [[2019, 2, 28], 3, [[2019, 5, 27]], 1000000, 0.0425], [[2019, 5, 31], 10861.11]], ['normal control 2', [[2027, 3, 31], 12, [[2028, 3, 27], [2028, 3, 30], [2028, 3, 30]], 1000000, 0.0425], [[2028, 3, 31], 43208.33]], ['normal control 3', [[2027, 7, 29], 6, [[2028, 1, 28], [2028, 1, 31], [2028, 1, 27]], 1000000, 0.0125], [[2028, 1, 26], 6284.72]], ['normal control 4', [[2028, 4, 26], 1, [[2028, 5, 30], [2028, 5, 30]], 1000000, 0.053], [[2028, 5, 26], 4416.67]]], [['regression end-end trigger 1', [[2023, 4, 28], 12, [], 250000, 0.0125], [[2024, 4, 30], 3194.44]], ['regression end-end trigger 2', [[2027, 1, 29], 6, [], 250000, 0.0125], [[2027, 7, 30], 1579.86]], ['partial repair probe 1', [[2029, 11, 28], 12, [[2030, 11, 26]], 250000, 0.0425], [[2030, 11, 28], 10772.57]], ['partial repair probe 2', [[2023, 11, 28], 6, [[2024, 5, 31]], 250000, 0.0125], [[2024, 5, 28], 1579.86]], ['normal control 1', [[2026, 3, 31], 12, [[2027, 3, 31]], 250000, 0.053], [[2027, 3, 30], 13397.22]], ['normal control 2', [[2030, 11, 11], 2, [[2031, 1, 31], [2031, 1, 28], [2031, 1, 30]], 1000000, 0.0425], [[2031, 1, 13], 7437.5]], ['normal control 3', [[2025, 1, 31], 3, [[2025, 4, 26], [2025, 4, 27]], 250000, 0.053], [[2025, 4, 30], 3275.69]], ['normal control 4', [[2023, 6, 22], 1, [], 1000000, 0.0125], [[2023, 7, 24], 1111.11]]], [['regression end-end trigger 1', [[2020, 2, 28], 2, [[2020, 4, 26], [2020, 4, 26]], 250000, 0.0125], [[2020, 4, 30], 538.19]], ['regression end-end trigger 2', [[2023, 4, 28], 6, [], 250000, 0.0425], [[2023, 10, 31], 5489.58]], ['partial repair probe 1', [[2021, 6, 28], 1, [[2021, 7, 29], [2021, 7, 27]], 1000000, 0.053], [[2021, 7, 28], 4416.67]], ['partial repair probe 2', [[2025, 2, 26], 3, [[2025, 5, 30], [2025, 5, 31]], 250000, 0.053], [[2025, 5, 26], 3275.69]], ['normal control 1', [[2023, 3, 31], 3, [[2023, 6, 26], [2023, 6, 29]], 250000, 0.0425], [[2023, 6, 30], 2685.76]], ['normal control 2', [[2029, 5, 31], 2, [[2029, 7, 28], [2029, 7, 31]], 1000000, 0.0125], [[2029, 7, 30], 2083.33]], ['normal control 3', [[2024, 9, 30], 2, [[2024, 11, 26]], 250000, 0.0425], [[2024, 11, 29], 1770.83]], ['normal control 4', [[2030, 5, 20], 12, [[2031, 5, 31], [2031, 5, 29], [2031, 5, 27]], 1000000, 0.053], [[2031, 5, 20], 53736.11]]], [['regression end-end trigger 1', [[2027, 1, 29], 2, [], 250000, 0.0425], [[2027, 3, 31], 1800.35]], ['regression end-end trigger 2', [[2027, 2, 26], 12, [[2028, 2, 25], [2028, 2, 27]], 1000000, 0.053], [[2028, 2, 29], 54177.78]], ['partial repair probe 1', [[2025, 10, 29], 2, [[2025, 12, 30]], 250000, 0.0125], [[2025, 12, 29], 529.51]], ['partial repair probe 2', [[2029, 1, 29], 12, [], 1000000, 0.053], [[2030, 1, 29], 53736.11]], ['normal control 1', [[2025, 5, 21], 2, [[2025, 7, 31], [2025, 7, 28], [2025, 7, 29]], 1000000, 0.0425], [[2025, 7, 21], 7201.39]], ['normal control 2', [[2028, 7, 31], 3, [], 1000000, 0.0125], [[2028, 10, 31], 3194.44]], ['normal control 3', [[2024, 1, 30], 2, [[2024, 3, 28], [2024, 3, 28], [2024, 3, 30]], 250000, 0.0125], [[2024, 3, 29], 512.15]], ['normal control 4', [[2023, 3, 27], 12, [[2024, 3, 31]], 250000, 0.0425], [[2024, 3, 27], 10802.08]]], [['regression end-end trigger 1', [[2030, 11, 29], 2, [[2031, 1, 29], [2031, 1, 29]], 250000, 0.0125], [[2031, 1, 31], 546.88]], ['regression end-end trigger 2', [[2023, 4, 28], 1, [[2023, 5, 31]], 250000, 0.0425], [[2023, 5, 30], 944.44]], ['partial repair probe 1', [[2021, 11, 29], 6, [], 250000, 0.053], [[2022, 5, 30], 6698.61]], ['partial repair probe 2', [[2030, 5, 29], 2, [], 250000, 0.0125], [[2030, 7, 29], 529.51]], ['normal control 1', [[2019, 1, 31], 1, [], 250000, 0.0125], [[2019, 2, 28], 243.06]], ['normal control 2', [[2021, 8, 31], 2, [[2021, 10, 29], [2021, 10, 29]], 250000, 0.0425], [[2021, 10, 28], 1711.81]], ['normal control 3', [[2020, 2, 17], 6, [[2020, 8, 29]], 1000000, 0.053], [[2020, 8, 17], 26794.44]], ['normal control 4', [[2030, 2, 28], 3, [], 1000000, 0.0425], [[2030, 5, 31], 10861.11]]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(start, tenor, holidays, principal, rate):
    S = datetime.date(*start)
    H = {datetime.date(*h) for h in holidays}
    def biz(x):
        return x.weekday() < 5 and x not in H
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    def last_biz(y, m):
        x = datetime.date(y, m, mlen(y, m))
        while not biz(x):
            x -= datetime.timedelta(days=1)
        return x
    def mf(x):
        f = x
        while not biz(f):
            f += datetime.timedelta(days=1)
        if f.month != x.month:
            f = x
            while not biz(f):
                f -= datetime.timedelta(days=1)
        return f
    t = S.year * 12 + S.month - 1 + tenor
    y, m = t // 12, t % 12 + 1
    if S.day >= mlen(S.year, S.month) - 2:
        M = last_biz(y, m)
    else:
        M = mf(datetime.date(y, m, min(S.day, mlen(y, m))))
    interest = round(principal * rate * (M - S).days / 360, 2)
    return [[M.year, M.month, M.day], interest]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression end-end trigger 1', [[2026, 5, 29], 2, [], 1000000, 0.0425], [[2026, 7, 31], 7437.5]], ['regression end-end trigger 2', [[2019, 3, 29], 2, [[2019, 5, 28], [2019, 5, 27], [2019, 5, 31]], 1000000, 0.0425], [[2019, 5, 30], 7319.44]], ['partial repair probe 1', [[2030, 7, 29], 3, [], 1000000, 0.053], [[2030, 10, 29], 13544.44]], ['partial repair probe 2', [[2029, 11, 28], 6, [], 1000000, 0.053], [[2030, 5, 28], 26647.22]], ['normal control 1', [[2019, 2, 28], 3, [[2019, 5, 27]], 1000000, 0.0425], [[2019, 5, 31], 10861.11]], ['normal control 2', [[2027, 3, 31], 12, [[2028, 3, 27], [2028, 3, 30], [2028, 3, 30]], 1000000, 0.0425], [[2028, 3, 31], 43208.33]], ['normal control 3', [[2027, 7, 29], 6, [[2028, 1, 28], [2028, 1, 31], [2028, 1, 27]], 1000000, 0.0125], [[2028, 1, 26], 6284.72]], ['normal control 4', [[2028, 4, 26], 1, [[2028, 5, 30], [2028, 5, 30]], 1000000, 0.053], [[2028, 5, 26], 4416.67]]], [['regression end-end trigger 1', [[2023, 4, 28], 12, [], 250000, 0.0125], [[2024, 4, 30], 3194.44]], ['regression end-end trigger 2', [[2027, 1, 29], 6, [], 250000, 0.0125], [[2027, 7, 30], 1579.86]], ['partial repair probe 1', [[2029, 11, 28], 12, [[2030, 11, 26]], 250000, 0.0425], [[2030, 11, 28], 10772.57]], ['partial repair probe 2', [[2023, 11, 28], 6, [[2024, 5, 31]], 250000, 0.0125], [[2024, 5, 28], 1579.86]], ['normal control 1', [[2026, 3, 31], 12, [[2027, 3, 31]], 250000, 0.053], [[2027, 3, 30], 13397.22]], ['normal control 2', [[2030, 11, 11], 2, [[2031, 1, 31], [2031, 1, 28], [2031, 1, 30]], 1000000, 0.0425], [[2031, 1, 13], 7437.5]], ['normal control 3', [[2025, 1, 31], 3, [[2025, 4, 26], [2025, 4, 27]], 250000, 0.053], [[2025, 4, 30], 3275.69]], ['normal control 4', [[2023, 6, 22], 1, [], 1000000, 0.0125], [[2023, 7, 24], 1111.11]]], [['regression end-end trigger 1', [[2020, 2, 28], 2, [[2020, 4, 26], [2020, 4, 26]], 250000, 0.0125], [[2020, 4, 30], 538.19]], ['regression end-end trigger 2', [[2023, 4, 28], 6, [], 250000, 0.0425], [[2023, 10, 31], 5489.58]], ['partial repair probe 1', [[2021, 6, 28], 1, [[2021, 7, 29], [2021, 7, 27]], 1000000, 0.053], [[2021, 7, 28], 4416.67]], ['partial repair probe 2', [[2025, 2, 26], 3, [[2025, 5, 30], [2025, 5, 31]], 250000, 0.053], [[2025, 5, 26], 3275.69]], ['normal control 1', [[2023, 3, 31], 3, [[2023, 6, 26], [2023, 6, 29]], 250000, 0.0425], [[2023, 6, 30], 2685.76]], ['normal control 2', [[2029, 5, 31], 2, [[2029, 7, 28], [2029, 7, 31]], 1000000, 0.0125], [[2029, 7, 30], 2083.33]], ['normal control 3', [[2024, 9, 30], 2, [[2024, 11, 26]], 250000, 0.0425], [[2024, 11, 29], 1770.83]], ['normal control 4', [[2030, 5, 20], 12, [[2031, 5, 31], [2031, 5, 29], [2031, 5, 27]], 1000000, 0.053], [[2031, 5, 20], 53736.11]]], [['regression end-end trigger 1', [[2027, 1, 29], 2, [], 250000, 0.0425], [[2027, 3, 31], 1800.35]], ['regression end-end trigger 2', [[2027, 2, 26], 12, [[2028, 2, 25], [2028, 2, 27]], 1000000, 0.053], [[2028, 2, 29], 54177.78]], ['partial repair probe 1', [[2025, 10, 29], 2, [[2025, 12, 30]], 250000, 0.0125], [[2025, 12, 29], 529.51]], ['partial repair probe 2', [[2029, 1, 29], 12, [], 1000000, 0.053], [[2030, 1, 29], 53736.11]], ['normal control 1', [[2025, 5, 21], 2, [[2025, 7, 31], [2025, 7, 28], [2025, 7, 29]], 1000000, 0.0425], [[2025, 7, 21], 7201.39]], ['normal control 2', [[2028, 7, 31], 3, [], 1000000, 0.0125], [[2028, 10, 31], 3194.44]], ['normal control 3', [[2024, 1, 30], 2, [[2024, 3, 28], [2024, 3, 28], [2024, 3, 30]], 250000, 0.0125], [[2024, 3, 29], 512.15]], ['normal control 4', [[2023, 3, 27], 12, [[2024, 3, 31]], 250000, 0.0425], [[2024, 3, 27], 10802.08]]], [['regression end-end trigger 1', [[2030, 11, 29], 2, [[2031, 1, 29], [2031, 1, 29]], 250000, 0.0125], [[2031, 1, 31], 546.88]], ['regression end-end trigger 2', [[2023, 4, 28], 1, [[2023, 5, 31]], 250000, 0.0425], [[2023, 5, 30], 944.44]], ['partial repair probe 1', [[2021, 11, 29], 6, [], 250000, 0.053], [[2022, 5, 30], 6698.61]], ['partial repair probe 2', [[2030, 5, 29], 2, [], 250000, 0.0125], [[2030, 7, 29], 529.51]], ['normal control 1', [[2019, 1, 31], 1, [], 250000, 0.0125], [[2019, 2, 28], 243.06]], ['normal control 2', [[2021, 8, 31], 2, [[2021, 10, 29], [2021, 10, 29]], 250000, 0.0425], [[2021, 10, 28], 1711.81]], ['normal control 3', [[2020, 2, 17], 6, [[2020, 8, 29]], 1000000, 0.053], [[2020, 8, 17], 26794.44]], ['normal control 4', [[2030, 2, 28], 3, [], 1000000, 0.0425], [[2030, 5, 31], 10861.11]]]]
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)

prompt:
Deposits starting on the last business day before a month-end weekend mature mid-month.

Inputs a start business day, tenor in months, holidays, principal and rate. If the start is the last business day of its month, maturity is the last business day of the target month; otherwise maturity is the start day clamped into the target month and adjusted modified following. Interest = principal*rate*days/360 rounded to 2. Return [maturity, interest].

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(start, tenor, holidays, principal, rate):
    S = datetime.date(*start)
    H = {datetime.date(*h) for h in holidays}
    def biz(x):
        return x.weekday() < 5 and x not in H
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    def last_biz(y, m):
        x = datetime.date(y, m, mlen(y, m))
        while not biz(x):
            x -= datetime.timedelta(days=1)
        return x
    def mf(x):
        f = x
        while not biz(f):
            f += datetime.timedelta(days=1)
        if f.month != x.month:
            f = x
            while not biz(f):
                f -= datetime.timedelta(days=1)
        return f
    t = S.year * 12 + S.month - 1 + tenor
    y, m = t // 12, t % 12 + 1
    if S == last_biz(S.year, S.month):
        M = datetime.date(y, m, mlen(y, m))
    else:
        M = mf(datetime.date(y, m, min(S.day, mlen(y, m))))
    interest = round(principal * rate * (M - S).days / 360, 2)
    return [[M.year, M.month, M.day], interest]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression end-end target 1', [[2024, 5, 31], 6, [[2024, 11, 30], [2024, 11, 28], [2024, 11, 27]], 1000000, 0.0125], [[2024, 11, 29], 6319.44]], ['regression end-end target 2', [[2022, 6, 30], 1, [[2022, 7, 29], [2022, 7, 27], [2022, 7, 29]], 250000, 0.053], [[2022, 7, 28], 1030.56]], ['partial repair probe 1', [[2019, 2, 28], 2, [[2019, 4, 30], [2019, 4, 26], [2019, 4, 26]], 1000000, 0.053], [[2019, 4, 29], 8833.33]], ['partial repair probe 2', [[2024, 12, 31], 3, [[2025, 3, 30], [2025, 3, 31]], 1000000, 0.053], [[2025, 3, 28], 12808.33]], ['normal control 1', [[2025, 3, 17], 2, [[2025, 5, 28], [2025, 5, 27]], 250000, 0.0425], [[2025, 5, 19], 1859.38]], ['normal control 2', [[2024, 3, 4], 2, [[2024, 5, 30], [2024, 5, 27], [2024, 5, 31]], 250000, 0.0125], [[2024, 5, 6], 546.88]], ['normal control 3', [[2023, 7, 7], 3, [[2023, 10, 29], [2023, 10, 30], [2023, 10, 28]], 1000000, 0.0425], [[2023, 10, 9], 11097.22]], ['normal control 4', [[2025, 5, 30], 1, [[2025, 6, 27]], 250000, 0.053], [[2025, 6, 30], 1140.97]]], [['regression end-end target 1', [[2025, 12, 31], 1, [], 1000000, 0.0125], [[2026, 1, 30], 1041.67]], ['regression end-end target 2', [[2019, 3, 29], 3, [[2019, 6, 27]], 1000000, 0.0425], [[2019, 6, 28], 10743.06]], ['partial repair probe 1', [[2029, 11, 30], 1, [[2029, 12, 31]], 250000, 0.0125], [[2029, 12, 28], 243.06]], ['partial repair probe 2', [[2030, 4, 30], 12, [[2031, 4, 27], [2031, 4, 30], [2031, 4, 27]], 1000000, 0.0125], [[2031, 4, 29], 12638.89]], ['normal control 1', [[2021, 5, 14], 3, [[2021, 8, 31]], 250000, 0.0425], [[2021, 8, 16], 2774.31]], ['normal control 2', [[2019, 2, 27], 2, [[2019, 4, 30], [2019, 4, 29]], 250000, 0.053], [[2019, 4, 26], 2134.72]], ['normal control 3', [[2024, 1, 31], 12, [[2025, 1, 29], [2025, 1, 29], [2025, 1, 30]], 1000000, 0.053], [[2025, 1, 31], 53883.33]], ['normal control 4', [[2027, 2, 26], 6, [[2027, 8, 29]], 250000, 0.053], [[2027, 8, 31], 6845.83]]], [['regression end-end target 1', [[2030, 3, 29], 1, [[2030, 4, 30], [2030, 4, 27], [2030, 4, 30]], 1000000, 0.0425], [[2030, 4, 29], 3659.72]], ['regression end-end target 2', [[2026, 4, 30], 1, [], 250000, 0.053], [[2026, 5, 29], 1067.36]], ['partial repair probe 1', [[2027, 7, 30], 3, [[2027, 10, 29], [2027, 10, 29]], 250000, 0.0425], [[2027, 10, 28], 2656.25]], ['partial repair probe 2', [[2025, 6, 30], 2, [[2025, 8, 31], [2025, 8, 29], [2025, 8, 31]], 250000, 0.0425], [[2025, 8, 28], 1741.32]], ['normal control 1', [[2030, 6, 17], 1, [], 250000, 0.0425], [[2030, 7, 17], 885.42]], ['normal control 2', [[2023, 7, 12], 1, [], 1000000, 0.0125], [[2023, 8, 14], 1145.83]], ['normal control 3', [[2021, 8, 16], 1, [[2021, 9, 26], [2021, 9, 29], [2021, 9, 26]], 1000000, 0.053], [[2021, 9, 16], 4563.89]], ['normal control 4', [[2027, 6, 17], 2, [[2027, 8, 28], [2027, 8, 27], [2027, 8, 29]], 250000, 0.0125], [[2027, 8, 17], 529.51]]], [['regression end-end target 1', [[2028, 3, 31], 6, [[2028, 9, 30], [2028, 9, 30], [2028, 9, 29]], 1000000, 0.0425], [[2028, 9, 28], 21368.06]], ['regression end-end target 2', [[2029, 8, 31], 6, [[2030, 2, 28]], 250000, 0.053], [[2030, 2, 27], 6625.0]], ['partial repair probe 1', [[2030, 10, 31], 3, [[2031, 1, 31], [2031, 1, 27], [2031, 1, 31]], 1000000, 0.0425], [[2031, 1, 30], 10743.06]], ['partial repair probe 2', [[2020, 11, 30], 2, [[2021, 1, 29], [2021, 1, 29], [2021, 1, 30]], 1000000, 0.0425], [[2021, 1, 28], 6965.28]], ['normal control 1', [[2024, 1, 15], 3, [], 250000, 0.0125], [[2024, 4, 15], 789.93]], ['normal control 2', [[2022, 10, 20], 6, [[2023, 4, 30], [2023, 4, 29]], 250000, 0.053], [[2023, 4, 20], 6698.61]], ['normal control 3', [[2027, 9, 21], 12, [[2028, 9, 26]], 250000, 0.053], [[2028, 9, 21], 13470.83]], ['normal control 4', [[2021, 3, 3], 12, [[2022, 3, 30], [2022, 3, 29], [2022, 3, 29]], 250000, 0.0425], [[2022, 3, 3], 10772.57]]], [['regression end-end target 1', [[2020, 12, 31], 1, [[2021, 1, 28], [2021, 1, 28], [2021, 1, 28]], 1000000, 0.0125], [[2021, 1, 29], 1006.94]], ['regression end-end target 2', [[2024, 4, 30], 2, [[2024, 6, 30], [2024, 6, 26], [2024, 6, 28]], 250000, 0.053], [[2024, 6, 27], 2134.72]], ['partial repair probe 1', [[2022, 7, 29], 3, [[2022, 10, 31], [2022, 10, 31], [2022, 10, 30]], 250000, 0.053], [[2022, 10, 28], 3349.31]], ['partial repair probe 2', [[2022, 2, 28], 1, [[2022, 3, 31], [2022, 3, 29]], 1000000, 0.0125], [[2022, 3, 30], 1041.67]], ['normal control 1', [[2020, 11, 10], 2, [[2021, 1, 27], [2021, 1, 28]], 1000000, 0.0425], [[2021, 1, 11], 7319.44]], ['normal control 2', [[2021, 5, 31], 1, [], 250000, 0.053], [[2021, 6, 30], 1104.17]], ['normal control 3', [[2029, 10, 22], 6, [], 1000000, 0.0125], [[2030, 4, 22], 6319.44]], ['normal control 4', [[2027, 4, 2], 2, [], 1000000, 0.0125], [[2027, 6, 2], 2118.06]]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json
import datetime
N = 1
observations = []
def solve(start, tenor, holidays, principal, rate):
    S = datetime.date(*start)
    H = {datetime.date(*h) for h in holidays}
    def biz(x):
        return x.weekday() < 5 and x not in H
    def mlen(y, m):
        if m == 2:
            return 29 if (y % 4 == 0 and y % 100 != 0) or y % 400 == 0 else 28
        return 30 if m in (4, 6, 9, 11) else 31
    def last_biz(y, m):
        x = datetime.date(y, m, mlen(y, m))
        while not biz(x):
            x -= datetime.timedelta(days=1)
        return x
    def mf(x):
        f = x
        while not biz(f):
            f += datetime.timedelta(days=1)
        if f.month != x.month:
            f = x
            while not biz(f):
                f -= datetime.timedelta(days=1)
        return f
    t = S.year * 12 + S.month - 1 + tenor
    y, m = t // 12, t % 12 + 1
    if S == last_biz(S.year, S.month):
        M = datetime.date(y, m, mlen(y, m))
        while M.weekday() >= 5:
            M -= datetime.timedelta(days=1)
    else:
        M = mf(datetime.date(y, m, min(S.day, mlen(y, m))))
    interest = round(principal * rate * (M - S).days / 360, 2)
    return [[M.year, M.month, M.day], interest]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression end-end target 1', [[2024, 5, 31], 6, [[2024, 11, 30], [2024, 11, 28], [2024, 11, 27]], 1000000, 0.0125], [[2024, 11, 29], 6319.44]], ['regression end-end target 2', [[2022, 6, 30], 1, [[2022, 7, 29], [2022, 7, 27], [2022, 7, 29]], 250000, 0.053], [[2022, 7, 28], 1030.56]], ['partial repair probe 1', [[2019, 2, 28], 2, [[2019, 4, 30], [2019, 4, 26], [2019, 4, 26]], 1000000, 0.053], [[2019, 4, 29], 8833.33]], ['partial repair probe 2', [[2024, 12, 31], 3, [[2025, 3, 30], [2025, 3, 31]], 1000000, 0.053], [[2025, 3, 28], 12808.33]], ['normal control 1', [[2025, 3, 17], 2, [[2025, 5, 28], [2025, 5, 27]], 250000, 0.0425], [[2025, 5, 19], 1859.38]], ['normal control 2', [[2024, 3, 4], 2, [[2024, 5, 30], [2024, 5, 27], [2024, 5, 31]], 250000, 0.0125], [[2024, 5, 6], 546.88]], ['normal control 3', [[2023, 7, 7], 3, [[2023, 10, 29], [2023, 10, 30], [2023, 10, 28]], 1000000, 0.0425], [[2023, 10, 9], 11097.22]], ['normal control 4', [[2025, 5, 30], 1, [[2025, 6, 27]], 250000, 0.053], [[2025, 6, 30], 1140.97]]], [['regression end-end target 1', [[2025, 12, 31], 1, [], 1000000, 0.0125], [[2026, 1, 30], 1041.67]], ['regression end-end target 2', [[2019, 3, 29], 3, [[2019, 6, 27]], 1000000, 0.0425], [[2019, 6, 28], 10743.06]], ['partial repair probe 1', [[2029, 11, 30], 1, [[2029, 12, 31]], 250000, 0.0125], [[2029, 12, 28], 243.06]], ['partial repair probe 2', [[2030, 4, 30], 12, [[2031, 4, 27], [2031, 4, 30], [2031, 4, 27]], 1000000, 0.0125], [[2031, 4, 29], 12638.89]], ['normal control 1', [[2021, 5, 14], 3, [[2021, 8, 31]], 250000, 0.0425], [[2021, 8, 16], 2774.31]], ['normal control 2', [[2019, 2, 27], 2, [[2019, 4, 30], [2019, 4, 29]], 250000, 0.053], [[2019, 4, 26], 2134.72]], ['normal control 3', [[2024, 1, 31], 12, [[2025, 1, 29], [2025, 1, 29], [2025, 1, 30]], 1000000, 0.053], [[2025, 1, 31], 53883.33]], ['normal control 4', [[2027, 2, 26], 6, [[2027, 8, 29]], 250000, 0.053], [[2027, 8, 31], 6845.83]]], [['regression end-end target 1', [[2030, 3, 29], 1, [[2030, 4, 30], [2030, 4, 27], [2030, 4, 30]], 1000000, 0.0425], [[2030, 4, 29], 3659.72]], ['regression end-end target 2', [[2026, 4, 30], 1, [], 250000, 0.053], [[2026, 5, 29], 1067.36]], ['partial repair probe 1', [[2027, 7, 30], 3, [[2027, 10, 29], [2027, 10, 29]], 250000, 0.0425], [[2027, 10, 28], 2656.25]], ['partial repair probe 2', [[2025, 6, 30], 2, [[2025, 8, 31], [2025, 8, 29], [2025, 8, 31]], 250000, 0.0425], [[2025, 8, 28], 1741.32]], ['normal control 1', [[2030, 6, 17], 1, [], 250000, 0.0425], [[2030, 7, 17], 885.42]], ['normal control 2', [[2023, 7, 12], 1, [], 1000000, 0.0125], [[2023, 8, 14], 1145.83]], ['normal control 3', [[2021, 8, 16], 1, [[2021, 9, 26], [2021, 9, 29], [2021, 9, 26]], 1000000, 0.053], [[2021, 9, 16], 4563.89]], ['normal control 4', [[2027, 6, 17], 2, [[2027, 8, 28], [2027, 8, 27], [2027, 8, 29]], 250000, 0.0125], [[2027, 8, 17], 529.51]]], [['regression end-end target 1', [[2028, 3, 31], 6, [[2028, 9, 30], [2028, 9, 30], [2028, 9, 29]], 1000000, 0.0425], [[2028, 9, 28], 21368.06]], ['regression end-end target 2', [[2029, 8, 31], 6, [[2030, 2, 28]], 250000, 0.053], [[2030, 2, 27], 6625.0]], ['partial repair probe 1', [[2030, 10, 31], 3, [[2031, 1, 31], [2031, 1, 27], [2031, 1, 31]], 1000000, 0.0425], [[2031, 1, 30], 10743.06]], ['partial repair probe 2', [[2020, 11, 30], 2, [[2021, 1, 29], [2021, 1, 29], [2021, 1, 30]], 1000000, 0.0425], [[2021, 1, 28], 6965.28]], ['normal control 1', [[2024, 1, 15], 3, [], 250000, 0.0125], [[2024, 4, 15], 789.93]], ['normal control 2', [[2022, 10, 20], 6, [[2023, 4, 30], [2023, 4, 29]], 250000, 0.053], [[2023, 4, 20], 6698.61]], ['normal control 3', [[2027, 9, 21], 12, [[2028, 9, 26]], 250000, 0.053], [[2028, 9, 21], 13470.83]], ['normal control 4', [[2021, 3, 3], 12, [[2022, 3, 30], [2022, 3, 29], [2022, 3, 29]], 250000, 0.0425], [[2022, 3, 3], 10772.57]]], [['regression end-end target 1', [[2020, 12, 31], 1, [[2021, 1, 28], [2021, 1, 28], [2021, 1, 28]], 1000000, 0.0125], [[2021, 1, 29], 1006.94]], ['regression end-end target 2', [[2024, 4, 30], 2, [[2024, 6, 30], [2024, 6, 26], [2024, 6, 28]], 250000, 0.053], [[2024, 6, 27], 2134.72]], ['partial repair probe 1', [[2022, 7, 29], 3, [[2022, 10, 31], [2022, 10, 31], [2022, 10, 30]], 250000, 0.053], [[2022, 10, 28], 3349.31]], ['partial repair probe 2', [[2022, 2, 28], 1, [[2022, 3, 31], [2022, 3, 29]], 1000000, 0.0125], [[2022, 3, 30], 1041.67]], ['normal control 1', [[2020, 11, 10], 2, [[2021, 1, 27], [2021, 1, 28]], 1000000, 0.0425], [[2021, 1, 11], 7319.44]], ['normal control 2', [[2021, 5, 31], 1, [], 250000, 0.053], [[2021, 6, 30], 1104.17]], ['normal control 3', [[2029, 10, 22], 6, [], 1000000, 0.0125], [[2030, 4, 22], 6319.44]], ['normal control 4', [[2027, 4, 2], 2, [], 1000000, 0.0125], [[2027, 6, 2], 2118.06]]]]
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)

prompt:
Maturities fall on weekends and holidays at month end.

Inputs a start business day, tenor in months, holidays, principal and rate. If the start is the last business day of its month, maturity is the last business day of the target month; otherwise maturity is the start day clamped into the target month and adjusted modified following. Interest = principal*rate*days/360 rounded to 2. Return [maturity, interest].

split: open-access