2. 固定收益基础
在进入 QuantLib 的定价与曲线构建之前,必须先建立一套“市场语言”与“现金流语言”的映射。固定收益产品的复杂性,往往不在于公式本身,而在于要素定义、计息惯例与报价方式之间的细微差异。同一只债券,在不同市场、不同计息基准下,现金流日期与金额可能完全不同,进而导致收益率与价格出现系统性偏差。
一、债券的核心要素:从合同到现金流
一只标准债券可以拆解为以下要素:面值(Notional)、票息率(Coupon Rate)、付息频率(Frequency)、起息日(Issue Date)、到期日(Maturity Date)、计息基准(Day Count)、付息日调整规则(Business Day Convention)以及是否含期权条款。QuantLib 中对应为 FaceAmount、CouponRate、Tenor、IssueDate、MaturityDate、DayCounter、Calendar 与 BusinessDayConvention。
其中最容易出错的是“计息基准”与“付息日调整规则”的组合。例如,一只按 Actual/Actual (ICMA) 计息、付息日为 Modified Following 的国债,其每个付息周期的应计利息天数并非简单等于日历天数,而是依据付息周期实际天数计算。若忽略这一点,在 QuantLib 中直接使用 Actual/365 构建,价格会出现明显偏差。
二、计息规则与市场惯例:Day Count 与 Business Day
计息规则决定了两个日期之间的“时间分数”(Year Fraction)。常见基准包括:
- Actual/Actual (ICMA):按付息周期实际天数计算,适用于多数国债与市政债。
- Actual/360:货币市场工具常用,如美国短期国债、商业票据。
- Actual/365 Fixed:部分欧洲债券与掉期使用。
- 30/360:公司债与部分机构债常用,假设每月30天、每年360天。
- Actual/Actual (ISDA):掉期与衍生品常用,按实际天数与年度天数比例计算。
付息日调整规则则决定当付息日落在非营业日时如何移动。常见规则有 Following、Modified Following、Preceding、Modified Preceding 与 Unadjusted。QuantLib 中通过 Calendar 与 BusinessDayConvention 联合控制。若调整规则与市场惯例不一致,会导致现金流日期整体偏移,进而影响贴现因子取值。
三、收益率与价格关系:从 YTM 到曲线
收益率与价格呈反向关系,但并非线性。对于固定利率债券,价格对收益率的敏感度由久期(Duration)与凸性(Convexity)刻画。到期收益率(YTM)是使债券未来现金流现值等于当前价格的单一贴现率,隐含了“收益率曲线平坦”与“再投资收益率等于YTM”两个假设。
在 QuantLib 中,常用 FixedRateBond 与 DiscountingBondEngine 计算净价与全价。全价 = 净价 + 应计利息。应计利息由 DayCounter 与 IssueDate、SettlementDate 共同决定。以下代码片段展示如何构建一只债券并计算其净价:
import QuantLib as ql
today = ql.Date(15, 1, 2025)
ql.Settings.instance().evaluationDate = today
calendar = ql.UnitedStates(ql.UnitedStates.GovernmentBond)
day_counter = ql.ActualActual(ql.ActualActual.ISDA)
settlement_days = 1
settlement_date = calendar.advance(today, settlement_days, ql.Days)
issue_date = ql.Date(15, 1, 2020)
maturity_date = ql.Date(15, 1, 2030)
coupon_rate = 0.03
frequency = ql.Semiannual
schedule = ql.Schedule(issue_date, maturity_date,
ql.Period(frequency),
calendar,
ql.ModifiedFollowing,
ql.ModifiedFollowing,
ql.DateGeneration.Backward,
False)
bond = ql.FixedRateBond(settlement_days, 100.0, schedule,
[coupon_rate], day_counter)
flat_curve = ql.FlatForward(settlement_date, 0.035, day_counter)
bond_engine = ql.DiscountingBondEngine(
ql.YieldTermStructureHandle(flat_curve))
bond.setPricingEngine(bond_engine)
print("Clean Price:", bond.cleanPrice())
print("Accrued Amount:", bond.accruedAmount())
print("Dirty Price:", bond.dirtyPrice())
运行后可得净价、应计利息与全价。若将 day_counter 改为 ql.Thirty360(),净价会发生变化,这正是计息规则对定价影响的直接体现。
四、常见品种与市场惯例对照
不同债券品种在计息、付息与报价上存在显著差异。下表汇总了主要品种的典型惯例,便于在 QuantLib 中快速选择对应参数:
| 品种 | 计息基准 | 付息频率 | 报价方式 | 典型市场 |
|---|---|---|---|---|
| 美国国债 | Actual/Actual (ICMA) | 半年 | 净价 + 应计 | 美国 |
| 德国国债 | Actual/Actual (ICMA) | 年 | 净价 + 应计 | 欧洲 |
| 中国国债 | Actual/Actual | 年或半年 | 净价 + 应计 | 中国 |
| 美国公司债 | 30/360 | 半年 | 净价 + 应计 | 美国 |
| 欧洲商业票据 | Actual/360 | 贴现 | 贴现率 | 欧洲 |
| 利率掉期 | Actual/360 或 30/360 | 季度或半年 | 互换利率 | 全球 |
DayCounter、BusinessDayConvention 与 DateGeneration。这三者共同决定现金流日期与金额,是定价准确性的基石。
五、误区与复盘:常见陷阱
初学者常犯的错误包括:将净价直接当作全价输入定价引擎;忽略结算日与起息日之间的应计利息;在非营业日调整规则上使用 Unadjusted 导致现金流日期偏移;以及将不同市场的计息基准混用。以下是一个典型复盘场景:
- 问题:某学员用 Actual/365 对一只美国国债定价,结果净价偏高约 0.3%。
- 原因:美国国债使用 Actual/Actual (ICMA),付息周期内天数计算方式不同,导致应计利息与贴现因子均出现偏差。
- 修正:将
DayCounter改为ql.ActualActual(ql.ActualActual.ISDA),并确认Schedule的DateGeneration为 Backward。 - 验证:对比 Bloomberg 或 Reuters 的净价与应计利息,误差应小于 0.01%。
FixedRateBond 默认使用面值 100,若实际面值为 1000 或 10000,需在构造时显式传入 FaceAmount,否则价格与应计利息会按 100 面值计算,导致数量级错误。
掌握上述要素、计息规则与市场惯例后,才能在后续章节中正确构建收益率曲线、校准贴现因子,并进一步完成利率互换、债券期权等复杂产品的定价。固定收益的“基础”并非简单概念,而是贯穿整个定价流程的约束条件。