diff options
| author | Guillaume Horel <guillaume.horel@gmail.com> | 2017-02-23 11:17:58 -0500 |
|---|---|---|
| committer | Guillaume Horel <guillaume.horel@gmail.com> | 2017-02-23 12:49:12 -0500 |
| commit | 39df288240394e74903b3c70986ede40b0b243a8 (patch) | |
| tree | 486a5a94c66af323666f8e1ad7adfa6b0bcfc392 | |
| parent | 1fe8d4a980ce2bdcef093946d360767f7e65976c (diff) | |
| download | pyisda-39df288240394e74903b3c70986ede40b0b243a8.tar.gz | |
Finish C++ switch
not sure if it's worth it, but we'll see...
| -rw-r--r-- | cpp_layer/curve.hpp | 5 | ||||
| -rw-r--r-- | pyisda/cdsone.pyx | 8 | ||||
| -rw-r--r-- | pyisda/credit_index.pxd | 13 | ||||
| -rw-r--r-- | pyisda/credit_index.pyx | 113 | ||||
| -rw-r--r-- | pyisda/curve.pxd | 19 | ||||
| -rw-r--r-- | pyisda/curve.pyx | 144 | ||||
| -rw-r--r-- | pyisda/flat_hazard.pyx | 10 | ||||
| -rw-r--r-- | pyisda/legs.pyx | 5 |
8 files changed, 164 insertions, 153 deletions
diff --git a/cpp_layer/curve.hpp b/cpp_layer/curve.hpp index e4fddb8..fd1db3b 100644 --- a/cpp_layer/curve.hpp +++ b/cpp_layer/curve.hpp @@ -38,7 +38,10 @@ public: TCurve* data() { return _ptr; } - + typedef TRatePt* iterator; + typedef const TRatePt* const_iterator; + iterator begin() { return _ptr->fArray; } + iterator end() {return &_ptr->fArray[_ptr->fNumItems];} int size() { return _ptr->fNumItems; } diff --git a/pyisda/cdsone.pyx b/pyisda/cdsone.pyx index 95fc6a6..ddc3336 100644 --- a/pyisda/cdsone.pyx +++ b/pyisda/cdsone.pyx @@ -58,8 +58,8 @@ def upfront_charge(date, value_date, benchmark_start_date, stepin_date, raise ValueError("can't convert to date interval") if JpmcdsCdsoneUpfrontCharge(today, value_date_c, benchmark_start_date_c, stepin_date_c, start_date_c, end_date_c, coupon_rate, pay_accrued_on_default, - &ivl, &stub, - dcc("ACT/360"), b'F', b"None", yc._thisptr, spread, recovery_rate, + &ivl, &stub, dcc("ACT/360"), b'F', b"None", + yc._thisptr.get().data(), spread, recovery_rate, pay_accrued_at_start, &result) == SUCCESS: return result else: @@ -120,8 +120,8 @@ def spread_from_upfront(date, value_date, benchmark_start_date, stepin_date, raise ValueError("can't convert to date interval") if JpmcdsCdsoneSpread(today, value_date_c, benchmark_start_date_c, stepin_date_c, start_date_c, end_date_c, coupon_rate, pay_accrued_on_default, - &ivl, &stub, - dcc("ACT/360"), b'F', b"None", yc._thisptr, upfront, recovery_rate, + &ivl, &stub, dcc("ACT/360"), b'F', b"None", + yc._thisptr.get().data(), upfront, recovery_rate, pay_accrued_at_start, &result) == SUCCESS: return result else: diff --git a/pyisda/credit_index.pxd b/pyisda/credit_index.pxd index cb7c944..8051726 100644 --- a/pyisda/credit_index.pxd +++ b/pyisda/credit_index.pxd @@ -1,18 +1,17 @@ from legs cimport TContingentLeg, TFeeLeg from date cimport TDate -from curve cimport TCurve +from curve cimport CurveObject, TCurve +from libcpp.memory cimport shared_ptr +from libcpp.vector cimport vector cdef class CurveList: cdef TDate _base_date - cdef TCurve** _curves - cdef int _len_curves - cdef double* _T - cdef int _len_T + cdef vector[shared_ptr[CurveObject]] _curves + cdef vector[double] _T cdef list _tickers cdef dict _tickersdict cdef class CreditIndex(CurveList): - cdef TDate* _maturities - cdef int _len_maturities + cdef vector[TDate] _maturities cdef TContingentLeg** _contingent_legs cdef TFeeLeg** _fee_legs diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx index c7cd4e9..774c8e9 100644 --- a/pyisda/credit_index.pyx +++ b/pyisda/credit_index.pyx @@ -1,4 +1,5 @@ from libc.stdlib cimport malloc, free +from cython.operator cimport dereference as deref, preincrement as preinc cimport cython from legs cimport (JpmcdsCdsContingentLegMake, JpmcdsCdsFeeLegMake, JpmcdsContingentLegPV, JpmcdsFeeLegPV, FeeLegAI, JpmcdsFeeLegFree) @@ -20,47 +21,35 @@ cdef class CurveList: else: raise TypeError("curves need to be a list of SpreadCurve "\ "or a list of tuple (SpreadCurve, ticker)") - self._len_T = sc._thisptr.fNumItems - self._base_date = sc._thisptr.fBaseDate - self._T = <double*>malloc(sizeof(double) * self._len_T) + self._T = vector[double](sc._thisptr.get().size()) + self._base_date = sc._thisptr.get().BaseDate() cdef size_t i - for i in range(self._len_T): - self._T[i] = (sc._thisptr.fArray[i].fDate - self._base_date) / 365. - self._len_curves = len(curves) - self._curves = <TCurve**>malloc(sizeof(TCurve*) * self._len_curves) + for i in range(self._T.size()): + self._T[i] = (sc._thisptr.get().data().fArray[i].fDate - self._base_date) / 365. self._tickers = [] self._tickersdict = {} if isinstance(curves[0], tuple): for i, (t, c) in enumerate(curves): - self._curves[i] = JpmcdsCopyCurve((<SpreadCurve?>c)._thisptr) + self._curves.push_back((<SpreadCurve?>c)._thisptr) self._tickers.append(t) self._tickersdict[t] = i else: - for i, c in enumerate(curves): - self._curves[i] = JpmcdsCopyCurve((<SpreadCurve?>c)._thisptr) + for c in curves: + self._curves.push_back((<SpreadCurve?>c)._thisptr) if tickers and not self._tickers: - if len(tickers) != self._len_curves: + if len(tickers) != self._curves.size(): raise ValueError("tickers must have the same length as curves") else: self._tickers = tickers self._tickersdict = {t: i for i, t in enumerate(tickers)} - def __dealloc__(self): - if self._T is not NULL: - free(self._T) - cdef size_t i - for i in range(self._len_curves): - JpmcdsFreeTCurve(self._curves[i]) - free(self._curves) - def __getitem__(self, str ticker): - ## would need to use a shared pointer to avoid a copy cdef SpreadCurve sc if ticker in self._tickers: sc = SpreadCurve.__new__(SpreadCurve) - sc._thisptr = JpmcdsCopyCurve(self._curves[self._tickersdict[ticker]]) + sc._thisptr = self._curves[self._tickersdict[ticker]] return sc else: raise KeyError(ticker) @@ -68,10 +57,14 @@ cdef class CurveList: def iteritems(self): ## would need to use a shared pointer to avoid a copy cdef SpreadCurve sc - for i in range(self._len_curves): + cdef vector[shared_ptr[CurveObject]].iterator it = self._curves.begin() + cdef size_t i + while it != self._curves.end(): sc = SpreadCurve.__new__(SpreadCurve) - sc._thisptr = self._curves[i] + sc._thisptr = deref(it) yield (self._tickers[i], sc) + preinc(it) + i = i+1 @property def curves(self): @@ -87,31 +80,28 @@ cdef class CurveList: @curves.setter def curves(self, list l): - if len(l) != self._len_curves: + if len(l) != self._curves.size(): raise ValueError("l should have {} elements".format(len(l))) cdef size_t i for i, c in enumerate(l): - JpmcdsFreeTCurve(self._curves[i]) - self._curves[i] = JpmcdsCopyCurve((<SpreadCurve?>c)._thisptr) + self._curves[i] = (<SpreadCurve?>c)._thisptr cdef class CreditIndex(CurveList): def __init__(self, start_date, maturities, curves): CurveList.__init__(self, curves) cdef TDate start_date_c = pydate_to_TDate(start_date) - self._len_maturities = len(maturities) - self._maturities = <TDate*>malloc(sizeof(TDate) * self._len_maturities) - cdef size_t i - for i, d in enumerate(maturities): - self._maturities[i] = pydate_to_TDate(d) + for d in maturities: + self._maturities.push_back(pydate_to_TDate(d)) - self._contingent_legs = <TContingentLeg**> malloc(self._len_maturities * + self._contingent_legs = <TContingentLeg**> malloc(self._maturities.size() * sizeof(TContingentLeg)) - self._fee_legs = <TFeeLeg**> malloc(self._len_maturities * + self._fee_legs = <TFeeLeg**> malloc(self._maturities.size() * sizeof(TFeeLeg)) cdef TStubMethod stub_type if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0: raise ValueError("can't convert stub") + cdef size_t i for i in range(self._len_maturities): self._contingent_legs[i] = JpmcdsCdsContingentLegMake(start_date_c, self._maturities[i], @@ -131,8 +121,6 @@ cdef class CreditIndex(CurveList): True) def __dealloc__(self): - 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]) @@ -145,7 +133,7 @@ cdef class CreditIndex(CurveList): 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 np.npy_intp[2] n = [self._curves.size(), self._maturities.size()] cdef double accrued FeeLegAI(self._fee_legs[0], self._base_date, &accrued) cdef size_t i, j @@ -153,14 +141,14 @@ cdef class CreditIndex(CurveList): 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 i in range(self._curves.size()): + sc = self._curves[i].get().data() for j in range(self._len_maturities): JpmcdsContingentLegPV(self._contingent_legs[j], sc.fBaseDate, value_date_c, step_in_date_c, - yc._thisptr, + yc._thisptr.get().data(), sc, recovery_rate, &cl_pv[i,j]) @@ -168,7 +156,7 @@ cdef class CreditIndex(CurveList): sc.fBaseDate, step_in_date_c, value_date_c, - yc._thisptr, + yc._thisptr.get().data(), sc, True, &fl_pv[i,j]) @@ -190,7 +178,7 @@ cdef class CreditIndex(CurveList): TContingentLeg* cl TFeeLeg* fl - for i in range(self._len_maturities): + for i in range(self._maturities.size()): if self._maturities[i] == maturity_c: cl = self._contingent_legs[i] fl = self._fee_legs[i] @@ -202,26 +190,25 @@ cdef class CreditIndex(CurveList): cdef double* h cdef TCurve* tweaked_curve if epsilon != 0: - mask = fill_mask(maturity_c, self._maturities, self._len_maturities, - self._curves[0]) + mask = fill_mask(maturity_c, self._maturities, self._curves[0]) if mask == NULL: raise ValueError("maturity is not correct") h = <double*>malloc(sizeof(double) * self._len_T) - tweaked_curve = JpmcdsCopyCurve(self._curves[0]) + tweaked_curve = JpmcdsCopyCurve(self._curves[0].get().data()) cdef: double fl_pv, cl_pv, r = 0 - for i in range(self._len_curves): + for i in range(self._curves.size()): if epsilon != 0: - tweak_curve(self._curves[i], tweaked_curve, epsilon, h, self._T, mask, self._len_T) + tweak_curve(self._curves[i].get().data(), tweaked_curve, epsilon, h, self._T, mask) else: - tweaked_curve = self._curves[i] + tweaked_curve = self._curves[i].get().data() JpmcdsContingentLegPV(cl, self._base_date, value_date_c, step_in_date_c, - yc._thisptr, + yc._thisptr.get().data(), tweaked_curve, recovery_rate, &cl_pv) @@ -229,7 +216,7 @@ cdef class CreditIndex(CurveList): self._base_date, step_in_date_c, value_date_c, - yc._thisptr, + yc._thisptr.get().data(), tweaked_curve, True, &fl_pv) @@ -243,35 +230,37 @@ cdef class CreditIndex(CurveList): @property def maturities(self): cdef list r = [] - for i in range(self._len_maturities): + for i in range(self._maturities.size()): r.append(TDate_to_pydate(self._maturities[i])) return r def tweak_portfolio(self, double epsilon, maturity, bint inplace=True): cdef TDate maturity_c = pydate_to_TDate(maturity) - cdef bint* mask = fill_mask(maturity_c, self._maturities, - self._len_maturities, self._curves[0]) + cdef bint* mask = fill_mask(maturity_c, self._maturities, self._curves[0]) cdef double* h = <double*>malloc(sizeof(double) * self._len_T) cdef size_t i - for i in range(self._len_curves): - sc = self._curves[i] - tweak_curve(sc, sc, epsilon, h, self._T, mask, self._len_T) + cdef TCurve* sc + for i in range(self._curves.size()): + sc = self._curves[i].get().data() + tweak_curve(sc, sc, epsilon, h, self._T, mask) free(h) free(mask) -cdef bint* fill_mask(TDate maturity, TDate* maturities, int n_maturities, - TCurve* sc) nogil: +cdef bint* fill_mask(TDate maturity, const vector[TDate]& maturities, + const shared_ptr[CurveObject]& sc) nogil: cdef TDate prev_maturity = 0 cdef size_t i - for i in range(n_maturities): + for i in range(maturities.size()): if maturities[i] == maturity: if i > 0: prev_maturity = maturities[i-1] break else: return NULL - cdef bint* mask = <bint*>malloc(sc.fNumItems * sizeof(bint)) - for i in range(sc.fNumItems): - mask[i] = (sc.fArray[i].fDate <= maturity ) and \ - (sc.fArray[i].fDate > prev_maturity) + cdef bint* mask = <bint*>malloc(sc.get().size() * sizeof(bint)) + cdef TDate date + for i in range(sc.get().size()): + date = sc.get().data().fArray[i].fDate + mask[i] = (date <= maturity ) and \ + (date > prev_maturity) return mask diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd index 63da78d..31b36b3 100644 --- a/pyisda/curve.pxd +++ b/pyisda/curve.pxd @@ -1,5 +1,7 @@ from cdsone cimport TStubMethod from legs cimport TContingentLeg, TFeeLeg +from libcpp.memory cimport shared_ptr +from libcpp.vector cimport vector cdef extern from "isda/zerocurve.h" nogil: ctypedef int TBoolean @@ -91,6 +93,19 @@ cdef extern from "isda/tcurve.h" nogil: double basis, # (I) Compounding periods/year long dayCountConv) +cdef extern from "../cpp_layer/curve.hpp" nogil: + cdef cppclass CurveObject: + CurveObject(TDate baseDate, vector[TDate] dates, vector[double] rates, + double basis, long dayCountConv) + TCurve* data() + double ForwardZeroPrice(TDate d2) + double ForwardZeroPrice(TDate d2, TDate d1) + int size() + TDate BaseDate() + ctypedef TRatePt* iterator + iterator begin() + iterator end() + cdef extern from "isda/cxzerocurve.h" nogil: double JpmcdsZeroPrice(TCurve* curve, TDate date) double JpmcdsForwardZeroPrice(TCurve* curve, TDate startDate, TDate maturityDate) @@ -108,7 +123,7 @@ cdef enum Basis: DISCOUNT_FACTOR = -2 cdef class Curve: - cdef TCurve* _thisptr + cdef shared_ptr[CurveObject] _thisptr cdef class YieldCurve(Curve): cdef TDate* _dates @@ -120,4 +135,4 @@ cdef class SpreadCurve(Curve): 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) + double* h, const vector[double]& T, bint* mask) diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx index d306dd9..a6c81f3 100644 --- a/pyisda/curve.pyx +++ b/pyisda/curve.pyx @@ -1,7 +1,10 @@ from libc.stdlib cimport malloc, free from libc.string cimport memcpy from libc.math cimport log1p -from libc.stdio cimport printf +from libcpp.memory cimport make_shared, shared_ptr +from libcpp.vector cimport vector +from cython.operator cimport preincrement as preinc + from date cimport (JpmcdsStringToDateInterval, pydate_to_TDate, dcc, JpmcdsDateIntervalToFreq, JpmcdsDateFwdThenAdjust, TDate_to_pydate, JpmcdsDateFromBusDaysOffset, JpmcdsStringToDayCountConv) @@ -27,17 +30,15 @@ cpdef public enum BadDay: MODIFIED = <long>'M' cdef class Curve(object): - def __dealloc__(self): - if self._thisptr is not NULL: - JpmcdsFreeTCurve(self._thisptr) def __getstate__(self): - cdef int num_items = self._thisptr.fNumItems + cdef TCurve* curve = self._thisptr.get().data() + cdef int num_items = curve.fNumItems; return (num_items, - <bytes>(<char*>self._thisptr.fArray)[:sizeof(TRatePt)*num_items], - self._thisptr.fBaseDate, - self._thisptr.fBasis, - self._thisptr.fDayCountConv) + <bytes>(<char*>curve.fArray)[:sizeof(TRatePt)*num_items], + curve.fBaseDate, + curve.fBasis, + curve.fDayCountConv) def __setstate__(self, state): cdef: @@ -55,7 +56,7 @@ cdef class Curve(object): new_curve.fBaseDate = base_date new_curve.fBasis = basis new_curve.fDayCountConv = dcc - self._thisptr = new_curve + self._thisptr = make_shared[CurveObject](new_curve) def inspect(self): """ method to inspect the content of the C struct @@ -67,60 +68,63 @@ cdef class Curve(object): """ return {'base_date': self.base_date, - 'basis': self._thisptr.fBasis, - 'day_count_convention': dcc_tostring(self._thisptr.fDayCountConv), - 'data': fArray_to_list(self._thisptr.fArray, self._thisptr.fNumItems)} + 'basis': self._thisptr.get().data().fBasis, + 'day_count_convention': dcc_tostring(self._thisptr.get().data().fDayCountConv), + 'data': fArray_to_list(self._thisptr.get().data().fArray, self._thisptr.get().data().fNumItems)} @cython.boundscheck(False) def to_df(self): - cdef np.npy_intp n = self._thisptr.fNumItems + cdef np.npy_intp n = self._thisptr.get().data().fNumItems cdef np.ndarray[np.float64_t,ndim=1] h = np.PyArray_EMPTY(1, &n, np.NPY_DOUBLE, 0) cdef np.ndarray[np.int64_t,ndim=1] d = np.PyArray_EMPTY(1, &n, np.NPY_INT64, 0) - cdef size_t i - for i in range(self._thisptr.fNumItems): - h[i] = self._thisptr.fArray[i].fRate - d[i] = self._thisptr.fArray[i].fDate - d[i] -= 134774 + cdef size_t i = 0 + cdef CurveObject.iterator it = self._thisptr.get().begin() + while it != self._thisptr.get().end(): + h[i] = it.fRate + d[i] = it.fDate -134774 + preinc(it) + preinc(i) + return {'hazard_rates': h, 'dates':d.view('M8[D]')} def __iter__(self): cdef: - size_t i - double h - int d - for i in range(self._thisptr.fNumItems): - h = self._thisptr.fArray[i].fRate - d = self._thisptr.fArray[i].fDate - yield TDate_to_pydate(d), h + size_t i = 0 + CurveObject.iterator it = self._thisptr.get().begin() + while it != self._thisptr.get().end(): + yield (TDate_to_pydate(it.fDate), it.fRate) + preinc(it) + preinc(i) def __len__(self): - return self._thisptr.fNumItems + return self._thisptr.get().size() def __deepcopy__(self, memo): cdef Curve sc = type(self).__new__(type(self)) - sc._thisptr = JpmcdsCopyCurve(self._thisptr) + sc._thisptr = self._thisptr return sc @property @cython.cdivision(True) def forward_hazard_rates(self): cdef double t1, h1, t2, h2 - cdef np.npy_intp shape = self._thisptr.fNumItems + cdef np.npy_intp shape = self._thisptr.get().size() t1 = 0 h1 = 0 - cdef double* data = <double*>malloc(self._thisptr.fNumItems * sizeof(double)) + cdef TCurve* curve = self._thisptr.get().data() + cdef double* data = <double*>malloc(curve.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 - t2 = (self._thisptr.fArray[i].fDate - self._thisptr.fBaseDate)/365. + if <Basis>curve.fBasis == Basis.CONTINUOUS: + for i in range(curve.fNumItems): + h2 = curve.fArray[i].fRate + t2 = (curve.fArray[i].fDate - curve.fBaseDate)/365. data[i] = (h2 * t2 - h1 * t1) / (t2 - t1) h1 = h2 t1 = t2 - elif <Basis>self._thisptr.fBasis == Basis.ANNUAL_BASIS: - for i in range(self._thisptr.fNumItems): - h2 = log1p(self._thisptr.fArray[i].fRate) - t2 = (self._thisptr.fArray[i].fDate - self._thisptr.fBaseDate)/365. + elif <Basis>curve.fBasis == Basis.ANNUAL_BASIS: + for i in range(curve.fNumItems): + h2 = log1p(curve.fArray[i].fRate) + t2 = (curve.fArray[i].fDate - curve.fBaseDate)/365. data[i] = (h2 * t2 - h1 * t1) / (t2 - t1) h1 = h2 t1 = t2 @@ -134,7 +138,7 @@ cdef class Curve(object): @property def base_date(self): - return TDate_to_pydate(self._thisptr.fBaseDate) + return TDate_to_pydate(self._thisptr.get().BaseDate()) def __forward_zero_price(self, d2, d1=None): """ computes the forward zero price at a given date. @@ -147,16 +151,14 @@ cdef class Curve(object): ------- float """ - if self._thisptr is NULL: + if not self._thisptr: raise ValueError('curve is empty') cdef TDate start_date if d1 is None: - start_date = self._thisptr.fBaseDate + return self._thisptr.get().ForwardZeroPrice(pydate_to_TDate(d2)) else: - start_date = pydate_to_TDate(d1) - return JpmcdsForwardZeroPrice(self._thisptr, - start_date, - pydate_to_TDate(d2)) + return self._thisptr.get().ForwardZeroPrice(pydate_to_TDate(d2), + pydate_to_TDate(d1)) cdef fArray_to_list(TRatePt* fArray, int fNumItems): cdef size_t i @@ -241,12 +243,12 @@ cdef class YieldCurve(Curve): if JpmcdsDateIntervalToFreq(&ivl, &float_freq) != SUCCESS: raise ValueError - self._thisptr = JpmcdsBuildIRZeroCurve( + self._thisptr = make_shared[CurveObject](JpmcdsBuildIRZeroCurve( value_date, types_bytes, self._dates, &rates[0], self._ninstr, dcc(mm_dcc), <long> fixed_freq, <long> float_freq, dcc(fixed_swap_dcc), dcc(float_swap_dcc), bad_day_conv, b"None" - ) + )) def __dealloc__(self): ## __dealloc__ of superclass is called by cython so no need to call here @@ -279,8 +281,9 @@ cdef class YieldCurve(Curve): JpmcdsDiscountToRateYearFrac(dfs[i], <double>(yc._dates[i]-base_date_c)/365., <double>1, &rates[i]) - yc._thisptr = JpmcdsMakeTCurve(base_date_c, yc._dates, rates, dfs.shape[0], - <double>1, dcc(day_count_conv)) + yc._thisptr = make_shared[CurveObject]( + JpmcdsMakeTCurve(base_date_c, yc._dates, rates, dfs.shape[0], + <double>1, dcc(day_count_conv))) return yc discount_factor = Curve.__forward_zero_price @@ -307,24 +310,25 @@ cdef class YieldCurve(Curve): cdef double df for k in range(yc._ninstr): yc._dates[k] = self._dates[i] - df = JpmcdsForwardZeroPrice(self._thisptr, forward_date_c, self._dates[i]) + df = self._thisptr.get().ForwardZeroPrice(forward_date_c, self._dates[i]) JpmcdsDiscountToRateYearFrac( df, <double>(self._dates[i] - forward_date_c)/365., <double>1, &rates[k]) i += 1 - yc._thisptr = JpmcdsMakeTCurve(forward_date_c, yc._dates, rates, yc._ninstr, - <double>1, self._thisptr.fDayCountConv) + yc._thisptr = make_shared[CurveObject]( + JpmcdsMakeTCurve(forward_date_c, yc._dates, rates, yc._ninstr, + <double>1, self._thisptr.get().data().fDayCountConv)) return yc @cython.cdivision(True) -cdef inline void tweak_curve(TCurve* sc, TCurve* sc_tweaked, double epsilon, - double* h, double* T, bint* mask, int n): +cdef void tweak_curve(TCurve* sc, TCurve* sc_tweaked, double epsilon, + double* h, const vector[double]& T, bint* mask): ## We want to tweak in the forward space, so we convert the hazard rates ## into forward rates and then back cdef double h1, h2, t1, t2 h1 = t1 = 0 cdef size_t i - for i in range(n): + for i in range(T.size()): h2 = sc.fArray[i].fRate t2 = T[i] h[i] = (h2 * t2 - h1 * t1) / (t2 - t1) @@ -335,7 +339,7 @@ cdef inline void tweak_curve(TCurve* sc, TCurve* sc_tweaked, double epsilon, t1 = 0 cdef double c = 0 - for i in range(n): + for i in range(T.size()): c += (T[i] - t1) * h[i] sc_tweaked.fArray[i].fRate = c / T[i] t1 = T[i] @@ -373,7 +377,7 @@ cdef class SpreadCurve(Curve): cdef TDate* end_dates_c = <TDate*>malloc(n_dates * sizeof(TDate)) cdef TCurve* curve = NULL cdef size_t i - if cash_settle_date_c < yc._thisptr.fBaseDate: + if cash_settle_date_c < yc._thisptr.get().BaseDate(): raise ValueError("cash_settle_date: {0} is anterior to yc's base_date: {1}". format(cash_settle_date, yc.base_date)) for i, d in enumerate(end_dates): @@ -386,7 +390,7 @@ cdef class SpreadCurve(Curve): with nogil: JpmcdsStringToDayCountConv('ACT/360', &dc) curve = JpmcdsCleanSpreadCurve(today_c, - yc._thisptr, + yc._thisptr.get().data(), start_date_c, step_in_date_c, cash_settle_date_c, @@ -406,7 +410,7 @@ cdef class SpreadCurve(Curve): if curve == NULL: raise ValueError("Didn't init the survival curve properly") else: - self._thisptr = curve + self._thisptr = make_shared[CurveObject](curve) survival_probability = Curve.__forward_zero_price @@ -432,8 +436,9 @@ cdef class SpreadCurve(Curve): cdef SpreadCurve sc = cls.__new__(cls) cdef TDate max_date = 200000 # can go higher but this should be more than enough - sc._thisptr = JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1, - <double>basis, dcc(day_count_conv)) + sc._thisptr = make_shared[CurveObject]( + JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1, + <double>basis, dcc(day_count_conv))) return sc @cython.boundscheck(False) @@ -455,32 +460,31 @@ cdef class SpreadCurve(Curve): cdef: TCurve* curve_tweaked SpreadCurve sc - int num_items = self._thisptr.fNumItems + int num_items = self._thisptr.get().size() double *h - double *T + vector[double] T size_t i bint* mask_ptr if not inplace: sc = SpreadCurve.__new__(SpreadCurve) - curve_tweaked = JpmcdsCopyCurve(self._thisptr) - sc._thisptr = curve_tweaked + curve_tweaked = JpmcdsCopyCurve(self._thisptr.get().data()) + sc._thisptr = make_shared[CurveObject](curve_tweaked) else: sc = self - curve_tweaked = self._thisptr + curve_tweaked = self._thisptr.get().data() h = <double*>malloc(num_items * sizeof(double)) - T = <double*>malloc(num_items * sizeof(double)) + T = vector[double](num_items) for i in range(num_items): T[i] = (curve_tweaked.fArray[i].fDate - curve_tweaked.fBaseDate) / 365. if mask is not None: - if mask.shape[0] != self._thisptr.fNumItems: + if mask.shape[0] != self._thisptr.get().size(): raise ValueError("mask size need to be the same as the number of Items") mask_ptr = &mask[0] else: mask_ptr = NULL - tweak_curve(self._thisptr, curve_tweaked, epsilon, h, T, mask_ptr, num_items) + tweak_curve(self._thisptr.get().data(), curve_tweaked, epsilon, h, T, mask_ptr) free(h) - free(T) return sc diff --git a/pyisda/flat_hazard.pyx b/pyisda/flat_hazard.pyx index fc93b1d..4922239 100644 --- a/pyisda/flat_hazard.pyx +++ b/pyisda/flat_hazard.pyx @@ -52,7 +52,7 @@ def strike_vec(double[:] spreads, YieldCurve yc, trade_date, value_date, cdef double zero_upfront = 0 for i in range(spreads.shape[0]): sc = JpmcdsCleanSpreadCurve(trade_date_c, - yc._thisptr, + yc._thisptr.get().data(), start_date_c, step_in_date_c, value_date_c, @@ -69,11 +69,11 @@ def strike_vec(double[:] spreads, YieldCurve yc, trade_date, value_date, <long>'M', b'NONE') if JpmcdsContingentLegPV(default_leg, trade_date_c, value_date_c, - step_in_date_c, yc._thisptr, sc, + step_in_date_c, yc._thisptr.get().data(), sc, recovery_rate, &default_leg_pv[i]) != 0: raise ValueError("Something went wrong") if JpmcdsFeeLegPV(fee_leg, trade_date_c, step_in_date_c, value_date_c, - yc._thisptr, sc, True, &coupon_leg_pv[i]) != 0: + yc._thisptr.get().data(), sc, True, &coupon_leg_pv[i]) != 0: raise ValueError("Something went wrong") JpmcdsFeeLegFree(fee_leg) free(default_leg) @@ -159,7 +159,7 @@ def pv_vec(double[:] spreads, YieldCurve yc, trade_date, value_date, params = <cds_bootstrap_ctx*>malloc(sizeof(cds_bootstrap_ctx)) params.stepinDate = step_in_date_c params.cashSettleDate = value_date_c - params.discountCurve = yc._thisptr + params.discountCurve = yc._thisptr.get().data() params.cdsCurve = sc params.recoveryRate = recovery_rate params.cl = default_leg @@ -185,7 +185,7 @@ def pv_vec(double[:] spreads, YieldCurve yc, trade_date, value_date, break sc.fArray[0].fRate = h if JpmcdsFeeLegPV(fee_leg, trade_date_c, step_in_date_c, value_date_c, - yc._thisptr, sc, True, &coupon_leg_pv) != 0: + yc._thisptr.get().data(), sc, True, &coupon_leg_pv) != 0: printf("Something went wrong\n") pv[i] = coupon_leg_pv * (spreads[i] - fixed_rate) free(params) diff --git a/pyisda/legs.pyx b/pyisda/legs.pyx index 71e300c..c558816 100644 --- a/pyisda/legs.pyx +++ b/pyisda/legs.pyx @@ -59,7 +59,8 @@ cdef class ContingentLeg: cdef TDate value_date_c = pydate_to_TDate(value_date) cdef double pv if JpmcdsContingentLegPV(self._thisptr, today_c, value_date_c, step_in_date_c, - yc._thisptr, sc._thisptr, recovery_rate, &pv) == 0: + yc._thisptr.get().data(), sc._thisptr.get().data(), + recovery_rate, &pv) == 0: return pv else: raise ValueError @@ -164,7 +165,7 @@ cdef class FeeLeg: cdef TDate value_date_c = pydate_to_TDate(value_date) cdef double pv if JpmcdsFeeLegPV(self._thisptr, today_c, step_in_date_c, value_date_c, - yc._thisptr, sc._thisptr, pay_accrued_at_start, &pv) == 0: + yc._thisptr.get().data(), sc._thisptr.get().data(), pay_accrued_at_start, &pv) == 0: return pv else: raise ValueError |
