← 返回编程题库
coding-bond-ytm-bisect中等免费版2000ms未尝试

固定利率附息债券的周期到期收益率:单调递减下的二分求根

Periodic Yield To Maturity of a Fixed-Rate Coupon Bond via Bisection

开始编码

实现 solution(price: float, face: float, coupon: float, n_periods: int) -> float。给定一只固定利率附息债券:当前 clean price 为 price,面值 face,每期票息现金额 coupon(已预乘——coupon = coupon_rate * face),剩余票息期数为 n_periods。返回让折现现金流恰好等于 price 的**周期到期收益率(YTM)y**。债券在 t = 1, 2, ..., n_periods 各期支付 coupon,并在第 n_periods 期额外返还 face(所以第 n 期现金流是 coupon + face,两者按同一个折现因子 (1+y)**n 折现)。定价函数 P(y) = sum_{t=1..n} coupon / (1+y)**t + face / (1+y)**ny > -1 上严格递减。返回让 P(y) = pricey,绝对容差 1e-7。若输入不合规(price <= 0face <= 0coupon < 0、或 n_periods < 1)返回 float("nan")

solution(1000.0, 1000.0, 50.0, 10) 返回约 0.05face = 1000、每期票息现金 = 50(即票息率 5%)、剩余 10 期、clean price 等于面值——债券在平价交易,所以 YTM 等于票息率 y = 0.05solution(62.0921323..., 100.0, 0.0, 5) 返回约 0.10:零息债券(coupon = 0),面值 100、5 期、价格 100 / 1.10**5 ~= 62.09,反推 y = 0.10solution(92.9081..., 100.0, 3.0, 4) 返回约 0.05:4 期债券每期票息现金 3(票息率 3%)、价格约 92.9081(即 3/1.05 + 3/1.05**2 + 3/1.05**3 + 103/1.05**4,注意第 4 期票息和面值合并为 103,共用 1/1.05**4 折现),反推 YTM 为 5%——票息率低于 yield 时价格低于面值,标准的折价债。

关键形态是**在严格递减的价格曲线上对 y 二分**:P(y) 的每一项都是 c / (1+y)**tc > 0t >= 1),所以 dP/dy < 0y > -1 上恒成立。y -> -1+P -> +infy -> +infP -> 0,因此对任意 price > 0,方程 P(y) = price 都恰好有一个根。自适应地选取初始区间(lo = -0.5 起,若 P(lo) <= price 则把 lo 半步推向 -1;hi = 1 起,若 P(hi) >= price 则把 hi 翻倍),再二分至 hi - lo < 1e-9。两个 off-by-one 陷阱:(a) 把 P(y) 当成递增(于是选错半区间);(b) 把最后一期的票息和面值各自折现到 (1+y)**(n+1)(1+y)**n不是共用 (1+y)**n。两者都要避免。

函数骨架见 stubs/stub.py

实践背景

YTM 是固收交易台最基本的收益率指标:给定固定利率债券的市场价,反推让折现现金流等于该价格的唯一周期 yield。它是 duration、convexity、par-spread、价收曲线的输入端,是任何初级交易员闭着眼也要能反算出来的第一个量。定价函数没有闭式逆,工业界一律迭代求解——价收曲线单调(标准输入下严格递减)让二分成为教科书首选:基于符号的区间收缩绝对鲁棒。Newton 方法在实践中更快,但需要导数簿记 + 合适初值;二分用几次额外迭代换收敛保证,正是日终风险批量任务做净价校验时常用的解法。本题刻意以每期现金额 coupon(已经 coupon_rate * face)作为入参,而不是利率本身——这样定价器签名对零息(coupon = 0)、阶梯息(外部预聚合)以及任何让函数内部重新换算现金额会脆弱的变体都保持一致。

约束条件

  • 1 <= n_periods <= 5000;price、face 为有限浮点数,price > 0、face > 0;coupon 为 >= 0 的有限浮点数,表示每期票息**现金额**(已经是 coupon_rate * face——函数内部不要再乘 face)
  • 债券现金流形态固定:在 t = 1..n_periods 各期收到 `coupon`,并在第 n_periods 期额外收到 `face`(即第 n 期总现金流为 `coupon + face`,两者共用 `(1+y)**n` 折现)
  • 若输入不合规(price <= 0、face <= 0、coupon < 0、或 n_periods < 1)一律返回 float('nan');否则返回唯一满足 P(y) = price 的周期 YTM y > -1(P 在 (-1, +inf) 上严格递减,所以根存在且唯一,对任意 price > 0 都良好定义)
  • 输出为单个 float;比较器为 float,rel_tol = 1e-6、abs_tol = 1e-7,并启用 nan_equals_nan = true(NaN 是不合规输入的合约约定,不是错误)
  • 参考解复杂度:O(n_periods * (log((hi - lo) / 1e-9) + bracket_expansion)),内层 P(y) 评估为 O(n_periods)

样例

Case 1 · statement-example: par bond (coupon rate equals YTM)

输入: [1000,1000,50,10]

期望: 0.04999999969732016

票面 1000、每期票息 50(即票息率 5%)、10 期、价格等于面值,YTM 恰好等于票息率 0.05

Case 2 · statement-example: zero-coupon bond at 10% yield

输入: [62.0921323059155,100,0,5]

期望: 0.10000000020954758

零息债:面值 100、5 期、10% 周期收益率 → 价格 ≈ 62.09,YTM 恢复为 0.10

Case 3 · statement-example: discount bond (coupon < ytm)

输入: [92.90809899167526,100,3,4]

期望: 0.04999999969732016

折价债:面值 100、票息 3、4 期、YTM 0.05 → price < 面值

最近提交

还没有提交记录。

编码区

实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。

加载编辑器...
计时0:00

默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。

Case 1 · statement-example: par bond (coupon rate equals YTM)

输入: [1000,1000,50,10]

期望: 0.04999999969732016

票面 1000、每期票息 50(即票息率 5%)、10 期、价格等于面值,YTM 恰好等于票息率 0.05

Case 2 · statement-example: zero-coupon bond at 10% yield

输入: [62.0921323059155,100,0,5]

期望: 0.10000000020954758

零息债:面值 100、5 期、10% 周期收益率 → 价格 ≈ 62.09,YTM 恢复为 0.10

Case 3 · statement-example: discount bond (coupon < ytm)

输入: [92.90809899167526,100,3,4]

期望: 0.04999999969732016

折价债:面值 100、票息 3、4 期、YTM 0.05 → price < 面值