债券价格 · ISDA(国际通用)
从收益到到期的固定收益证券价格
提交格式 yyyy-mm-dd(显示格式随系统区域设置)
提交格式 yyyy-mm-dd(显示格式随系统区域设置)
计算结果
点击「计算」查看输出
code
计算逻辑代码
以下为「ISDA国际通用」QuantLib 代码示例。
# 依赖版本:
# python==3.9
# QuantLib==1.43
from datetime import datetime, date as py_date
import traceback
import QuantLib as ql
# ============================================================
# 工具函数
# ============================================================
def _parse_date(s: str) -> ql.Date:
d = datetime.strptime(s.strip(), "%Y-%m-%d")
return ql.Date(d.day, d.month, d.year)
def _map_period(period: int):
mapping = {
0: (None, ql.NoFrequency),
1: (ql.Period(ql.Annual), ql.Annual),
2: (ql.Period(ql.Semiannual), ql.Semiannual),
3: (ql.Period(4, ql.Months), ql.EveryFourthMonth),
4: (ql.Period(ql.Quarterly), ql.Quarterly),
6: (ql.Period(ql.Bimonthly), ql.Bimonthly),
12: (ql.Period(ql.Monthly), ql.Monthly),
}
if period not in mapping:
raise ValueError(f"不支持的 Period: {period}")
return mapping[period]
def _map_basis(basis: int):
mapping = {
0: ql.ActualActual(ql.ActualActual.ISDA), # 或保持 ISMA,需与业务确认
1: ql.Thirty360(ql.Thirty360.USA),
2: ql.Actual360(),
3: ql.Actual365Fixed(),
4: ql.Thirty360(ql.Thirty360.BondBasis), # PSA 通常对应 BondBasis,而非 European
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(), # ICMA 语义需确认,可能需要特殊处理
11: ql.Thirty360(ql.Thirty360.EurobondBasis), # 或 European,视 QuantLib 版本别名
12: ql.Actual365Fixed(), # ISDA 语义需确认
13: ql.Business252(), # 必须补充
}
if basis not in mapping:
raise ValueError(f"暂不支持的 Basis: {basis}")
return mapping[basis]
# ============================================================
# 核心计算函数(QuantLib 原生口径)
# ============================================================
def qjquant_calu_bndprice(
yield_var: float,
coupon_var: float,
settle_var: str,
maturity_var: str,
period_var: int = 2,
basis_var: int = 0,
):
try:
# 参数校验
if coupon_var < 0:
return {"ok": False, "msg": "息票率不能为负"}
settle_date = _parse_date(settle_var)
maturity_date = _parse_date(maturity_var)
if settle_date >= maturity_date:
return {"ok": False, "msg": "结算日必须早于到期日"}
coupon_period, freq = _map_period(period_var)
day_counter = _map_basis(basis_var)
if period_var == 0:
# ========== 零息债 ==========
bond = ql.ZeroCouponBond(
settlementDays=0,
calendar=ql.NullCalendar(),
faceAmount=100.0,
maturityDate=maturity_date,
paymentConvention=ql.Unadjusted,
redemption=100.0,
issueDate=settle_date,
)
price = bond.cleanPrice(
yield_var, day_counter, ql.Compounded, ql.Annual, settle_date
)
accrued = 0.0
else:
coupon_period, freq = _map_period(period_var)
issue_date = maturity_date
while issue_date >= settle_date:
issue_date = issue_date - coupon_period
schedule = ql.Schedule(
issue_date, maturity_date, coupon_period,
ql.NullCalendar(), ql.Unadjusted, ql.Unadjusted,
ql.DateGeneration.Forward, False,
)
bond = ql.FixedRateBond(
settlementDays=0, faceAmount=100.0,
schedule=schedule, coupons=[coupon_var],
paymentDayCounter=day_counter,
)
compounding_freq = ql.Semiannual if basis_var <= 7 else freq
price = bond.cleanPrice(
yield_var, day_counter, ql.Compounded, compounding_freq, settle_date,
)
# ---- 应计利息:MATLAB 用 Actual/Actual 天数比 ----
def ql_to_py(d):
return py_date(d.year(), d.month(), d.dayOfMonth())
last_coupon = schedule[0] # 上一个票息日
next_coupon = schedule[1] # 下一个票息日
A = (ql_to_py(settle_date) - ql_to_py(last_coupon)).days
D = (ql_to_py(next_coupon) - ql_to_py(last_coupon)).days
coupon_amount = 100.0 * coupon_var / period_var
accrued = coupon_amount * A / D if D else 0.0
return {
"ok": True,
"price": round(price, 4),
"accrued_int": 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:附息债(半年付息,普通附息债场景)")
print("=" * 60)
r1 = qjquant_calu_bndprice(
yield_var=0.04,
coupon_var=0.05,
settle_var="1997-01-20",
maturity_var="2002-06-15",
period_var=2,
basis_var=0,
)
print(r1)
print()
print("=" * 60)
print("示例 2:附息债(年付息,基数为 30/360 USA)")
print("=" * 60)
r2 = qjquant_calu_bndprice(
yield_var=0.035,
coupon_var=0.045,
settle_var="2024-03-15",
maturity_var="2029-06-20",
period_var=1,
basis_var=1,
)
print(r2)
print()
print("=" * 60)
print("示例 3:零息债(basis=0,Actual/Actual)")
print("=" * 60)
r3 = qjquant_calu_bndprice(
yield_var=0.025,
coupon_var=0.0,
settle_var="2024-03-15",
maturity_var="2026-06-20",
period_var=0,
basis_var=0,
)
print(r3)
print()
print("=" * 60)
print("示例 4:附息债(季付,Actual/365 Fixed)")
print("=" * 60)
r4 = qjquant_calu_bndprice(
yield_var=0.03,
coupon_var=0.04,
settle_var="2024-03-15",
maturity_var="2029-06-20",
period_var=4,
basis_var=3,
)
print(r4)