Example #1
0
    def test_exog(self):
        # check that trend and exog are equivalent for basics and varsim
        data = self.res0.model.endog
        res_lin_trend = VAR(data).fit(maxlags=2, trend="ct")
        ex = np.arange(len(data))
        res_lin_trend1 = VAR(data, exog=ex).fit(maxlags=2)
        ex2 = np.arange(len(data))[:, None]**[0, 1]
        res_lin_trend2 = VAR(data, exog=ex2).fit(maxlags=2, trend="n")
        # TODO: intercept differs by 4e-3, others are < 1e-12
        assert_allclose(res_lin_trend.params, res_lin_trend1.params, rtol=5e-3)
        assert_allclose(res_lin_trend.params, res_lin_trend2.params, rtol=5e-3)
        assert_allclose(res_lin_trend1.params,
                        res_lin_trend2.params,
                        rtol=1e-10)

        y1 = res_lin_trend.simulate_var(seed=987128)
        y2 = res_lin_trend1.simulate_var(seed=987128)
        y3 = res_lin_trend2.simulate_var(seed=987128)
        assert_allclose(y2.mean(0), y1.mean(0), rtol=1e-12)
        assert_allclose(y3.mean(0), y1.mean(0), rtol=1e-12)
        assert_allclose(y3.mean(0), y2.mean(0), rtol=1e-12)

        h = 10
        fc1 = res_lin_trend.forecast(res_lin_trend.endog[-2:], h)
        exf = np.arange(len(data), len(data) + h)
        fc2 = res_lin_trend1.forecast(res_lin_trend1.endog[-2:],
                                      h,
                                      exog_future=exf)
        with pytest.raises(ValueError, match="exog_future only has"):
            wrong_exf = np.arange(len(data), len(data) + h // 2)
            res_lin_trend1.forecast(res_lin_trend1.endog[-2:],
                                    h,
                                    exog_future=wrong_exf)
        exf2 = exf[:, None]**[0, 1]
        fc3 = res_lin_trend2.forecast(res_lin_trend2.endog[-2:],
                                      h,
                                      exog_future=exf2)
        assert_allclose(fc2, fc1, rtol=1e-12, atol=1e-12)
        assert_allclose(fc3, fc1, rtol=1e-12, atol=1e-12)
        assert_allclose(fc3, fc2, rtol=1e-12, atol=1e-12)

        fci1 = res_lin_trend.forecast_interval(res_lin_trend.endog[-2:], h)
        exf = np.arange(len(data), len(data) + h)
        fci2 = res_lin_trend1.forecast_interval(res_lin_trend1.endog[-2:],
                                                h,
                                                exog_future=exf)
        exf2 = exf[:, None]**[0, 1]
        fci3 = res_lin_trend2.forecast_interval(res_lin_trend2.endog[-2:],
                                                h,
                                                exog_future=exf2)
        assert_allclose(fci2, fci1, rtol=1e-12, atol=1e-12)
        assert_allclose(fci3, fci1, rtol=1e-12, atol=1e-12)
        assert_allclose(fci3, fci2, rtol=1e-12, atol=1e-12)
Example #2
0
class dieboldLi(nelsonSiegel):
    """
    The dieboldLi class generates a curve based on the D&L parameters. This 
    class is also capable of calibrating the parameters based on the input data.
    This class inherits the features of the nelsonSiegel class.
    """
    def __init__(self, parameters=None):
        super(dieboldLi, self).__init__(parameters=parameters)
        self._parametersHistorical = None
        self._tenorsHistorical = None
        self._yieldsHistorical = None

    def parametersHistorical(self):
        """
        This method shows the historical values of the parameters: tau, level,
        slope and curvature.
        """
        return pd.DataFrame(self._parametersHistorical,
                            columns=('tau', 'b0', 'b1', 'b2'),
                            index=pd.to_datetime(self._dates))

    def calibrateParametersHistorical(self, tenors, yields, tau=1):
        """
        This method calculates the historical parameters for the provided
        tenors and yields. The inputs are an array of tenors, an array of
        yields, and tau (an integer).
        inputs: array, array, float
        output: DataFrame
        """

        yieldCurve = yields.values
        param = []
        x0 = np.array([0.1, 0.1, 0.1])

        for y in yieldCurve:

            x0 = leastsq(self.nelsonSiegelCurveResiduals,
                         x0,
                         args=(tenors, y, tau))
            x0 = x0[0]
            param.append([tau] + x0.tolist())

        self._tenorsHistorical = tenors
        self._yieldsHistorical = yields
        self._parametersHistorical = param

        return param

    def parametersAR(self, lag=1):
        #        OLS(self.parametersHistorical()['b0'], self.parametersHistorical()['b0'][])
        #        self._arModel = (AR(self.parametersHistorical()['b0']).fit(lag), AR(self.parametersHistorical()['b1']).fit(lag), AR(self.parametersHistorical()['b2']).fit(lag))
        self._varModel = VAR(self.parametersHistorical()[['b0', 'b1',
                                                          'b2']]).fit(lag)
        self._varModel.summary()
        return True

    def calibrateDieboldLi(self, yields, tenor, tau=1, lag=1):

        yieldCurve = yields
        tenors = tenor
        par = self.calibrateParametersHistorical(np.array(tenors),
                                                 yieldCurve,
                                                 tau=tau)
        self._dates = yields.index
        self.parametersAR(lag=lag)
        return par

    def setNSParameters(self, position=-1):

        self._parameters = self._parametersHistorical[position]
        self._tenors = self._tenorsHistorical[position]
        self._yields = self._yieldsHistorical[position]

    def forecastDLParameters(self,
                             initialParameters=None,
                             steps=1,
                             alpha=0.05):
        #Función que proyecta parámetros Diebold Li a futuro
        """
        inputs : array, int
        output: array
        """
        assert not isinstance(
            self._varModel,
            VAR), "Theres no model yet. Run calibrateDieboldLi first"

        if initialParameters is None:
            initialParameters = self._parameters

        parameters = np.array([initialParameters[1:4]])

        return self._varModel.forecast_interval(parameters, steps,
                                                alpha=alpha), initialParameters

    def plotForecastedCurve(self,
                            tenor,
                            initialParameters=None,
                            steps=1,
                            alpha=0.05,
                            style='fivethirtyeight',
                            error=True):
        #Función que grafica forecast de curva, junto con error
        forecast, initialParameters = self.forecastDLParameters(
            initialParameters=initialParameters, steps=steps, alpha=alpha)

        baseParameter = initialParameters
        fcParameter = [baseParameter[0]] + forecast[0][-1].tolist()
        topParameter = [baseParameter[0]] + forecast[1][-1].tolist()
        bottomParameter = [baseParameter[0]] + forecast[2][-1].tolist()

        with plt.style.context(style, after_reset=True):
            plt.plot(tenor,
                     self.nelsonSiegelCurve(tenor, baseParameter),
                     linewidth=2.0)
            plt.plot(tenor, self.nelsonSiegelCurve(tenor, fcParameter), 'w.')
            if error:
                plt.plot(tenor, self.nelsonSiegelCurve(tenor, topParameter),
                         'w--')
                plt.plot(tenor, self.nelsonSiegelCurve(tenor, bottomParameter),
                         'w--')
                plt.text(0.2,
                         0.7,
                         """$\\alpha$ = %s""" % alpha,
                         transform=plt.gca().transAxes)

            plt.ylabel('%')
            plt.title('%s Months Projection for %s calibrated curve' %
                      (str(steps), self._currency))

        plt.show()
Example #3
0
class yieldCurve(object):
    
    def __init__(self):
        self.parameters = []

    def nelsonSiegelCurve(self, tenors, parameters = None):
        #A partir de los tenores ingresados entrega los puntos de la curva de tasas para los parámetros ingresados o lo guardados
        """
        Based on the provided tenors and parameters, this method calculates the
        rates for each point of the curve. The input can be an array (of 
        tenors) and a list or another array (of parameters). The output is an 
        array that contains the rates for each of the tenors.
        input: array, list or array
        output: array
        """
        if parameters is None:
            parameters = self._parameters

        if parameters is None:
            print("""There are no parameters calibrated for the curve. Run calibrateParameters first.""")
            return False
              
        b0, b1, b2 = parameters[1:4]
        tau = float(parameters[0])
        
        yc = b0 + b1*(1 - np.exp(-tenors/tau))/(tenors/tau) + b2*((1 - np.exp(-tenors/tau))/(tenors/tau) - np.exp(-tenors/tau))
        
        return yc

    def nelsonSiegelCurveResiduals(self, p, tenors, yields, tau):
        """
        The residuals method calculates the error between the actual yields and
        what the model computes with the parameters obtained from the least
        square optimization. the inputs are an array of parameters, an array
        of tenors, an array of yields and the parameter tau (integer).
        inputs: array, array, array, int
        output: array
        """
        
        b0, b1, b2 = p
        err = yields - self.nelsonSiegelCurve(tenors, [tau, b0, b1, b2])
        err = err.astype(float)
        return err

    def calibrateCurveParametersHistorical(self, tenors, yields, tau = 1):
        """
        This method calculates the historical parameters for the provided
        tenors and yields. The inputs are an array of tenors, an array of
        yields, and tau (an integer).
        inputs: array, array, float
        output: DataFrame
        """
        yieldCurve = yields.values.astype(float)
        param= []
        x0 = np.array([0.1, 0.1, 0.1])
        
        for y in yieldCurve:
            x0 = leastsq(self.nelsonSiegelCurveResiduals, x0, args = (tenors, y, tau))
            x0 = x0[0]
            param.append([tau] + x0.tolist())
            
        self._tenorsHistorical = tenors
        self._yieldsHistorical = yields
        self._parametersHistorical = param
        
        return param


    def parametersVAR(self, tenors, yields, lag = 1, steps = 1, alpha = 0.01):
        params = pd.DataFrame(data=self.calibrateCurveParametersHistorical(tenors, yields),columns=['tau','b0','b1','b2'], index = yields.index)
        self._varModel = VAR(params[['b0','b1','b2']]).fit(lag) 
        self._varModel.summary()
        fparam = self._varModel.forecast_interval(params.tail(1)[['b0','b1','b2']].values, steps, alpha = alpha)
        return fparam, params.tail(1)[['b0','b1','b2']].values


    def plotForecastedCurve(self, tenors, yields, steps = 1, alpha = 0.05, tau = 1, style = 'fivethirtyeight', error = True):
        #Función que grafica forecast de curva, junto con error
        forecast, initialParameters = self.parametersVAR(tenors, yields, steps = steps, alpha = alpha)
        
        baseParameter = initialParameters.tolist()
        fcParameter = forecast[0].tolist()
        topParameter = forecast[1].tolist()
        bottomParameter = forecast[2].tolist()
        
        shock_level = -0.25*1
        shock_slope = 0
        shock_curvature = 0
        
        with plt.style.context(style, after_reset = True):
            plt.plot(tenors,yields.tail(1).values[0],'g.')
            plt.plot(tenors,self.nelsonSiegelCurve(tenors, [tau, baseParameter[0][0] + shock_level, baseParameter[0][1], baseParameter[0][2]]), linewidth = 1.0)
            plt.plot(tenors,self.nelsonSiegelCurve(tenors, [tau, fcParameter[0][0] + shock_level, fcParameter[0][1], fcParameter[0][2]]), 'b.')
            if error:
                plt.plot(tenors,self.nelsonSiegelCurve(tenors, [tau, topParameter[0][0] + shock_level, topParameter[0][1], topParameter[0][2]]), 'b--', linewidth = 1.0)
                plt.plot(tenors,self.nelsonSiegelCurve(tenors, [tau, bottomParameter[0][0] + shock_level, bottomParameter[0][1], bottomParameter[0][2]]), 'b--', linewidth = 1.0)
#                plt.text(0.2, 0.8, """$\\alpha$ = %s"""%alpha, transform =  plt.gca().transAxes)
                
            plt.ylabel('%')
#            plt.title('%s Months Projection for CLP calibrated curve'%(str(steps)))
        plt.show()