You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Actual365Fixed.NoLeap构建OIS曲线时闰年2月28日指数值为0的问题

QuantLib中Estr指数闰年2月28日Fixing值为0的问题

问题现象

使用QuantLib构建Estr指数的OIS曲线时,发现每逢闰年的2月28日,调用index.fixing(ql.Date(28,2,2024))返回值为0,但使用Euribor指数或其他日计数规则时无此问题。

异常代码(Estr+OIS曲线)

import QuantLib as ql

YieldTS = ql.RelinkableYieldTermStructureHandle()
index = ql.Estr(YieldTS)

helpers = []
for p,q in zip(['1M','50Y'], [0.02,0.02]):
    helperitem = ql.OISRateHelper(0, 
                                  ql.Period(p), 
                                  ql.QuoteHandle(ql.SimpleQuote(q)), 
                                  index)
    helpers.append(helperitem)

dayCounter = ql.Actual365Fixed(ql.Actual365Fixed.NoLeap)

curve = ql.PiecewiseKrugerZero(0, index.fixingCalendar(), helpers, dayCounter)
YieldTS.linkTo(curve)

index.fixing(ql.Date(28,2,2024))  # 闰年2月28日返回0

正常代码(Euribor+Fra曲线)

import QuantLib as ql

YieldTS = ql.RelinkableYieldTermStructureHandle()

euribor = ql.Euribor(ql.Period('6M'), YieldTS)
helpers = []
for p,q in zip([1,5], [0.02,0.02]):
    helperitem = ql.FraRateHelper(
                                    ql.QuoteHandle(ql.SimpleQuote(q)),
                                    p, 
                                    euribor)
    helpers.append(helperitem)

curve = ql.PiecewiseKrugerZero(0, euribor.fixingCalendar(), helpers, dayCounter)   
YieldTS.linkTo(curve)
euribor.fixing(ql.Date(28,2,2024))  # 返回预期值0.02

原因分析

问题出在日计数规则不匹配+闰年处理逻辑冲突:

  • Estr指数的官方默认日计数规则是Actual/360,但你构建曲线时使用了Actual365Fixed(NoLeap)——该规则会忽略闰年,强制每年按365天计算,不承认闰年的2月29日。
  • 当计算闰年2月28日的Estr隔夜fixing时,需要计算从2月28日到下一个工作日(2月29日)的天数,但NoLeap规则不认可2月29日的存在,导致天数计算为0,最终推导的利率为0。
  • Euribor例子中正常,是因为Euribor是期限型指数(你用了6M期限),计算的是一段时期的远期利率,单日天数异常的影响被稀释,且FraRateHelper的处理逻辑对这种单日问题不敏感。

解决方法

解决核心是让曲线的日计数规则与指数匹配,或修改闰年处理逻辑:

方法1:匹配Estr的默认日计数规则(Actual/360)

import QuantLib as ql

YieldTS = ql.RelinkableYieldTermStructureHandle()
# 显式指定Estr日计数为Actual/360(默认值,可省略,此处为明确逻辑)
index = ql.Estr(YieldTS, ql.Actual360())

helpers = []
for p,q in zip(['1M','50Y'], [0.02,0.02]):
    helperitem = ql.OISRateHelper(0, 
                                  ql.Period(p), 
                                  ql.QuoteHandle(ql.SimpleQuote(q)), 
                                  index)
    helpers.append(helperitem)

# 曲线使用与指数一致的Actual/360日计数
dayCounter = ql.Actual360()

curve = ql.PiecewiseKrugerZero(0, index.fixingCalendar(), helpers, dayCounter)
YieldTS.linkTo(curve)

print(index.fixing(ql.Date(28,2,2024)))  # 返回预期值0.02

方法2:改用普通Actual365Fixed(考虑闰年)

如果坚持使用Actual365Fixed规则,去掉NoLeap参数即可:

# 改用普通Actual365Fixed(会识别闰年的366天)
dayCounter = ql.Actual365Fixed()
curve = ql.PiecewiseKrugerZero(0, index.fixingCalendar(), helpers, dayCounter)

内容的提问来源于stack exchange,提问作者vpvp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:03:18