2. 附息债券现金流与定价

任务说明

构建一只附息债券的现金流表:每期票息 + 到期本金,然后用给定的即期贴现因子对每笔现金流贴现并加总,得到债券理论价格。同时计算应计利息与全价,便于与市场报价(净价)对照。

实现思路

  • 输入:面值、票息率、付息频率、剩余期数、每期贴现因子。
  • 现金流表:第 1..n-1 期只有票息,第 n 期票息 + 面值。
  • 理论价格 = Σ 现金流t × 贴现因子t。
  • 应计利息按“上一付息日到结算日”的占比计算,全价 = 净价 + 应计利息。

核心代码

from dataclasses import dataclass

@dataclass
class Bond:
    face: float          # 面值
    coupon_rate: float   # 年票息率
    freq: int            # 每年付息次数
    periods: int         # 剩余付息期数

    def cashflows(self):
        """返回 [(期数, 现金流)],最后一期含本金。"""
        c = self.face * self.coupon_rate / self.freq
        flows = [(t, c) for t in range(1, self.periods)]
        flows.append((self.periods, c + self.face))
        return flows

    def price(self, discount_factors):
        """用即期贴现因子对现金流贴现并加总。"""
        assert len(discount_factors) == self.periods, "贴现因子数量须等于期数"
        return sum(cf * df for (_, cf), df in zip(self.cashflows(), discount_factors))

    def accrued_interest(self, days_since_last, days_in_period):
        """应计利息:票息 × 已过天数占比。"""
        c = self.face * self.coupon_rate / self.freq
        return c * days_since_last / days_in_period

if __name__ == "__main__":
    bond = Bond(face=100.0, coupon_rate=0.06, freq=2, periods=4)
    # 4 期即期贴现因子(示例输入)
    dfs = [0.9709, 0.9426, 0.9151, 0.8885]

    flows = bond.cashflows()
    print("期数  现金流   贴现因子   现值")
    for (t, cf), df in zip(flows, dfs):
        print(f"{t:>3}  {cf:>7.3f}  {df:>8.4f}  {cf*df:>8.4f}")

    clean = bond.price(dfs)
    ai = bond.accrued_interest(days_since_last=45, days_in_period=180)
    print(f"\n理论净价 = {clean:.4f}")
    print(f"应计利息 = {ai:.4f}")
    print(f"全价     = {clean + ai:.4f}")

运行与验证

python bond_pricing.py

判定标准:

  • 现金流表共 4 行,前 3 行为票息 3.000,第 4 行为 103.000(票息 + 面值)。
  • 理论净价等于各行“现值”之和,即 2.9127 + 2.8278 + 2.7453 + 91.5155 = 100.0013(由代码逻辑唯一确定)。
  • 应计利息 = 3.000 × 45/180 = 0.7500,全价 = 净价 + 0.7500。

关键点

贴现因子数量必须与剩余期数一致,否则 assert 会报错;票息按 面值 × 年票息率 / 付息频率 计算,最后一期现金流需加上面值。若贴现因子来自即期利率曲线,可先用 df = 1 / (1 + z_t)**t 生成后再传入 price。