diff options
| -rw-r--r-- | cpp_layer/curve.hpp | 6 | ||||
| -rw-r--r-- | pyisda/cdsone.pyx | 4 | ||||
| -rw-r--r-- | pyisda/credit_index.pxd | 4 | ||||
| -rw-r--r-- | pyisda/credit_index.pyx | 49 | ||||
| -rw-r--r-- | pyisda/curve.pxd | 5 | ||||
| -rw-r--r-- | pyisda/curve.pyx | 94 | ||||
| -rw-r--r-- | pyisda/flat_hazard.pyx | 10 | ||||
| -rw-r--r-- | pyisda/legs.pyx | 4 |
8 files changed, 88 insertions, 88 deletions
diff --git a/cpp_layer/curve.hpp b/cpp_layer/curve.hpp index fd1db3b..5d1720d 100644 --- a/cpp_layer/curve.hpp +++ b/cpp_layer/curve.hpp @@ -1,6 +1,8 @@ #include <isda/tcurve.h> #include <isda/cxzerocurve.h> #include <vector> +#include <memory> + typedef long TDate; class CurveObject { @@ -69,3 +71,7 @@ double CurveObject::ForwardZeroPrice(TDate d2, TDate d1) { double CurveObject::ForwardZeroPrice(TDate d2) { return JpmcdsForwardZeroPrice(_ptr, _ptr->fBaseDate, d2); } + +std::shared_ptr<TCurve>& make_shared(TCurve* ptr) { + return std::shared_ptr<TCurve>(ptr, jpmcdsFreeTCurve); +} diff --git a/pyisda/cdsone.pyx b/pyisda/cdsone.pyx index ddc3336..074c4ad 100644 --- a/pyisda/cdsone.pyx +++ b/pyisda/cdsone.pyx @@ -59,7 +59,7 @@ def upfront_charge(date, value_date, benchmark_start_date, stepin_date, 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.get().data(), spread, recovery_rate, + yc._thisptr.get(), spread, recovery_rate, pay_accrued_at_start, &result) == SUCCESS: return result else: @@ -121,7 +121,7 @@ def spread_from_upfront(date, value_date, benchmark_start_date, stepin_date, 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.get().data(), upfront, recovery_rate, + yc._thisptr.get(), 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 8051726..e4391e9 100644 --- a/pyisda/credit_index.pxd +++ b/pyisda/credit_index.pxd @@ -1,12 +1,12 @@ from legs cimport TContingentLeg, TFeeLeg from date cimport TDate -from curve cimport CurveObject, TCurve +from curve cimport CurveObject, TCurve, TRatePt from libcpp.memory cimport shared_ptr from libcpp.vector cimport vector cdef class CurveList: cdef TDate _base_date - cdef vector[shared_ptr[CurveObject]] _curves + cdef vector[shared_ptr[TCurve]] _curves cdef vector[double] _T cdef list _tickers cdef dict _tickersdict diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx index 06b0308..a6228a3 100644 --- a/pyisda/credit_index.pyx +++ b/pyisda/credit_index.pyx @@ -21,11 +21,11 @@ cdef class CurveList: else: raise TypeError("curves need to be a list of SpreadCurve "\ "or a list of tuple (SpreadCurve, ticker)") - self._T = vector[double](sc._thisptr.get().size()) - self._base_date = sc._thisptr.get().BaseDate() + self._T = vector[double](sc._thisptr.get().fNumItems) + self._base_date = sc._thisptr.get().fBaseDate cdef size_t i for i in range(self._T.size()): - self._T[i] = (sc._thisptr.get().data().fArray[i].fDate - self._base_date) / 365. + self._T[i] = (sc._thisptr.get().fArray[i].fDate - self._base_date) / 365. self._tickers = [] self._tickersdict = {} @@ -54,10 +54,10 @@ cdef class CurveList: else: raise KeyError(ticker) - def iteritems(self): + def items(self): ## would need to use a shared pointer to avoid a copy cdef SpreadCurve sc - cdef vector[shared_ptr[CurveObject]].iterator it = self._curves.begin() + cdef vector[shared_ptr[TCurve]].iterator it = self._curves.begin() cdef size_t i while it != self._curves.end(): sc = SpreadCurve.__new__(SpreadCurve) @@ -143,13 +143,13 @@ cdef class CreditIndex(CurveList): 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._curves.size()): - sc = self._curves[i].get().data() + sc = self._curves[i].get() for j in range(self._maturities.size()): JpmcdsContingentLegPV(self._contingent_legs[j], sc.fBaseDate, value_date_c, step_in_date_c, - yc._thisptr.get().data(), + yc._thisptr.get(), sc, recovery_rate, &cl_pv[i,j]) @@ -157,7 +157,7 @@ cdef class CreditIndex(CurveList): sc.fBaseDate, step_in_date_c, value_date_c, - yc._thisptr.get().data(), + yc._thisptr.get(), sc, True, &fl_pv[i,j]) @@ -188,28 +188,28 @@ cdef class CreditIndex(CurveList): raise ValueError("maturity is not correct") cdef bint* mask - cdef double* h + cdef vector[double] h cdef TCurve* tweaked_curve if epsilon != 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._T.size()) - tweaked_curve = JpmcdsCopyCurve(self._curves[0].get().data()) + h = vector[double](self._T.size()) + tweaked_curve = JpmcdsCopyCurve(self._curves[0].get()) cdef: double fl_pv, cl_pv, r = 0 for i in range(self._curves.size()): if epsilon != 0: - tweak_curve(self._curves[i].get().data(), tweaked_curve, epsilon, h, self._T, mask) + tweak_curve(self._curves[i].get(), tweaked_curve, epsilon, h, self._T, mask) else: - tweaked_curve = self._curves[i].get().data() + tweaked_curve = self._curves[i].get() JpmcdsContingentLegPV(cl, self._base_date, value_date_c, step_in_date_c, - yc._thisptr.get().data(), + yc._thisptr.get(), tweaked_curve, recovery_rate, &cl_pv) @@ -217,14 +217,13 @@ cdef class CreditIndex(CurveList): self._base_date, step_in_date_c, value_date_c, - yc._thisptr.get().data(), + yc._thisptr.get(), tweaked_curve, True, &fl_pv) r += cl_pv - fl_pv * fixed_rate if epsilon != 0: JpmcdsFreeTCurve(tweaked_curve) - free(h) free(mask) return r / <double>self._curves.size() @@ -238,17 +237,16 @@ cdef class CreditIndex(CurveList): 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._curves[0]) - cdef double* h = <double*>malloc(sizeof(double) * self._T.size()) + cdef vector[double] h = vector[double](self._T.size()) cdef size_t i cdef TCurve* sc for i in range(self._curves.size()): - sc = self._curves[i].get().data() + sc = self._curves[i].get() tweak_curve(sc, sc, epsilon, h, self._T, mask) - free(h) free(mask) cdef bint* fill_mask(TDate maturity, const vector[TDate]& maturities, - const shared_ptr[CurveObject]& sc) nogil: + const shared_ptr[TCurve]& sc) nogil: cdef TDate prev_maturity = 0 cdef size_t i for i in range(maturities.size()): @@ -258,10 +256,9 @@ cdef bint* fill_mask(TDate maturity, const vector[TDate]& maturities, break else: return NULL - 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) + cdef bint* mask = <bint*>malloc(sc.get().fNumItems * sizeof(bint)) + cdef TRatePt* it = sc.get().fArray + for i in range(sc.get().fNumItems): + mask[i] = (it[i].fDate <= maturity ) and \ + (it[i].fDate > prev_maturity) return mask diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd index 31b36b3..d76a2af 100644 --- a/pyisda/curve.pxd +++ b/pyisda/curve.pxd @@ -105,6 +105,7 @@ cdef extern from "../cpp_layer/curve.hpp" nogil: ctypedef TRatePt* iterator iterator begin() iterator end() + shared_ptr[TCurve]& make_shared(TCurve* ptr) cdef extern from "isda/cxzerocurve.h" nogil: double JpmcdsZeroPrice(TCurve* curve, TDate date) @@ -123,7 +124,7 @@ cdef enum Basis: DISCOUNT_FACTOR = -2 cdef class Curve: - cdef shared_ptr[CurveObject] _thisptr + cdef shared_ptr[TCurve] _thisptr cdef class YieldCurve(Curve): cdef TDate* _dates @@ -135,4 +136,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, const vector[double]& T, bint* mask) + const vector[double]& h, const vector[double]& T, bint* mask) diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx index a6c81f3..ab498bd 100644 --- a/pyisda/curve.pyx +++ b/pyisda/curve.pyx @@ -1,7 +1,7 @@ from libc.stdlib cimport malloc, free from libc.string cimport memcpy from libc.math cimport log1p -from libcpp.memory cimport make_shared, shared_ptr +from libcpp.memory cimport shared_ptr from libcpp.vector cimport vector from cython.operator cimport preincrement as preinc @@ -32,7 +32,7 @@ cpdef public enum BadDay: cdef class Curve(object): def __getstate__(self): - cdef TCurve* curve = self._thisptr.get().data() + cdef TCurve* curve = self._thisptr.get() cdef int num_items = curve.fNumItems; return (num_items, <bytes>(<char*>curve.fArray)[:sizeof(TRatePt)*num_items], @@ -56,7 +56,7 @@ cdef class Curve(object): new_curve.fBaseDate = base_date new_curve.fBasis = basis new_curve.fDayCountConv = dcc - self._thisptr = make_shared[CurveObject](new_curve) + self._thisptr = make_shared(new_curve) def inspect(self): """ method to inspect the content of the C struct @@ -68,50 +68,46 @@ cdef class Curve(object): """ return {'base_date': self.base_date, - '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)} + 'basis': self._thisptr.get().fBasis, + 'day_count_convention': dcc_tostring(self._thisptr.get().fDayCountConv), + 'data': fArray_to_list(self._thisptr.get().fArray, self._thisptr.get().fNumItems)} @cython.boundscheck(False) def to_df(self): - cdef np.npy_intp n = self._thisptr.get().data().fNumItems + cdef np.npy_intp n = self._thisptr.get().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 = 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) + cdef size_t i + cdef TRatePt* it = self._thisptr.get().fArray + for i in range(n): + h[i] = it[i].fRate + d[i] = it[i].fDate -134774 return {'hazard_rates': h, 'dates':d.view('M8[D]')} def __iter__(self): cdef: 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) + TRatePt* it = self._thisptr.get().fArray + for i in range(self._thisptr.get().fNumItems): + yield (TDate_to_pydate(it[i].fDate), it[i].fRate) def __len__(self): - return self._thisptr.get().size() + return self._thisptr.get().fNumItems def __deepcopy__(self, memo): cdef Curve sc = type(self).__new__(type(self)) - sc._thisptr = self._thisptr + sc._thisptr = make_shared(JpmcdsCopyCurve(self._thisptr.get())) return sc @property @cython.cdivision(True) def forward_hazard_rates(self): cdef double t1, h1, t2, h2 - cdef np.npy_intp shape = self._thisptr.get().size() + cdef np.npy_intp shape = self._thisptr.get().fNumItems t1 = 0 h1 = 0 - cdef TCurve* curve = self._thisptr.get().data() + cdef TCurve* curve = self._thisptr.get() cdef double* data = <double*>malloc(curve.fNumItems * sizeof(double)) cdef size_t i if <Basis>curve.fBasis == Basis.CONTINUOUS: @@ -138,7 +134,7 @@ cdef class Curve(object): @property def base_date(self): - return TDate_to_pydate(self._thisptr.get().BaseDate()) + return TDate_to_pydate(self._thisptr.get().fBaseDate) def __forward_zero_price(self, d2, d1=None): """ computes the forward zero price at a given date. @@ -155,10 +151,12 @@ cdef class Curve(object): raise ValueError('curve is empty') cdef TDate start_date if d1 is None: - return self._thisptr.get().ForwardZeroPrice(pydate_to_TDate(d2)) + start_date = self._thipstr.get().fBaseDate + return JpmcdsForwardZeroPrice(self._thisptr.get(), start_date, + pydate_to_TDate(d2)) else: - return self._thisptr.get().ForwardZeroPrice(pydate_to_TDate(d2), - pydate_to_TDate(d1)) + return JpmcdsForwardZeroPrice(self._thisptr.get(), pydate_to_TDate(d1), + pydate_to_TDate(d2)) cdef fArray_to_list(TRatePt* fArray, int fNumItems): cdef size_t i @@ -243,7 +241,7 @@ cdef class YieldCurve(Curve): if JpmcdsDateIntervalToFreq(&ivl, &float_freq) != SUCCESS: raise ValueError - self._thisptr = make_shared[CurveObject](JpmcdsBuildIRZeroCurve( + self._thisptr = make_shared(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), @@ -281,7 +279,7 @@ cdef class YieldCurve(Curve): JpmcdsDiscountToRateYearFrac(dfs[i], <double>(yc._dates[i]-base_date_c)/365., <double>1, &rates[i]) - yc._thisptr = make_shared[CurveObject]( + yc._thisptr = make_shared( JpmcdsMakeTCurve(base_date_c, yc._dates, rates, dfs.shape[0], <double>1, dcc(day_count_conv))) return yc @@ -310,19 +308,19 @@ cdef class YieldCurve(Curve): cdef double df for k in range(yc._ninstr): yc._dates[k] = self._dates[i] - df = self._thisptr.get().ForwardZeroPrice(forward_date_c, self._dates[i]) + df = JpmcdsForwardZeroPrice(self._thisptr.get(), forward_date_c, self._dates[i]) JpmcdsDiscountToRateYearFrac( df, <double>(self._dates[i] - forward_date_c)/365., <double>1, &rates[k]) i += 1 - yc._thisptr = make_shared[CurveObject]( - JpmcdsMakeTCurve(forward_date_c, yc._dates, rates, yc._ninstr, - <double>1, self._thisptr.get().data().fDayCountConv)) + yc._thisptr = make_shared(JpmcdsMakeTCurve( + forward_date_c, yc._dates, rates, yc._ninstr, + <double>1, self._thisptr.get().fDayCountConv)) return yc @cython.cdivision(True) cdef void tweak_curve(TCurve* sc, TCurve* sc_tweaked, double epsilon, - double* h, const vector[double]& T, bint* mask): + vector[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 @@ -377,7 +375,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.get().BaseDate(): + if cash_settle_date_c < yc._thisptr.get().fBaseDate: 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): @@ -390,7 +388,7 @@ cdef class SpreadCurve(Curve): with nogil: JpmcdsStringToDayCountConv('ACT/360', &dc) curve = JpmcdsCleanSpreadCurve(today_c, - yc._thisptr.get().data(), + yc._thisptr.get(), start_date_c, step_in_date_c, cash_settle_date_c, @@ -410,7 +408,7 @@ cdef class SpreadCurve(Curve): if curve == NULL: raise ValueError("Didn't init the survival curve properly") else: - self._thisptr = make_shared[CurveObject](curve) + self._thisptr = make_shared(curve) survival_probability = Curve.__forward_zero_price @@ -436,9 +434,8 @@ 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 = make_shared[CurveObject]( - JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1, - <double>basis, dcc(day_count_conv))) + sc._thisptr = make_shared(JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1, + <double>basis, dcc(day_count_conv))) return sc @cython.boundscheck(False) @@ -460,31 +457,30 @@ cdef class SpreadCurve(Curve): cdef: TCurve* curve_tweaked SpreadCurve sc - int num_items = self._thisptr.get().size() - double *h + int num_items = self._thisptr.get().fNumItems + vector[double] h vector[double] T size_t i bint* mask_ptr if not inplace: sc = SpreadCurve.__new__(SpreadCurve) - curve_tweaked = JpmcdsCopyCurve(self._thisptr.get().data()) - sc._thisptr = make_shared[CurveObject](curve_tweaked) + curve_tweaked = JpmcdsCopyCurve(self._thisptr.get()) + sc._thisptr = make_shared(curve_tweaked) else: sc = self - curve_tweaked = self._thisptr.get().data() + curve_tweaked = self._thisptr.get() - h = <double*>malloc(num_items * sizeof(double)) + h = vector[double](num_items) 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.get().size(): + if mask.shape[0] != self._thisptr.get().fNumItems: 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.get().data(), curve_tweaked, epsilon, h, T, mask_ptr) - free(h) + tweak_curve(self._thisptr.get(), curve_tweaked, epsilon, h, T, mask_ptr) return sc diff --git a/pyisda/flat_hazard.pyx b/pyisda/flat_hazard.pyx index 4922239..363ef95 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.get().data(), + yc._thisptr.get(), 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.get().data(), sc, + step_in_date_c, yc._thisptr.get(), 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.get().data(), sc, True, &coupon_leg_pv[i]) != 0: + yc._thisptr.get(), 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.get().data() + params.discountCurve = yc._thisptr.get() 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.get().data(), sc, True, &coupon_leg_pv) != 0: + yc._thisptr.get(), 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 c558816..f80f5f7 100644 --- a/pyisda/legs.pyx +++ b/pyisda/legs.pyx @@ -59,7 +59,7 @@ 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.get().data(), sc._thisptr.get().data(), + yc._thisptr.get(), sc._thisptr.get(), recovery_rate, &pv) == 0: return pv else: @@ -165,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.get().data(), sc._thisptr.get().data(), pay_accrued_at_start, &pv) == 0: + yc._thisptr.get(), sc._thisptr.get(), pay_accrued_at_start, &pv) == 0: return pv else: raise ValueError |
