债券量化:NS收益率曲线

  • Nelson-Siegel 模型由Charles Nelson 和Andrew Siegel提出的,用参数表示瞬时远期利率函数,进而推导出即期利率的函数形式。通常情况下需要确定代表各个期限样本券,然后通过对样本券价格做最小误差确定参数。本文展示一种更加简便的方法,直接使用中债每日发布的关键期限点上的即期收益率,反推参数,并用时间序列对函数中代表水平、斜率和曲度的参数做预测,进而预估下一期的即期曲线水平。

  • 首先定义DNS模型,输入关键期限点的即期收益率和衰减率lambda。
class dns_model(base_model):

    def __init__(self,curve_code:str,beg_dt:str,end_dt:str):
        super().__init__(curve_code,beg_dt,end_dt)

    def betas(self,lamb):
        """
        calc history beta from raw data.
        :param dfs: col <- tenor; row <- time series.
        :param lamb: decay rate
        :return:
        """
        t_arr= self.hist_yield.columns.values
        t = np.where(t_arr == 0, 1e-5, t_arr)
        del t_arr
        fac1=(1-np.e**(-lamb*t))/(lamb*t)
        fac2=fac1-np.e**(-lamb*t)

        X = np.concatenate(([fac1], [fac2]), axis=0).T
        X = np.c_[np.ones(X.shape[0]), X]
        Y = self.hist_yield.T.values

        params = np.linalg.pinv(X.T @ X) @ X.T @ Y
        resid = Y - X @ params

        return params.T,resid.T

    def rmses(self,lamb1):
        _,resid=self.betas(lamb1)
        Resids=np.array(resid)
        rmses=np.sqrt(np.sum((Resids**2)/Resids.shape[1],axis=1))
        return sum(rmses)
  •  定义初始的lambda参数,使用scipy优化器,得到rmse值最小的参数值
from scipy.optimize import minimize,Bounds
lamba_ini = 10.001 / 2
lambda_opt_dnss = minimize(dnss_func.rmses, (lamba_ini,lamba_ini), method='powell', bounds=Bounds(0.001, 10)).x
  •  定义一个预测模型,输入上一个步骤中求得的最优lambda值。在自定义的数据回看期内,求解得到对应的3列beta值序列,对这3个序列,使用时间序列的预测方法计算下一期的beta值。代入NS公式后,得到新一期的即期收益率值。
    def forcast_model(self,startdate,enddate):
        
        ## -- trace back 1 year.
        t_arr = self.yield_data.OutstandingPeriod.values
        t = np.where(t_arr == 0, 1e-5, t_arr)

        model = dns_model(self.spot_code,startdate,enddate)
        lamb = 3.82027815
        betas, _ = model.betas(lamb)
        fac1 = (1 - np.e ** (-lamb * t)) / (lamb * t)
        fac2 = fac1 - np.e ** (-lamb * t)
        X = np.concatenate(([fac1], [fac2]), axis=0).T

        pred_beta = []
        for b in range(betas.shape[1]):
            if b>=2:
                model_fit = ARIMA(betas[:, b], order=(1, 1, 1)).fit()
            else:
                model_fit = ARIMA(betas[:,b],order=(1,0,0)).fit()
                pred_beta.append(model_fit.predict(start=len(betas),end=len(betas)+self.expt_htime)[-1])

        X = np.c_[np.ones(X.shape[0]), X]
        return X @ pred_beta, X@betas[-1,:]

最后将时间点代入 ,得到如下的收益率预估。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值