QuantLib与PYOMO连续复利到期收益率计算结果差异排查
债券到期收益率(YTM)计算:QuantLib与PYOMO连续复利结果差异问题
我在计算债券现金流的到期收益率时,发现PYOMO求解的连续复利收益率与QuantLib结果存在13bp的显著差异,但年复利结果差异控制在1bp以内。具体操作流程如下:
- 基于日期和金额向量创建BondLeg并指定债券全价(dirty_value)
- 调用
ql.Cashflows.yieldRate分别计算年复利(Annually Compounding)和连续复利(Continuous Compounding)到期收益率 - 采用与收益率计算一致的Actual365Fixed日计数基准生成年分数(yearFraction)
- 使用PYOMO的ipopt非线性优化求解器,结合年分数、现金流金额和全价求解到期收益率
代码实现
导入模块
import numpy as np import QuantLib as ql import pyomo.environ as pyo from pyomo.opt import SolverFactory ql.Settings.instance().evaluationDate = ql.Date(30,6,2023)
现金流与全价
dates = [ql.Date(14,11,2023), ql.Date(14,11,2024), ql.Date(14,11,2025), ql.Date(16,11,2026), ql.Date(15,11,2027), ql.Date(14,11,2028), ql.Date(14,11,2029), ql.Date(14,11,2030), ql.Date(14,11,2031), ql.Date(15,11,2032)] amounts = [84070, 84070, 84070, 84537.05555555558, 65131.50532953604, 65131.50532953604, 65312.930135468014, 65312.930135468014, 65312.930135468014, 1065494.3549413998] dirty_val = 1050876.388888889
QuantLib计算实现
BondLeg = ql.Leg([ql.SimpleCashFlow(amt, dt) for dt,amt in zip(dates,amounts)]) ql_ra = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Compounded, ql.Annual, True) ql_rc = ql.CashFlows.yieldRate(BondLeg, dirty_val, ql.Actual365Fixed(), ql.Compounded, ql.Continuous, True)
生成年分数
year_fracs = [ql.Actual365Fixed().yearFraction(ql.Date(30,6,2023),dt) for dt in dates] periods = np.array([frac for frac in year_fracs]) p_int = np.int_(periods) p_frac = periods - p_int amount_vec = np.array(amounts)
PYOMO求解实现
年复利收益率计算
model_ra = pyo.ConcreteModel() # 决策变量 model_ra.ra = pyo.Var(domain = pyo.NonNegativeReals, initialize=0.05) ra = model_ra.ra # 目标函数 def ra_objective_rule(model_ra): return (amount_vec.dot(1/(((1+ra)**p_int)* (1+(ra*p_frac)))) - dirty_val)**2 model_ra.objf = pyo.Objective(rule=ra_objective_rule, sense=pyo.minimize) Solver = SolverFactory('ipopt') results_ra = Solver.solve(model_ra) print(results_ra) print(f'Objective Function = {model_ra.objf()}') print(f'ra = {ra()}')
连续复利收益率计算
model_rc = pyo.ConcreteModel() # 决策变量 model_rc.rc = pyo.Var(domain = pyo.NonNegativeReals, initialize=0.05) rc = model_rc.rc # 目标函数 def rc_objective_rule(model_rc): return (amount_vec.dot(np.array([pyo.exp(-p*rc) for p in periods])) - dirty_val)**2 model_rc.objf = pyo.Objective(rule=rc_objective_rule, sense=pyo.minimize) Solver = SolverFactory('ipopt') results_rc = Solver.solve(model_rc) print(results_rc) print(f'Objective Function = {model_rc.objf()}') print(f'rc = {rc()}')
结果对比
print(f'QuantLib - Annually Compounded Rate : {ql_ra:.4%}') print(f'QuantLib - Continuously Compounded Rate : {ql_rc:.4%}') print(f'PYOMO - Annually Compounded Rate : {ra.value:.4%}') print(f'PYOMO - Continuously Compounded Rate : {rc.value:.4%}')
输出结果:
QuantLib - Annually Compounded Rate : 7.3623%
QuantLib - Continuously Compounded Rate : 7.2315%PYOMO - Annually Compounded Rate : 7.3526%
PYOMO - Continuously Compounded Rate : 7.1039%
内容的提问来源于stack exchange,提问作者Amir Lakha
相关产品推荐
相关产品推荐

