定期存单应计利息 · ISDA(国际通用)
给定结算日、到期日等计算应计利息
根据存单息票率、结算日、到期日、签发日及日计数基准计算定期存单的应计利息。
格式 yyyy-mm-dd
格式 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_cdai(
coupon_rate: float,
settle_date: str,
maturity_date: str,
issue_date: str,
basis: int = 2, # 默认 2 = Actual/360
):
try:
# ---------- 参数校验 ----------
if coupon_rate < 0:
return {"ok": False, "msg": "息票率不能为负"}
settle_qd = _parse_date(settle_date)
maturity_qd = _parse_date(maturity_date)
issue_qd = _parse_date(issue_date)
if issue_qd >= settle_qd:
return {"ok": False, "msg": "签发日必须早于结算日"}
if settle_qd >= maturity_qd:
return {"ok": False, "msg": "结算日必须早于到期日"}
day_counter = _map_basis(basis)
# ---------- 核心计算 ----------
# 定期存单应计利息(CD Accrued Interest)
# 公式:accrued = face * coupon_rate * yearFraction(issue, settle)
# 注意:CD 通常按面值 100 计算应计利息,但这里按“每 100 面值”的利息返回。
# 接口不传 face,因此以 100 为隐含面值,返回每 100 面值的应计利息。
FACE = 100.0
# 使用 QuantLib 的 yearFraction 计算从签发日到结算日的应计年化比例
# 部分 basis(如 Actual/Actual ISMA)需要提供参考期,CD 通常用 Issue-Maturity 作为参考期
if basis in (0, 8):
# Actual/Actual (ISMA) 对 CD 使用签发日至到期日作为参考期
yf = day_counter.yearFraction(issue_qd, settle_qd, issue_qd, maturity_qd)
else:
yf = day_counter.yearFraction(issue_qd, settle_qd)
accrued = FACE * coupon_rate * yf
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:实际/360(默认,最常用的 CD 口径)")
print("=" * 60)
r1 = qjquant_calu_cdai(
coupon_rate=0.05,
settle_date="2024-06-15",
maturity_date="2024-12-15",
issue_date="2024-01-15",
basis=2,
)
print(r1)
print()
print("=" * 60)
print("示例 2:实际/实际(ISDA)")
print("=" * 60)
r2 = qjquant_calu_cdai(
coupon_rate=0.05,
settle_date="2024-06-15",
maturity_date="2024-12-15",
issue_date="2024-01-15",
basis=0,
)
print(r2)
print()
print("=" * 60)
print("示例 3:30/360(SIA)")
print("=" * 60)
r3 = qjquant_calu_cdai(
coupon_rate=0.05,
settle_date="2024-06-15",
maturity_date="2024-12-15",
issue_date="2024-01-15",
basis=1,
)
print(r3)
print()
print("=" * 60)
print("示例 4:实际/365 Fixed")
print("=" * 60)
r4 = qjquant_calu_cdai(
coupon_rate=0.05,
settle_date="2024-06-15",
maturity_date="2024-12-15",
issue_date="2024-01-15",
basis=3,
)
print(r4)
print()
print("=" * 60)
print("示例 5:实际/实际(ICMA,带参考期)")
print("=" * 60)
r5 = qjquant_calu_cdai(
coupon_rate=0.05,
settle_date="2024-06-15",
maturity_date="2024-12-15",
issue_date="2024-01-15",
basis=8,
)
print(r5)