浮息债折现利差
浮动利率债券的折现利差
根据浮息债价格、报价利差、利率信息(RateInfo)、结算日与到期日,计算浮动利率债券的折现利差。RateInfo 由 StubRate(首个 stub 期利率)与 SpotRate(参考利率)组成。可选参数:每年付款频率 Reset、计息天数规则 Basis、最新浮动利率 LatestFloatingRate、是否调整现金流天数 AdjustCashFlowsBasis。
格式 yyyy-mm-dd
格式 yyyy-mm-dd
利率信息 RateInfo
可选参数
计算结果
点击「计算」查看输出
code
计算逻辑代码
以下为「ISDA国际通用」浮息债折现利差的 Python 代码示例(基于 QuantLib)。
# 依赖版本:
# python==3.9
# QuantLib==1.43
# scipy(用于 brentq)
import traceback
from datetime import datetime
import QuantLib as ql
from scipy.optimize import brentq
def qjquant_calu_floatdiscmargin(
price: float,
spread: float,
settle: str,
maturity: str,
stub_rate: float,
spot_rate: float,
latest_floating_rate: float = 0.0,
reset: int = 1,
basis: int = 0,
adjust_cash_flows_basis: int = 1,
):
try:
# ---------- 参数校验 ----------
if price <= 0:
return {"ok": False, "msg": "债券价格必须大于 0"}
if spread < 0:
return {"ok": False, "msg": "报价利差不能为负"}
if stub_rate < 0 or spot_rate < 0:
return {"ok": False, "msg": "利率不能为负"}
# ---------- 日期解析 ----------
try:
d1 = datetime.strptime(settle, "%Y-%m-%d")
d2 = datetime.strptime(maturity, "%Y-%m-%d")
except ValueError:
return {"ok": False, "msg": "日期格式必须为 YYYY-MM-DD"}
settle_date = ql.Date(d1.day, d1.month, d1.year)
maturity_date = ql.Date(d2.day, d2.month, d2.year)
if maturity_date <= settle_date:
return {"ok": False, "msg": "到期日必须晚于结算日"}
ql.Settings.instance().evaluationDate = settle_date
# ---------- 日历与计息天数 ----------
calendar = ql.NullCalendar()
day_counter_map = {
0: ql.ActualActual(ql.ActualActual.Bond),
1: ql.Thirty360(ql.Thirty360.BondBasis),
2: ql.Actual360(),
3: ql.Actual365Fixed(),
4: ql.Thirty360(ql.Thirty360.USA),
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.European),
12: ql.Actual365Fixed(),
13: ql.Actual365Fixed(),
}
day_counter = day_counter_map.get(basis, ql.ActualActual(ql.ActualActual.Bond))
# ---------- 付息频率 ----------
freq_map = {1: ql.Annual, 2: ql.Semiannual, 4: ql.Quarterly, 12: ql.Monthly}
frequency = freq_map.get(reset, ql.Annual)
tenor = ql.Period(frequency)
# ---------- 构建 Schedule ----------
schedule = ql.Schedule(
settle_date, maturity_date, tenor, calendar,
ql.Unadjusted, ql.Unadjusted,
ql.DateGeneration.Backward, False
)
# ---------- 预测曲线与贴现曲线 ----------
forecast_curve = ql.YieldTermStructureHandle(
ql.FlatForward(settle_date, spot_rate, day_counter)
)
# ---------- 构建 IborIndex ----------
index = ql.IborIndex(
"MockIbor", tenor, 0, ql.USDCurrency(), calendar,
ql.Unadjusted, False, day_counter, forecast_curve
)
# 只为首个 accrual start 添加一次 fixing,避免重复
first_accrual_start = schedule[0]
fixing_value = stub_rate if stub_rate > 0 else latest_floating_rate
index.addFixing(first_accrual_start, fixing_value)
# ---------- 构建浮息债 ----------
quoted_spread = spread / 10000.0
bond = ql.FloatingRateBond(
0, # settlementDays
100.0, # faceAmount
schedule, # schedule
index, # index
day_counter, # paymentDayCounter(位置参数,兼容版本差异)
fixingDays=0,
gearings=[1.0],
spreads=[quoted_spread],
caps=[],
floors=[],
inArrears=False,
redemption=100.0,
issueDate=settle_date,
)
# ---------- 折现利差求解 ----------
spread_simple_quote = ql.SimpleQuote(0.0)
spread_quote_handle = ql.QuoteHandle(spread_simple_quote)
spreaded_curve = ql.ZeroSpreadedTermStructure(
ql.YieldTermStructureHandle(
ql.FlatForward(settle_date, spot_rate, day_counter)
),
spread_quote_handle
)
discount_handle = ql.YieldTermStructureHandle(spreaded_curve)
bond.setPricingEngine(ql.DiscountingBondEngine(discount_handle))
def price_diff(dm):
spread_simple_quote.setValue(dm)
return bond.cleanPrice() - price
try:
discount_margin = brentq(price_diff, -0.5, 1.0, xtol=1e-10, maxiter=200)
except ValueError:
return {"ok": False, "msg": "无法在给定范围内求解折现利差,请检查输入参数"}
margin_bp = discount_margin * 10000.0
return {
"ok": True,
"margin": round(margin_bp, 4),
}
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_floatdiscmargin(
price=99.99,
spread=50,
settle="2024-03-15",
maturity="2029-03-15",
stub_rate=0.049,
spot_rate=0.05,
latest_floating_rate=0.0,
reset=1,
basis=0,
)
print(r1)
print()
print("=" * 60)
print("示例 2:浮息债折现利差(季度,30/360 USA)")
print("=" * 60)
r2 = qjquant_calu_floatdiscmargin(
price=98.50,
spread=75,
settle="2024-03-15",
maturity="2029-06-20",
stub_rate=0.048,
spot_rate=0.05,
reset=4,
basis=1,
)
print(r2)
print()
print("=" * 60)
print("示例 3:浮息债折现利差(半年,实际/365)")
print("=" * 60)
r3 = qjquant_calu_floatdiscmargin(
price=100.25,
spread=30,
settle="2024-06-01",
maturity="2027-06-01",
stub_rate=0.052,
spot_rate=0.05,
reset=2,
basis=3,
)
print(r3)
print()
print("=" * 60)
print("示例 4:浮息债折现利差(短期限,实际/360)")
print("=" * 60)
r4 = qjquant_calu_floatdiscmargin(
price=99.80,
spread=120,
settle="2024-03-15",
maturity="2025-03-15",
stub_rate=0.05,
spot_rate=0.05,
reset=1,
basis=2,
)
print(r4)