summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Horel <guillaume.horel@gmail.com>2018-11-08 11:33:17 -0500
committerGuillaume Horel <guillaume.horel@gmail.com>2018-11-08 16:39:42 -0500
commitda06692cf8e03e58efebcb6a2737e28fb25e038f (patch)
tree32de34f44897be3e0a6b0e4abe7a9f111f028cc4
parente778769df705ca00f5c7f0cf76bc6c957650ab68 (diff)
downloadpyisda-da06692cf8e03e58efebcb6a2737e28fb25e038f.tar.gz
try to fix defaulted curve
-rw-r--r--pyisda/curve.pxd7
-rw-r--r--pyisda/curve.pyx232
2 files changed, 131 insertions, 108 deletions
diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd
index 12ed440..c7362c0 100644
--- a/pyisda/curve.pxd
+++ b/pyisda/curve.pxd
@@ -47,7 +47,7 @@ cdef inline size_t TCurve_size(int num_items) nogil:
return sizeof(int) + sizeof(TDate) + sizeof(double) + \
sizeof(long) + sizeof(TRatePt) * num_items
-cdef inline void serialize(const TCurve* curve, unsigned char* buf) nogil:
+cdef inline unsigned char* serialize(const TCurve* curve, unsigned char* buf) nogil:
memcpy(buf, &(curve.fNumItems), sizeof(curve.fNumItems))
buf += sizeof(curve.fNumItems)
memcpy(buf, curve.fArray, sizeof(TRatePt) * curve.fNumItems)
@@ -57,6 +57,7 @@ cdef inline void serialize(const TCurve* curve, unsigned char* buf) nogil:
memcpy(buf, &(curve.fBasis), sizeof(double))
buf += sizeof(double)
memcpy(buf, &(curve.fDayCountConv), sizeof(long))
+ return buf + sizeof(long)
cdef inline void serialize_vector(const vector[TDate]& v, unsigned char* cursor) nogil:
cdef size_t size = v.size()
@@ -211,12 +212,14 @@ cdef extern from "<memory>" namespace "std" nogil:
cdef class Curve:
cdef shared_ptr[TCurve] _thisptr
+ cdef size_t size(self)
+ cdef const TCurve* curve(self)
cdef class YieldCurve(Curve):
cdef vector[TDate] dates
cdef class SpreadCurve(Curve):
- cdef string ticker
+ cdef public string ticker
cdef shared_ptr[double] recovery_rates
cdef TDate defaulted
diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx
index b435eeb..a575a96 100644
--- a/pyisda/curve.pyx
+++ b/pyisda/curve.pyx
@@ -60,10 +60,9 @@ cdef class Curve(object):
def __getstate__(self):
cdef:
- TCurve* curve = self._thisptr.get()
- size_t curve_size = TCurve_size(curve.fNumItems)
+ size_t curve_size = self.size()
unsigned char* buf = <unsigned char*>malloc(curve_size * sizeof(unsigned char))
- serialize(curve, buf)
+ serialize(self.curve(), buf)
cdef bytes r = buf[:curve_size]
free(buf)
return r
@@ -75,6 +74,9 @@ cdef class Curve(object):
deserialize(cursor, curve)
self._thisptr = make_shared(curve)
+ cdef size_t size(self):
+ return TCurve_size(self._thisptr.get().fNumItems)
+
@classmethod
def from_bytes(cls, object state):
cdef:
@@ -93,8 +95,8 @@ cdef class Curve(object):
def __hash__(self):
cdef:
- TCurve* curve = self._thisptr.get()
- size_t curve_size = TCurve_size(curve.fNumItems)
+ const TCurve* curve = self.curve()
+ size_t curve_size = self.size()
unsigned char* buf = <unsigned char*>malloc(curve_size * sizeof(unsigned char))
serialize(curve, buf)
cdef uint64_t r = Hash64(<char*>buf, curve_size)
@@ -109,24 +111,31 @@ cdef class Curve(object):
dict
contains `base_date`, `basis`, `day_count_counvention` and `data`
"""
-
+ cdef const TCurve* curve = self.curve()
return {'base_date': self.base_date,
- '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)}
+ 'basis': curve.fBasis,
+ 'day_count_convention': dcc_tostring(curve.fDayCountConv),
+ 'data': fArray_to_list(curve.fArray, curve.fNumItems)}
+
+ cdef const TCurve* curve(self):
+ if not self._thisptr:
+ raise ValueError("Curve is not initialized")
+ else:
+ return self._thisptr.get()
@cython.boundscheck(False)
@cython.cdivision(True)
def to_series(self, bint forward=True):
- cdef np.npy_intp n = self._thisptr.get().fNumItems
+ cdef const TCurve* curve = self.curve()
+ cdef np.npy_intp n = curve.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
- cdef TRatePt* it = self._thisptr.get().fArray
+ cdef TRatePt* it = curve.fArray
cdef double t1, h1, t2, h2
t1 = 0
h1 = 0
- cdef int base_date = self._thisptr.get().fBaseDate
+ cdef int base_date = curve.fBaseDate
if forward:
for i in range(n):
h2 = it[i].fRate
@@ -150,16 +159,16 @@ cdef class Curve(object):
def __iter__(self):
cdef:
size_t i = 0
- TRatePt* it = self._thisptr.get().fArray
- for i in range(self._thisptr.get().fNumItems):
+ TRatePt* it = self.curve().fArray
+ for i in range(self.curve().fNumItems):
yield (TDate_to_pydate(it[i].fDate), it[i].fRate)
def __len__(self):
- return self._thisptr.get().fNumItems
+ return self.curve().fNumItems
def __deepcopy__(self, dict memo):
cdef Curve sc = Curve.__new__(Curve)
- sc._thisptr = make_shared(JpmcdsCopyCurve(self._thisptr.get()))
+ sc._thisptr = make_shared(JpmcdsCopyCurve(<TCurve*>self.curve()))
memo[id(self)] = sc
return sc
@@ -167,21 +176,22 @@ cdef class Curve(object):
@cython.cdivision(True)
def forward_hazard_rates(self):
cdef double t1, h1, t2, h2
- cdef np.npy_intp shape = self._thisptr.get().fNumItems
+ cdef const TCurve* curve = self.curve()
+ cdef np.npy_intp shape = curve.fNumItems
t1 = 0
h1 = 0
- cdef TCurve* curve = self._thisptr.get()
- cdef double* data = <double*>malloc(curve.fNumItems * sizeof(double))
+
+ cdef double* data = <double*>malloc(shape * sizeof(double))
cdef size_t i
if <Basis>curve.fBasis == Basis.CONTINUOUS:
- for i in range(curve.fNumItems):
+ for i in range(shape):
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>curve.fBasis == Basis.ANNUAL_BASIS:
- for i in range(curve.fNumItems):
+ for i in range(shape):
h2 = log1p(curve.fArray[i].fRate)
t2 = (curve.fArray[i].fDate - curve.fBaseDate)/365.
data[i] = (h2 * t2 - h1 * t1) / (t2 - t1)
@@ -197,7 +207,7 @@ cdef class Curve(object):
@property
def base_date(self):
- return TDate_to_pydate(self._thisptr.get().fBaseDate)
+ return TDate_to_pydate(self.curve().fBaseDate)
def __forward_zero_price(self, d2, d1=None):
""" computes the forward zero price at a given date.
@@ -210,15 +220,12 @@ cdef class Curve(object):
-------
float
"""
- if not self._thisptr:
- raise ValueError('curve is empty')
- cdef TDate start_date
+ cdef TCurve* curve = <TCurve*>self.curve()
if d1 is None:
- start_date = self._thisptr.get().fBaseDate
- return JpmcdsForwardZeroPrice(self._thisptr.get(), start_date,
+ return JpmcdsForwardZeroPrice(curve, curve.fBaseDate,
pydate_to_TDate(d2))
else:
- return JpmcdsForwardZeroPrice(self._thisptr.get(), pydate_to_TDate(d1),
+ return JpmcdsForwardZeroPrice(curve, pydate_to_TDate(d1),
pydate_to_TDate(d2))
cdef fArray_to_list(TRatePt* fArray, int fNumItems):
@@ -314,14 +321,16 @@ cdef class YieldCurve(Curve):
bad_day_conv, b"None"
))
+ cdef size_t size(self):
+ return Curve.size(self) + sizeof(size_t) + sizeof(TDate) * self.dates.size()
+
def __getstate__(self):
cdef:
- TCurve* curve = self._thisptr.get()
- size_t size = TCurve_size(curve.fNumItems)
- size_t buf_size = size + sizeof(size_t) + sizeof(TDate) * self.dates.size()
+ const TCurve* curve = self.curve()
+ size_t buf_size = self.size()
unsigned char* buf = <unsigned char*>malloc(buf_size)
- unsigned char* cursor = buf + size
- serialize(curve, buf)
+ unsigned char* cursor = serialize(curve, buf)
+
serialize_vector(self.dates, cursor)
cdef bytes r = buf[:buf_size]
free(buf)
@@ -373,12 +382,12 @@ cdef class YieldCurve(Curve):
def __hash__(self):
cdef:
- TCurve* curve = self._thisptr.get()
- size_t size = TCurve_size(curve.fNumItems)
- size_t buf_size = size + sizeof(size_t) + sizeof(TDate) * self.dates.size()
+ const TCurve* curve = self.curve()
+ size_t buf_size = self.size()
+ size_t size
unsigned char* buf = <unsigned char*>malloc(buf_size)
- unsigned char* cursor = buf + size
- serialize(curve, buf)
+ unsigned char* cursor = serialize(curve, buf)
+
size = self.dates.size()
memcpy(cursor, &size, sizeof(size_t))
cursor += sizeof(size_t)
@@ -516,6 +525,7 @@ cdef class SpreadCurve(Curve):
cdef double* tenors_c = NULL
cdef TCurve* curve = NULL
cdef TCurve* new_curve = NULL
+ cdef double* rates = NULL
cdef unsigned int includes = 0
cdef size_t i
cdef bint freeup = False
@@ -527,12 +537,6 @@ cdef class SpreadCurve(Curve):
self.defaulted = -1
else:
self.defaulted = pydate_to_TDate(defaulted)
- self.recovery_rates = shared_ptr[double](
- <double*>malloc(sizeof(double)), double_free)
- self.recovery_rates.get()[0] = recovery_rates[0]
- if ticker:
- self.ticker = ticker
- return
if isinstance(end_dates, list):
n_dates = len(end_dates)
@@ -564,55 +568,72 @@ cdef class SpreadCurve(Curve):
if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0:
raise ValueError("can't convert stub")
with nogil:
- curve = JpmcdsCleanSpreadCurve(today_c,
- yc._thisptr.get(),
- start_date_c,
- step_in_date_c,
- cash_settle_date_c,
- n_dates,
- end_dates_c,
- &coupon_rates[0],
- &upfront_rates[0],
- includes,
- &recovery_rates[0],
- pay_accrued_on_default,
- NULL,
- ACT_360,
- &stub_type,
- <long>'M',
- b'NONE')
+ if defaulted is None:
+ curve = JpmcdsCleanSpreadCurve(today_c,
+ yc._thisptr.get(),
+ start_date_c,
+ step_in_date_c,
+ cash_settle_date_c,
+ n_dates,
+ end_dates_c,
+ &coupon_rates[0],
+ &upfront_rates[0],
+ includes,
+ &recovery_rates[0],
+ pay_accrued_on_default,
+ NULL,
+ ACT_360,
+ &stub_type,
+ <long>'M',
+ b'NONE')
+ else:
+ rates = <double*>malloc(n_dates * sizeof(double))
+ for i in range(n_dates):
+ rates[i] = 1000
+ curve = JpmcdsMakeTCurve(today_c,
+ end_dates_c,
+ rates,
+ n_dates,
+ 5000.,
+ ACT_360)
+ if curve is not NULL:
+ if fill_curve and curve.fNumItems != n_dates:
+ new_curve = _fill_curve(curve, end_dates_c, n_dates)
+ JpmcdsFreeTCurve(curve)
+ curve = new_curve
+ if freeup:
+ free(end_dates_c)
+ self._thisptr = make_shared(curve)
+ self.recovery_rates = shared_ptr[double](
+ <double*>malloc(curve.fNumItems * sizeof(double)),
+ double_free)
+ memcpy(<void*>self.recovery_rates.get(), &recovery_rates[0],
+ curve.fNumItems * sizeof(double))
+
+ if ticker:
+ self.ticker = ticker
+
if curve is NULL:
if freeup:
free(end_dates_c)
raise ValueError("Didn't init the survival curve properly")
- else:
- if fill_curve and curve.fNumItems != n_dates:
- new_curve = _fill_curve(curve, end_dates_c, n_dates)
- JpmcdsFreeTCurve(curve)
- curve = new_curve
- if freeup:
- free(end_dates_c)
- self._thisptr = make_shared(curve)
- self.recovery_rates = shared_ptr[double](
- <double*>malloc(curve.fNumItems * sizeof(double)),
- double_free)
- memcpy(<void*>self.recovery_rates.get(), &recovery_rates[0],
- curve.fNumItems * sizeof(double))
- if ticker:
- self.ticker = ticker
+
survival_probability = Curve.__forward_zero_price
+ cdef size_t size(self):
+ cdef TCurve* curve = self._thisptr.get()
+ return Curve.size(self) + curve.fNumItems * sizeof(double) + \
+ sizeof(size_t) + self.ticker.length() + sizeof(TDate)
+
def __getstate__(self):
cdef:
- TCurve* curve = self._thisptr.get()
- size_t size = TCurve_size(curve.fNumItems)
+ const TCurve* curve = self.curve()
+ size_t buf_size = self.size()
size_t size_recovery = curve.fNumItems * sizeof(double)
- size_t buf_size = size + sizeof(size_t) + self.ticker.length() + \
- size_recovery + sizeof(TDate)
unsigned char* buf = <unsigned char*>malloc(buf_size)
- unsigned char* cursor = buf + size
- serialize(curve, buf)
+ unsigned char* cursor = serialize(curve, buf)
+
cursor = serialize_string(self.ticker, cursor)
memcpy(cursor, self.recovery_rates.get(), size_recovery)
cursor += size_recovery
@@ -625,29 +646,30 @@ cdef class SpreadCurve(Curve):
cdef:
TCurve* curve = <TCurve*>malloc(sizeof(TCurve))
unsigned char* cursor = state
- size_t ticker_length, size
- double* temp
+ size_t ticker_length, recovery_size
+
cursor = deserialize(cursor, curve)
self._thisptr = make_shared(curve)
memcpy(&ticker_length, cursor, sizeof(size_t))
cursor += sizeof(size_t)
self.ticker = string(<char*>cursor, ticker_length)
cursor += ticker_length
- size = curve.fNumItems * sizeof(double)
- self.recovery_rates = shared_ptr[double](<double*>malloc(size),
+ recovery_size = curve.fNumItems * sizeof(double)
+ self.recovery_rates = shared_ptr[double](<double*>malloc(recovery_size),
double_free)
- memcpy(self.recovery_rates.get(), cursor, size)
- cursor += size
+ memcpy(self.recovery_rates.get(), cursor, recovery_size)
+ cursor += recovery_size
memcpy(&self.defaulted, cursor, sizeof(TDate))
def __deepcopy__(self, dict memo):
cdef SpreadCurve sc = SpreadCurve.__new__(SpreadCurve)
- cdef size_t size = self._thisptr.get().fNumItems * sizeof(double)
- sc._thisptr = make_shared(JpmcdsCopyCurve(self._thisptr.get()))
+ cdef const TCurve* curve = self.curve()
+ cdef size_t size = curve.fNumItems * sizeof(double)
+ sc._thisptr = make_shared(JpmcdsCopyCurve(<TCurve*>curve))
sc.ticker = self.ticker
- sc.recovery_rates= shared_ptr[double](<double*>malloc(size), double_free)
+ sc.recovery_rates = shared_ptr[double](<double*>malloc(size), double_free)
memcpy(sc.recovery_rates.get(), self.recovery_rates.get(), size)
- memcpy(&sc.defaulted, &self.defaulted, sizeof(TDate))
+ sc.defaulted = self.defaulted
memo[id(self)] = sc
return sc
@@ -666,7 +688,7 @@ cdef class SpreadCurve(Curve):
SpreadCurve instance = SpreadCurve.__new__(SpreadCurve)
unsigned char* cursor
TCurve* curve = <TCurve*>malloc(sizeof(TCurve))
- size_t ticker_length, size
+ size_t ticker_length, recovery_size
Py_buffer* py_buf
if PyMemoryView_Check(state):
@@ -681,25 +703,23 @@ cdef class SpreadCurve(Curve):
cursor += sizeof(size_t)
instance.ticker = string(<char*>cursor, ticker_length)
cursor += ticker_length
- size = curve.fNumItems * sizeof(double)
- instance.recovery_rates = shared_ptr[double](
- <double*>malloc(size), double_free)
- memcpy(instance.recovery_rates.get(), cursor, size)
- cursor += size
+ recovery_size = curve.fNumItems * sizeof(double)
+ instance.recovery_rates = shared_ptr[double](<double*>malloc(recovery_size),
+ double_free)
+ memcpy(instance.recovery_rates.get(), cursor, recovery_size)
+ cursor += recovery_size
memcpy(&instance.defaulted, cursor, sizeof(TDate))
return instance
def __hash__(self):
# same code as __getstate__
cdef:
- TCurve* curve = self._thisptr.get()
- size_t size = TCurve_size(curve.fNumItems)
+ const TCurve* curve = self.curve()
+ size_t buf_size = self.size()
size_t size_recovery = curve.fNumItems * sizeof(double)
- size_t buf_size = size + sizeof(size_t) + self.ticker.length() + \
- size_recovery + sizeof(TDate)
unsigned char* buf = <unsigned char*>malloc(buf_size)
- unsigned char* cursor = buf + size
- serialize(curve, buf)
+ unsigned char* cursor = serialize(curve, buf)
+
cursor = serialize_string(self.ticker, cursor)
memcpy(cursor, self.recovery_rates.get(), size_recovery)
cursor += size_recovery
@@ -823,7 +843,7 @@ cdef class SpreadCurve(Curve):
@property
def recovery_rates(self):
- cdef np.npy_intp shape = <np.npy_intp>self._thisptr.get().fNumItems
+ cdef np.npy_intp shape = self.curve().fNumItems
cdef np.ndarray[np.float64_t] out = \
np.PyArray_SimpleNewFromData(1, &shape, np.NPY_DOUBLE,
self.recovery_rates.get())
@@ -831,7 +851,7 @@ cdef class SpreadCurve(Curve):
@cython.cdivision(True)
@cython.boundscheck(False)
-cdef TCurve* _fill_curve(TCurve* sc, TDate* end_dates, int n_dates):
+cdef TCurve* _fill_curve(TCurve* sc, TDate* end_dates, int n_dates) nogil:
cdef:
size_t i
TDate base_date = sc.fBaseDate