到期含息价格

到期含息价格 prmat · ISDA(国际通用)
计算到期一次性还本付息证券的价格与应计利息。 零息债或纯贴现证券可将 CouponRate 设为 0。
提交格式 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


# ============================================================
# 工具函数(原 util 模块内联)
# ============================================================
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_period(period: int):
    """年付息次数 -> (ql.Period, ql.Frequency)"""
    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):
    """日计数基准编号 -> 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_prmat(
    settle_var: str,
    maturity_var: str,
    issue_var: str,
    face_var: float,
    coupon_var: float,
    yield_var: float,
    basis_var: int = 0,
):
    try:
        # ---------- 参数校验 ----------
        if face_var <= 0:
            return {"ok": False, "msg": "面值必须为正"}
        if coupon_var < 0:
            return {"ok": False, "msg": "息票率不能为负"}

        settle_date   = _parse_date(settle_var)
        maturity_date = _parse_date(maturity_var)
        issue_date    = _parse_date(issue_var)

        if settle_date >= maturity_date:
            return {"ok": False, "msg": "结算日必须早于到期日"}
        if issue_date > settle_date:
            return {"ok": False, "msg": "发行日必须早于或等于结算日"}

        dc = _map_basis(basis_var)

        # ---------- 计算年分数(与 prmat 公式一致) ----------
        T_issue_to_mat = dc.yearFraction(issue_date, maturity_date)
        T_issue_to_set = dc.yearFraction(issue_date, settle_date)

        # 到期总赎回金额 = 面值 + 累计利息(单利)
        redemption_amount = face_var * (1.0 + coupon_var * T_issue_to_mat)

        # 应计利息
        accru_interest = face_var * coupon_var * T_issue_to_set

        # ---------- 关键:设置 QuantLib 评估日为结算日 ----------
        ql.Settings.instance().evaluationDate = settle_date

        # ---------- 手动构造到期现金流 ----------
        cashflow = ql.SimpleCashFlow(redemption_amount, maturity_date)

        # ---------- 构建单利折现曲线 ----------
        curve = ql.FlatForward(
            settle_date,
            ql.QuoteHandle(ql.SimpleQuote(yield_var)),
            dc,
            ql.Simple,
            ql.Annual,
        )
        curve_handle = ql.YieldTermStructureHandle(curve)

        # ---------- 用 CashFlows.npv 折现 ----------
        dirty_price = ql.CashFlows.npv(
            [cashflow],
            curve_handle,
            True,
            settle_date,
            settle_date,
        )

        # ---------- 净价 = 全价 - 应计利息 ----------
        clean_price = dirty_price - accru_interest

        return {
            "ok": True,
            "price": round(clean_price, 4),
            "accrued_int": round(accru_interest, 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_prmat(
        settle_var="2024-03-15",
        maturity_var="2029-06-20",
        issue_var="2024-01-01",
        face_var=100.0,
        coupon_var=0.05,
        yield_var=0.06,
        basis_var=0,
    )
    print(r1)

    print()
    print("=" * 60)
    print("示例 2:零息债(coupon=0,实际/实际)")
    print("=" * 60)
    r2 = qjquant_calu_prmat(
        settle_var="2024-03-15",
        maturity_var="2026-06-20",
        issue_var="2024-01-01",
        face_var=100.0,
        coupon_var=0.0,
        yield_var=0.04,
        basis_var=0,
    )
    print(r2)

    print()
    print("=" * 60)
    print("示例 3:附息,30/360 USA(basis=1)")
    print("=" * 60)
    r3 = qjquant_calu_prmat(
        settle_var="2024-03-15",
        maturity_var="2029-06-20",
        issue_var="2024-01-01",
        face_var=100.0,
        coupon_var=0.05,
        yield_var=0.05,
        basis_var=1,
    )
    print(r3)

    print()
    print("=" * 60)
    print("示例 4:附息,实际/365 Fixed(basis=3)")
    print("=" * 60)
    r4 = qjquant_calu_prmat(
        settle_var="2024-06-15",
        maturity_var="2027-12-31",
        issue_var="2024-01-01",
        face_var=100.0,
        coupon_var=0.03,
        yield_var=0.035,
        basis_var=3,
    )
    print(r4)