diff options
| -rw-r--r-- | pyisda/credit_index.pxd | 14 | ||||
| -rw-r--r-- | pyisda/credit_index.pyx | 194 | ||||
| -rw-r--r-- | pyisda/curve.pxd | 14 | ||||
| -rw-r--r-- | pyisda/curve.pyx | 178 |
4 files changed, 213 insertions, 187 deletions
diff --git a/pyisda/credit_index.pxd b/pyisda/credit_index.pxd new file mode 100644 index 0000000..88a3e3a --- /dev/null +++ b/pyisda/credit_index.pxd @@ -0,0 +1,14 @@ +from legs cimport TContingentLeg, TFeeLeg +from date cimport TDate +from curve cimport TCurve + +cdef class CreditIndexCurve: + cdef TDate _base_date + cdef TCurve** _curves + cdef int _len_curves + cdef TDate* _maturities + cdef TContingentLeg** _contingent_legs + cdef TFeeLeg** _fee_legs + cdef int _len_maturities + cdef double* _T + cdef int _len_T diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx new file mode 100644 index 0000000..25337ed --- /dev/null +++ b/pyisda/credit_index.pyx @@ -0,0 +1,194 @@ +from libc.stdlib cimport malloc, free +cimport cython +from legs cimport (JpmcdsCdsContingentLegMake, JpmcdsCdsFeeLegMake, + JpmcdsContingentLegPV, JpmcdsFeeLegPV, FeeLegAI, JpmcdsFeeLegFree) +from curve cimport SpreadCurve, JpmcdsCopyCurve, tweak_curve, YieldCurve, JpmcdsFreeTCurve +from date cimport pydate_to_TDate, TDate_to_pydate +from cdsone cimport JpmcdsStringToStubMethod, TStubMethod +cimport numpy as np +np.import_array() + +cdef class CreditIndexCurve: + def __init__(self, start_date, maturities, curves): + cdef SpreadCurve sc = <SpreadCurve?>curves[0] + self._len_T = sc._thisptr.fNumItems + self._base_date = sc._thisptr.fBaseDate + self._T = <double*>malloc(sizeof(double) * self._len_T) + cdef size_t i + for i in range(self._len_T): + self._T[i] = (sc._thisptr.fArray[i].fDate - self._base_date) / 365. + cdef TDate start_date_c = pydate_to_TDate(start_date) + self._len_maturities = len(maturities) + self._maturities = <TDate*>malloc(sizeof(TDate) * self._len_maturities) + for i, d in enumerate(maturities): + self._maturities[i] = pydate_to_TDate(d) + self._len_curves = len(curves) + self._curves = <TCurve**>malloc(sizeof(TCurve*) * self._len_curves) + + for i, c in enumerate(curves): + self._curves[i] = JpmcdsCopyCurve((<SpreadCurve?>c)._thisptr) + + self._contingent_legs = <TContingentLeg**> malloc(self._len_maturities * + sizeof(TContingentLeg)) + self._fee_legs = <TFeeLeg**> malloc(self._len_maturities * + sizeof(TFeeLeg)) + cdef TStubMethod stub_type + if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0: + raise ValueError("can't convert stub") + for i in range(self._len_maturities): + self._contingent_legs[i] = JpmcdsCdsContingentLegMake(start_date_c, + self._maturities[i], + 1., + True) + + self._fee_legs[i] = JpmcdsCdsFeeLegMake(start_date_c, + self._maturities[i], + True, + NULL, + &stub_type, + 1., + 1.0, + 3, #ACT_360 + <long>'M', # MODIFIED + b'NONE', + True) + def __dealloc__(self): + if self._T is not NULL: + free(self._T) + if self._maturities is not NULL: + free(self._maturities) + if self._contingent_legs is not NULL: + for i in range(self._len_maturities): + free(self._contingent_legs[i]) + if self._fee_legs is not NULL: + for i in range(self._len_maturities): + JpmcdsFeeLegFree(self._fee_legs[i]) + for i in range(self._len_curves): + JpmcdsFreeTCurve(self._curves[i]) + free(self._curves) + + #@cython.initializedcheck(False) + @cython.boundscheck(False) + def pv_vec(self, step_in_date, value_date, YieldCurve yc, double recovery_rate): + cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) + cdef TDate value_date_c = pydate_to_TDate(value_date) + cdef np.npy_intp[2] n = [self._len_curves, self._len_maturities] + cdef double accrued + FeeLegAI(self._fee_legs[0], self._base_date, &accrued) + cdef size_t i, j + + cdef np.ndarray[np.float64_t,ndim=2] cl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0) + cdef np.ndarray[np.float64_t,ndim=2] fl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0) + cdef TCurve* sc + for i in range(self._len_curves): + sc = self._curves[i] + for j in range(self._len_maturities): + JpmcdsContingentLegPV(self._contingent_legs[j], + sc.fBaseDate, + value_date_c, + step_in_date_c, + yc._thisptr, + sc, + recovery_rate, + &cl_pv[i,j]) + JpmcdsFeeLegPV(self._fee_legs[j], + sc.fBaseDate, + step_in_date_c, + value_date_c, + yc._thisptr, + sc, + True, + &fl_pv[i,j]) + return (fl_pv-accrued, cl_pv) + + def pv(self, step_in_date, value_date, maturity, YieldCurve yc not None, + double recovery_rate, double fixed_rate): + + cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) + cdef TDate value_date_c = pydate_to_TDate(value_date) + cdef TDate maturity_c = pydate_to_TDate(value_date) + + cdef double accrued + FeeLegAI(self._fee_legs[0], self._base_date, &accrued) + + for j in range(self._len_maturities): + if self._maturities[j] == maturity_c: + return pv(self._base_date, step_in_date_c, value_date_c, + yc._thisptr, recovery_rate, fixed_rate, + self._contingent_legs[j], self._fee_legs[j], + self._curves, self._len_curves) - accrued + else: + ValueError("This maturity is not available.") + + @property + def curves(self): + """returns the list of curves inside the porfolio. + + This is returning the curves by reference so don't delete them.""" + cdef list r = [] + cdef SpreadCurve sc + for i in range(self._len_curves): + sc = SpreadCurve.__new__(SpreadCurve) + sc._thisptr = self._curves[i] + r.append(sc) + + @property + def maturities(self): + cdef list r = [] + for i in range(self._len_maturities): + r.append(TDate_to_pydate(self._maturities[i])) + + def tweak_portfolio(self, epsilon, maturity): + cdef bint* mask = <bint*>malloc(sizeof(bint) * self._len_T) + cdef TDate maturity_c = pydate_to_TDate(maturity) + cdef TDate prev_maturity + prev_maturity = 0 + cdef size_t i, j + for i in range(self._len_maturities): + if self._maturities[i] > maturity_c: + break + if self._maturities[i] == maturity_c: + prev_maturity = self._maturities[i-1] + else: + raise ValueError("maturity is not correct") + cdef TCurve* sc = self._curves[0] + for j in range(self._len_T): + mask[j] = (sc.fArray[i].fDate <= maturity_c ) and \ + (sc.fArray[i].fDate > prev_maturity) + + cdef double* h = <double*>malloc(sizeof(double) * self._len_T) + for j in self._len_curves: + sc = self._curves[j] + tweak_curve(sc, sc, epsilon, h, self._T, mask, self._len_curves) + free(h) + free(mask) + +@cython.boundscheck(False) +cdef double pv(TDate base_date, TDate step_in_date, TDate value_date, TCurve* yc, + double recovery_rate, double coupon, + TContingentLeg* cl, TFeeLeg* fl, TCurve** curves, int n_curves): + + cdef size_t i + cdef TCurve* sc + cdef double r = 0 + cdef double cl_pv, fl_pv + for i in range(n_curves): + sc = curves[i] + JpmcdsContingentLegPV(cl, + base_date, + value_date, + step_in_date, + yc, + sc, + recovery_rate, + &cl_pv) + JpmcdsFeeLegPV(fl, + base_date, + step_in_date, + value_date, + yc, + sc, + True, + &fl_pv) + r += cl_pv - fl_pv*coupon + return r / <double>n_curves diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd index e42e8de..63da78d 100644 --- a/pyisda/curve.pxd +++ b/pyisda/curve.pxd @@ -117,15 +117,7 @@ cdef class YieldCurve(Curve): cdef class SpreadCurve(Curve): pass -cdef class CreditIndexCurve: - cdef TDate _base_date - cdef TCurve** _curves - cdef int _len_curves - cdef TDate* _maturities - cdef TContingentLeg** _contingent_legs - cdef TFeeLeg** _fee_legs - cdef int _len_maturities - cdef double* _T - cdef int _len_T - cdef fArray_to_list(TRatePt* fArray, int fNumItems) + +cdef void tweak_curve(TCurve* sc, TCurve* sc_tweaked, double epsilon, + double* h, double* T, bint* mask, int n) diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx index 9662961..d306dd9 100644 --- a/pyisda/curve.pyx +++ b/pyisda/curve.pyx @@ -1,6 +1,7 @@ from libc.stdlib cimport malloc, free from libc.string cimport memcpy from libc.math cimport log1p +from libc.stdio cimport printf from date cimport (JpmcdsStringToDateInterval, pydate_to_TDate, dcc, JpmcdsDateIntervalToFreq, JpmcdsDateFwdThenAdjust, TDate_to_pydate, JpmcdsDateFromBusDaysOffset, JpmcdsStringToDayCountConv) @@ -108,6 +109,7 @@ cdef class Curve(object): t1 = 0 h1 = 0 cdef double* data = <double*>malloc(self._thisptr.fNumItems * sizeof(double)) + cdef size_t i if <Basis>self._thisptr.fBasis == Basis.CONTINUOUS: for i in range(self._thisptr.fNumItems): h2 = self._thisptr.fArray[i].fRate @@ -482,179 +484,3 @@ cdef class SpreadCurve(Curve): free(h) free(T) return sc - -cdef class CreditIndexCurve: - def __init__(self, start_date, maturities, curves): - cdef SpreadCurve sc = <SpreadCurve?>curves[0] - self._len_T = sc._thisptr.fNumItems - self._base_date = sc._thisptr.fBaseDate - self._T = <double*>malloc(sizeof(double) * self._len_T) - cdef size_t i - for i in range(self._len_T): - self._T[i] = (sc._thisptr.fArray[i].fDate - self._base_date) / 365. - cdef TDate start_date_c = pydate_to_TDate(start_date) - self._len_maturities = len(maturities) - self._maturities = <TDate*>malloc(sizeof(TDate) * self._len_maturities) - for i, d in enumerate(maturities): - self._maturities[i] = pydate_to_TDate(d) - self._len_curves = len(curves) - self._curves = <TCurve**>malloc(sizeof(TCurve*) * self._len_curves) - - for i, c in enumerate(curves): - self._curves[i] = JpmcdsCopyCurve((<SpreadCurve?>c)._thisptr) - - self._contingent_legs = <TContingentLeg**> malloc(self._len_maturities * - sizeof(TContingentLeg)) - self._fee_legs = <TFeeLeg**> malloc(self._len_maturities * - sizeof(TFeeLeg)) - cdef TStubMethod stub_type - if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0: - raise ValueError("can't convert stub") - for i in range(self._len_maturities): - self._contingent_legs[i] = JpmcdsCdsContingentLegMake(start_date_c, - self._maturities[i], - 1., - True) - - self._fee_legs[i] = JpmcdsCdsFeeLegMake(start_date_c, - self._maturities[i], - True, - NULL, - &stub_type, - 1., - 1.0, - 3, #ACT_360 - MODIFIED, - b'NONE', - True) - def __dealloc__(self): - if self._T is not NULL: - free(self._T) - if self._maturities is not NULL: - free(self._maturities) - if self._contingent_legs is not NULL: - for i in range(self._len_maturities): - free(self._contingent_legs[i]) - if self._fee_legs is not NULL: - for i in range(self._len_maturities): - JpmcdsFeeLegFree(self._fee_legs[i]) - for i in range(self._len_curves): - JpmcdsFreeTCurve(self._curves[i]) - free(self._curves) - - #@cython.initializedcheck(False) - @cython.boundscheck(False) - def pv_vec(self, step_in_date, value_date, YieldCurve yc, double recovery_rate): - cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) - cdef TDate value_date_c = pydate_to_TDate(value_date) - cdef np.npy_intp[2] n = [self._len_curves, self._len_maturities] - cdef double accrued - FeeLegAI(self._fee_legs[0], self._base_date, &accrued) - cdef size_t i, j - - cdef np.ndarray[np.float64_t,ndim=2] cl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0) - cdef np.ndarray[np.float64_t,ndim=2] fl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0) - cdef TCurve* sc - for i in range(self._len_curves): - sc = self._curves[i] - for j in range(self._len_maturities): - JpmcdsContingentLegPV(self._contingent_legs[j], - sc.fBaseDate, - value_date_c, - step_in_date_c, - yc._thisptr, - sc, - recovery_rate, - &cl_pv[i,j]) - JpmcdsFeeLegPV(self._fee_legs[j], - sc.fBaseDate, - step_in_date_c, - value_date_c, - yc._thisptr, - sc, - True, - &fl_pv[i,j]) - return (fl_pv-accrued, cl_pv) - - def pv(self, step_in_date, value_date, YieldCurve yc not None, - double recovery_rate): - - cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) - cdef TDate value_date_c = pydate_to_TDate(value_date) - - r = [] - for j in range(self._len_maturities): - r.append(pv(self._base_date, step_in_date_c, value_date_c, - yc._thisptr, recovery_rate, 0.01, - self._contingent_legs[j], - self._fee_legs[j], self._curves, self._len_curves)) - - cdef double accrued - FeeLegAI(self._fee_legs[0], self._base_date, &accrued) - return r - - @property - def curves(self): - """returns the list of curves inside the porfolio. - - This is returning the curves by reference so don't delete them.""" - cdef list r = [] - cdef SpreadCurve sc - for i in range(self._len_curves): - sc = SpreadCurve.__new__(SpreadCurve) - sc._thisptr = self._curves[i] - r.append(sc) - - @property - def maturities(self): - cdef list r = [] - for i in range(self._len_maturities): - r.append(TDate_to_pydate(self._maturities[i])) - - def tweak_portfolio(self, quotes): - if len(quotes) != self._len_maturities: - raise ValueError("length of quotes must equal length of maturities") - cdef bint* mask = <bint*>malloc(sizeof(bint) * self._len_T) - cdef double* basis = <double*>malloc(sizeof(double) * self._len_T) - cdef TCurve* sc = self._curves[0] - cdef TDate maturity, prev_maturity - prev_maturity = 0 - cdef size_t i - for i in range(self._len_maturities): - maturity = self._maturities[i] - for j in range(self._len_T): - mask[j] = (sc.fArray[i].fDate <= maturity ) and \ - (sc.fArray[i].fDate > prev_maturity) - - free(mask) - free(basis) - -@cython.boundscheck(False) -cdef double pv(TDate base_date, TDate step_in_date, TDate value_date, TCurve* yc, - double recovery_rate, double coupon, - TContingentLeg* cl, TFeeLeg* fl, TCurve** curves, int n_curves): - - cdef size_t i - cdef TCurve* sc - cdef double r = 0 - cdef double cl_pv, fl_pv - for i in range(n_curves): - sc = curves[i] - JpmcdsContingentLegPV(cl, - base_date, - value_date, - step_in_date, - yc, - sc, - recovery_rate, - &cl_pv) - JpmcdsFeeLegPV(fl, - base_date, - step_in_date, - value_date, - yc, - sc, - True, - &fl_pv) - r += cl_pv - fl_pv*coupon - return r / <double>n_curves |
