使用QuantLib从即期利率构建贴现曲线遇浮点数期限错误求助
问题根源
你遇到的TypeError是因为QuantLib的Period构造函数不接受浮点数作为第一个参数。看报错里的原型提示:Period::Period(Integer,TimeUnit),第一个参数必须是整数类型,但你的spot_tenors里有0.5、1.5这类非整数值,直接用Period(n, Years)肯定会触发类型错误。
解决思路
你的即期利率是按半年间隔设置的,最直接的修正方式是把年份转成对应的月份数(毕竟0.5年=6个月,1.5年=18个月),用Months作为时间单位来构造Period,这样就能用整数参数了。
具体修正步骤
修正期限节点的创建:
把原来的这行代码:nodes = [today + Period(n, Years) for n in spot_tenors]修改为:
nodes = [today + ql.Period(int(n * 12), ql.Months) for n in spot_tenors]这里用
n * 12把年数转成月数,再转成整数,完美匹配Period的参数要求。利率格式修正(重要!):
你的spots列表里的数值是百分比(比如5.25代表5.25%),但QuantLib的ZeroCurve要求利率是小数形式(比如0.0525),所以必须先转换:spots = [s / 100.0 for s in spots]不做这一步的话,构造的曲线会把5.25当成525%的利率,计算出来的债券价格完全不符合预期。
修正后的完整代码
把这两处修改后,代码就能正常运行了,我帮你整理了完整版本:
import matplotlib matplotlib.use('macosx') import matplotlib.pyplot as plt import QuantLib as ql # 债券创建逻辑保持不变 issueDate = ql.Date(15, 1, 2015) maturityDate = ql.Date(15, 1, 2025) tenor = ql.Period(ql.Semiannual) calendar = ql.UnitedStates() businessConvention = ql.Unadjusted dateGeneration = ql.DateGeneration.Backward monthEnd = False schedule = ql.Schedule(issueDate, maturityDate, tenor, calendar, businessConvention, businessConvention, dateGeneration, monthEnd) dayCount = ql.Thirty360() couponRate = .06 coupons = [couponRate] settlementDays = 0 faceValue = 100 bond = ql.FixedRateBond(settlementDays, faceValue, schedule, coupons, dayCount) today = ql.Date(30, ql.January, 2020) spot_tenors = [0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0] # 转换利率为小数格式 spots = [s / 100.0 for s in [0.0, 5.25, 5.43, 5.76, 6.02, 6.28, 6.55, 6.82, 6.87, 7.1, 7.21, 7.26, 7.31, 7.43, 7.48, 7.54, 7.67, 7.8, 7.79, 7.93, 8.07]] # 用月份构造正确的期限节点 nodes = [today + ql.Period(int(n * 12), ql.Months) for n in spot_tenors] discount_curve = ql.ZeroCurve(nodes, spots, ql.Actual360()) discount_handle = ql.YieldTermStructureHandle(discount_curve) bond.setPricingEngine(ql.DiscountingBondEngine(discount_handle)) # 可以打印债券价格验证 print("债券净价:", bond.cleanPrice())
补充说明
如果你的期限不是严格的半年倍数,比如有像1.2年这种非整数,也可以用ql.Period(int(n * 360), ql.Days)来构造,但要注意和你用的日计数惯例(这里是Actual360)保持一致,避免日期计算偏差。
内容的提问来源于stack exchange,提问作者TRex
相关产品推荐
相关产品推荐

