到期付息贴现债券应计利息 · ISDA(国际通用)
给定结算日、到期日等计算应计利息
根据债券结算日、到期日、面值、贴现率等计算到期时支付的贴现证券的应计利息。
格式 yyyy-mm-dd
格式 yyyy-mm-dd
计算结果
点击「计算」查看输出
code
计算逻辑代码
以下为「ISDA国际通用」QuantLib 代码示例。
# 依赖版本:
# python==3.9
# QuantLib==1.43
from datetime import datetime
import traceback
import QuantLib as ql
# ============================================================
# 工具函数
# ============================================================
def _parse_date(s: str) -> ql.Date:
"""解析 'yyyy-mm-dd' 字符串为 ql.Date"""
d = datetime.strptime(s.strip(), "%Y-%m-%d")
return ql.Date(d.day, d.month, d.year)
def _map_basis(basis: int):
"""日计数基准编号 -> ql.DayCounter"""
mapping = {
0: ql.ActualActual(ql.ActualActual.ISDA),
1: ql.Thirty360(ql.Thirty360.USA),
2: ql.Actual360(),
3: ql.Actual365Fixed(),
4: ql.Thirty360(ql.Thirty360.BondBasis),
5: ql.Thirty360(ql.Thirty360.ISDA),
6: ql.Thirty360(ql.Thirty360.European),
7: ql.Actual365Fixed(),
8: ql.ActualActual(ql.ActualActual.ISMA),
9: ql.Actual360(),
10: ql.Actual365Fixed(),
11: ql.Thirty360(ql.Thirty360.EurobondBasis),
12: ql.Actual365Fixed(),
13: ql.Business252(),
}
if basis not in mapping:
raise ValueError(f"暂不支持的 Basis: {basis}")
return mapping[basis]
# ============================================================
# 核心计算函数
# ============================================================
def qjquant_calu_acrudisc(
settle_date: str,
maturity_date: str,
face: float,
discount: float,
period: int = 2,
basis: int = 0,
):
try:
def _period_to_months(p: int):
"""acrudisc 专用:避开 ql.Period(Frequency),只用 (Integer, TimeUnit)。"""
m = {1: 12, 2: 6, 3: 4, 4: 3, 6: 2, 12: 1}
if p not in m:
raise ValueError(f"不支持的 Period: {p}")
return m[p]
if face <= 0:
return {"ok": False, "msg": "面值必须大于 0"}
if discount < 0:
return {"ok": False, "msg": "贴现率不能为负"}
settle_qd = _parse_date(settle_date)
maturity_qd = _parse_date(maturity_date)
if settle_qd >= maturity_qd:
return {"ok": False, "msg": "结算日必须早于到期日"}
day_counter = _map_basis(basis)
# ---- 核心计算 ----
if period == 0:
# 零息:无周期,按年化比例线性分摊
if basis in (0, 8):
yf = ql.ActualActual(ql.ActualActual.ISDA).yearFraction(settle_qd, maturity_qd)
else:
yf = day_counter.yearFraction(settle_qd, maturity_qd)
accrued = face * discount * yf
else:
months = _period_to_months(period)
coupon_period = ql.Period(months, ql.Months) # ★ (Integer, TimeUnit)
prev_coupon_qd = maturity_qd - coupon_period
period_days = day_counter.dayCount(prev_coupon_qd, maturity_qd)
settle_days = day_counter.dayCount(settle_qd, maturity_qd)
if period_days <= 0:
return {"ok": False, "msg": "付息周期天数异常"}
year_fraction = settle_days / period_days
accrued = face * discount * year_fraction / period
if accrued < 0:
accrued = 0.0
return {
"ok": True,
"accru_interest": round(accrued, 4),
}
except ValueError as ve:
traceback.print_exc()
return {"ok": False, "msg": f"参数错误: {ve}"}
except Exception as e:
traceback.print_exc()
return {"ok": False, "msg": f"未知错误: {e}"}
# ============================================================
# 示例:复制本文件后直接运行
# ============================================================
if __name__ == "__main__":
print("=" * 60)
print("示例 1:半年期贴现债(period=2,实际/实际)")
print("=" * 60)
r1 = qjquant_calu_acrudisc(
settle_date="2024-05-15",
maturity_date="2024-11-15",
face=100.0,
discount=0.05,
period=2,
basis=0,
)
print(r1)
print()
print("=" * 60)
print("示例 2:一年期贴现债(period=1,30/360 USA)")
print("=" * 60)
r2 = qjquant_calu_acrudisc(
settle_date="2024-06-15",
maturity_date="2025-06-15",
face=100.0,
discount=0.04,
period=1,
basis=1,
)
print(r2)
print()
print("=" * 60)
print("示例 3:季付口径贴现债(period=4,实际/365 Fixed)")
print("=" * 60)
r3 = qjquant_calu_acrudisc(
settle_date="2024-02-15",
maturity_date="2024-05-15",
face=100.0,
discount=0.03,
period=4,
basis=3,
)
print(r3)
print()
print("=" * 60)
print("示例 4:零息口径(period=0,按年化比例线性分摊)")
print("=" * 60)
r4 = qjquant_calu_acrudisc(
settle_date="2024-03-15",
maturity_date="2025-03-15",
face=100.0,
discount=0.04,
period=0,
basis=0,
)
print(r4)