summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c_layer/survival_curve.hpp88
-rw-r--r--pyisda/credit_index.pxd4
-rw-r--r--pyisda/credit_index.pyx107
-rw-r--r--pyisda/curve.pxd48
-rw-r--r--pyisda/curve.pyx107
5 files changed, 243 insertions, 111 deletions
diff --git a/c_layer/survival_curve.hpp b/c_layer/survival_curve.hpp
new file mode 100644
index 0000000..7032687
--- /dev/null
+++ b/c_layer/survival_curve.hpp
@@ -0,0 +1,88 @@
+#include <string>
+
+struct CurveName {
+ enum class __attribute__ ((__packed__)) Seniority {
+ Senior,
+ Subordinated
+ };
+
+ enum class __attribute__ ((__packed__)) DocClause {
+ XR14,
+ MR14,
+ MM14,
+ CR14
+ };
+ void serialize(unsigned char* buf) {
+ memcpy(buf, &seniority, sizeof(Seniority));
+ buf += sizeof(Seniority);
+ memcpy(buf, &doc_clause, sizeof(DocClause));
+ buf += sizeof(DocClause);
+ strcpy((char*)buf, ticker.c_str());
+ };
+
+ std::string full_ticker() {
+ std::string r = ticker;
+ return r.append("_").append(str_seniority()).
+ append("_").append(str_doc_clause());
+ }
+
+ void serialize(unsigned char* buf, size_t num) {
+ memcpy(buf, &seniority, sizeof(Seniority));
+ buf += sizeof(Seniority);
+ memcpy(buf, &doc_clause, sizeof(DocClause));
+ buf += sizeof(DocClause);
+ strncpy((char*)buf, ticker.c_str(), num);
+ };
+
+ CurveName(std::string& ticker, Seniority seniority, DocClause doc_clause) :
+ ticker(ticker),
+ seniority(seniority),
+ doc_clause(doc_clause) {};
+
+ CurveName(const unsigned char* buf) {
+ memcpy(&seniority, buf, sizeof(Seniority));
+ buf += sizeof(Seniority);
+ memcpy(&doc_clause, buf, sizeof(DocClause));
+ buf += sizeof(DocClause);
+ ticker = std::string((char*)buf);
+ }
+
+ CurveName() {};
+
+ size_t size() {
+ return sizeof(Seniority) + sizeof(DocClause) + ticker.length() + 1;
+ };
+
+ bool operator<(const CurveName &other) const {
+
+ return ticker < other.ticker ||
+ ((ticker == other.ticker) && (seniority < other.seniority)) ||
+ ((ticker == other.ticker) && (seniority == other.seniority) && (doc_clause < other.doc_clause));
+ }
+
+ std::string str_seniority() const {
+ switch (seniority) {
+ case Seniority::Senior:
+ return "Senior";
+ case Seniority::Subordinated:
+ return "Subordinated";
+ };
+ }
+
+ std::string str_doc_clause() const {
+ switch (doc_clause) {
+ case DocClause::XR14:
+ return "XR14";
+ case DocClause::MR14:
+ return "MR14";
+ case DocClause::MM14:
+ return "MM14";
+ case DocClause::CR14:
+ return "CR14";
+ }
+ }
+
+ std::string ticker;
+ Seniority seniority;
+ DocClause doc_clause;
+};
diff --git a/pyisda/credit_index.pxd b/pyisda/credit_index.pxd
index 43c1eb5..eadb8f8 100644
--- a/pyisda/credit_index.pxd
+++ b/pyisda/credit_index.pxd
@@ -1,6 +1,6 @@
from .legs cimport TContingentLeg, TFeeLeg
from .date cimport TDate
-from .curve cimport TCurve, TRatePt, shared_ptr
+from .curve cimport TCurve, TRatePt, shared_ptr, CurveName
from libcpp.vector cimport vector
from libcpp.map cimport map
from libcpp.string cimport string
@@ -9,7 +9,7 @@ cdef class CurveList:
cdef TDate base_date
cdef vector[double] _weights
cdef vector[shared_ptr[TCurve]] _curves
- cdef map[string, size_t] tickers
+ cdef map[CurveName, size_t] names
cdef vector[shared_ptr[double]] recovery_rates
cdef vector[TDate] defaulted
diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx
index d2dde30..74bd409 100644
--- a/pyisda/credit_index.pyx
+++ b/pyisda/credit_index.pyx
@@ -3,7 +3,7 @@ from libc.stdlib cimport malloc, free
from libc.math cimport nan, isnan
from libc.string cimport memcpy, memset
from libcpp.pair cimport pair
-from libcpp.memory cimport unique_ptr
+from libcpp.memory cimport make_shared
from cython.operator cimport dereference as deref, preincrement as preinc
from cpython cimport PyObject, Py_INCREF
from cython.parallel cimport prange, parallel
@@ -12,8 +12,9 @@ cimport cython
from .legs cimport (JpmcdsCdsContingentLegMake, JpmcdsCdsFeeLegMake,
JpmcdsContingentLegPV, JpmcdsFeeLegPV, FeeLegAI, JpmcdsFeeLegFree)
from .curve cimport (SpreadCurve, JpmcdsCopyCurve, tweak_curve, YieldCurve,
- JpmcdsFreeTCurve, survival_prob, Hash64WithSeed,
- Hash64, uint64_t, TCurve_size, serialize)
+ JpmcdsFreeTCurve, survival_prob, Hash64WithSeed,
+ Hash64, uint64_t, TCurve_size, serialize, CurveName,
+ Seniority, DocClause, get_TCurve)
from .date cimport (pydate_to_TDate, TDate_to_pydate, JpmcdsDtFwdAny,
TDateInterval, JpmcdsMakeDateInterval)
from .cdsone cimport JpmcdsStringToStubMethod, TStubMethod
@@ -23,8 +24,6 @@ np.import_array()
import pandas as pd
import warnings
-cdef inline shared_ptr[TCurve] make_shared(TCurve* ptr) nogil:
- return shared_ptr[TCurve](ptr, JpmcdsFreeTCurve)
ctypedef TFeeLeg* TFeeLeg_ptr
ctypedef TContingentLeg* TContingentLeg_ptr
@@ -54,7 +53,7 @@ cdef class CurveList:
cdef:
SpreadCurve sc
size_t i
- map[string, size_t].iterator it
+ map[CurveName, size_t].iterator it
size_t n = len(curves)
double w
@@ -70,9 +69,9 @@ cdef class CurveList:
cdef double total_weight = 0.
for w, sc in curves:
if sc is not None:
- it = self.tickers.find(sc.ticker)
- if it == self.tickers.end():
- self.tickers[sc.ticker] = i
+ it = self.names.find(deref(sc.name))
+ if it == self.names.end():
+ self.names[deref(sc.name)] = i
self._curves.push_back(sc._thisptr)
self.recovery_rates.push_back(sc.recovery_rates)
self._weights.push_back(w)
@@ -90,32 +89,35 @@ cdef class CurveList:
for i in range(self._weights.size()):
self._weights[i] /= total_weight
- def __getitem__(self, str ticker):
+ def __getitem__(self, tuple name):
cdef:
- string ticker_cpp = ticker
- map[string, size_t].iterator got = \
- self.tickers.find(ticker_cpp)
+ string ticker_cpp = name[0]
+ CurveName.Seniority seniority = <CurveName.Seniority>(<int>name[1])
+ CurveName.DocClause doc_clause = <CurveName.DocClause>(<int>name[2])
+ shared_ptr[CurveName] name_cpp = make_shared[CurveName](ticker_cpp, seniority, doc_clause)
+ map[CurveName, size_t].iterator got = \
+ self.names.find(deref(name_cpp))
SpreadCurve sc
- if got == self.tickers.end():
- raise KeyError(ticker)
+ if got == self.names.end():
+ raise KeyError(name)
else:
sc = SpreadCurve.__new__(SpreadCurve)
sc._thisptr = self._curves[deref(got).second]
sc.recovery_rates = self.recovery_rates[deref(got).second]
- sc.ticker = ticker_cpp
+ sc.name = name_cpp
sc.defaulted = self.defaulted[deref(got).second]
return sc
def items(self):
cdef:
SpreadCurve sc
- pair[string, size_t] p
+ pair[CurveName, size_t] p
- for p in self.tickers:
+ for p in self.names:
sc = SpreadCurve.__new__(SpreadCurve)
sc._thisptr = self._curves[p.second]
- sc.ticker = p.first
+ sc.name = make_shared[CurveName](p.first)
sc.recovery_rates = self.recovery_rates[p.second]
sc.defaulted = self.defaulted[p.second]
yield (sc.ticker, self._weights[p.second], sc)
@@ -131,11 +133,11 @@ cdef class CurveList:
@property
def tickers(self):
- cdef np.npy_intp shape = self.tickers.size()
- cdef pair[string, size_t] p
+ cdef np.npy_intp shape = self.names.size()
+ cdef pair[CurveName, size_t] p
cdef np.ndarray out = np.PyArray_EMPTY(1, &shape, np.NPY_OBJECT, 1)
- for p in self.tickers:
- out[p.second] = p.first
+ for p in self.names:
+ out[p.second] = p.first.ticker
return out
@property
@@ -154,12 +156,12 @@ cdef class CurveList:
cdef:
list r = []
SpreadCurve sc
- pair[string, size_t] p
+ pair[CurveName, size_t] p
- for p in self.tickers:
+ for p in self.names:
sc = SpreadCurve.__new__(SpreadCurve)
sc._thisptr = self._curves[p.second]
- sc.ticker = p.first
+ sc.name = make_shared[CurveName](p.first)
sc.recovery_rates = self.recovery_rates[p.second]
sc.defaulted = self.defaulted[p.second]
r.append((self._weights[p.second], sc))
@@ -168,7 +170,7 @@ cdef class CurveList:
@curves.setter
def curves(self, list l not None):
self._curves.clear()
- self.tickers.clear()
+ self.names.clear()
self._weights.clear()
self.recovery_rates.clear()
self.defaulted.clear()
@@ -265,30 +267,23 @@ cdef class CreditIndex(CurveList):
def __hash__(self):
cdef:
TCurve* curve = self._curves[0].get()
- size_t size = TCurve_size(curve.fNumItems)
+ size_t size = TCurve_size(curve)
size_t size_recovery = curve.fNumItems * sizeof(double)
- size_t buf_size = size + size_recovery + 8 + sizeof(TDate)
+ size_t buf_size = size + size_recovery + sizeof(TDate) + \
+ sizeof(CurveName.Seniority) + sizeof(DocClause) + 14
unsigned char* buf = <unsigned char*>malloc(buf_size)
unsigned char* cursor
- unsigned char* start = buf + size
- size_t i
uint64_t h = 0
- pair[string, size_t] p
+ pair[CurveName, size_t] p
- for p in self.tickers:
- cursor = start
+ for p in self.names:
curve = self._curves[p.second].get()
- serialize(curve, buf)
- if p.first.length() < 8:
- p.first.copy(<char*>cursor, p.first.length(), 0)
- #0 padding
- memset(cursor + p.first.length(), 0, 8 - p.first.length())
- else:
- p.first.copy(<char*>cursor, 8, 0)
- cursor += 8
+ cursor = serialize(curve, buf)
memcpy(cursor, self.recovery_rates[p.second].get(), size_recovery)
cursor += size_recovery
memcpy(cursor, &self.defaulted[p.second], sizeof(TDate))
+ cursor += sizeof(TDate)
+ p.first.serialize(cursor, 14)
h ^= Hash64(<char*>buf, buf_size)
free(buf)
@@ -313,8 +308,8 @@ cdef class CreditIndex(CurveList):
list tickers = []
np.ndarray[np.int64_t,ndim=1] d = np.PyArray_EMPTY(1, &n[1], np.NPY_INT64, 0)
TDate maturity
- TCurve* sc
- pair[string, size_t] p
+ const TCurve* sc
+ pair[CurveName, size_t] p
double recovery_rate
for maturity in self._maturities:
@@ -322,9 +317,9 @@ cdef class CreditIndex(CurveList):
j += 1
j = 0
- for p in self.tickers:
+ for p in self.names:
sc = self._curves[p.second].get()
- tickers.append(p.first)
+ tickers.append(p.first.ticker)
# TODO: pick the actual recovery on the curve
# this only works for flat recovery curve
recovery_rate = self.recovery_rates[p.second].get()[0]
@@ -333,7 +328,7 @@ cdef class CreditIndex(CurveList):
sc.fBaseDate,
cash_settle_date_c,
step_in_date_c,
- yc._thisptr.get(),
+ get_TCurve(yc),
sc,
recovery_rate,
&cl_pv[i,j])
@@ -341,7 +336,7 @@ cdef class CreditIndex(CurveList):
sc.fBaseDate,
step_in_date_c,
cash_settle_date_c,
- yc._thisptr.get(),
+ get_TCurve(yc),
sc,
True,
&fl_pv[i,j])
@@ -383,7 +378,7 @@ cdef class CreditIndex(CurveList):
raise ValueError("maturity is not correct")
with nogil:
r = pv(self._curves, self.base_date, step_in_date_c, cash_settle_date_c,
- yc._thisptr.get(), legs, self.recovery_rates, fixed_rate,
+ get_TCurve(yc), legs, self.recovery_rates, fixed_rate,
self._weights, epsilon, mask)
if i == -1:
free(legs.first)
@@ -423,7 +418,7 @@ cdef class CreditIndex(CurveList):
legs.first = self.contingent_legs[i]
legs.second = self.fee_legs[i]
old_pv = pv(self._curves, self.base_date, step_in_date_c,
- cash_settle_date_c, yc._thisptr.get(), legs,
+ cash_settle_date_c, get_TCurve(yc), legs,
self.recovery_rates, fixed_rate, self._weights,
0., 0)
if i == -1:
@@ -440,7 +435,7 @@ cdef class CreditIndex(CurveList):
cdef r = old_pv - pv(self._curves, self.base_date, step_in_date_c,
cash_settle_date_c,
- yc._thisptr.get(), legs, self.recovery_rates, fixed_rate,
+ get_TCurve(yc), legs, self.recovery_rates, fixed_rate,
self._weights, 0., 0) + carry
if i == -1:
free(legs.first)
@@ -563,7 +558,7 @@ cdef class CreditIndex(CurveList):
def survival_matrix(self, TDate[:] schedule, double epsilon=0.):
cdef:
shared_ptr[TCurve] sc
- pair[string, size_t] p
+ pair[CurveName, size_t] p
size_t i
np.npy_intp[2] n
n[0] = self._curves.size()
@@ -572,9 +567,9 @@ cdef class CreditIndex(CurveList):
np.ndarray[np.float64_t, ndim=2] sp = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 1)
np.ndarray tickers = np.PyArray_EMPTY(1, n, np.NPY_OBJECT, 1)
- for p in self.tickers:
+ for p in self.names:
sc = self._curves[p.second]
- tickers[p.second] = p.first
+ tickers[p.second] = p.first.ticker
for i in range(n[1]):
sp[p.second, i] = survival_prob(sc.get(), self.base_date, schedule[i], epsilon)
return sp, tickers
@@ -642,11 +637,11 @@ cdef double pv(const vector[shared_ptr[TCurve]]& curves,
TDate base_date,
TDate step_in_date,
TDate cash_settle_date,
- TCurve* yc,
+ const TCurve* yc,
pair[TContingentLeg_ptr, TFeeLeg_ptr]& legs,
const vector[shared_ptr[double]] &recovery_rates,
double fixed_rate,
- vector[double]& weights,
+ const vector[double]& weights,
double epsilon,
unsigned long mask) nogil:
cdef:
diff --git a/pyisda/curve.pxd b/pyisda/curve.pxd
index c885d10..de79d38 100644
--- a/pyisda/curve.pxd
+++ b/pyisda/curve.pxd
@@ -65,12 +65,6 @@ cdef inline void serialize_vector(const vector[TDate]& v, unsigned char* cursor)
cursor += sizeof(size_t)
memcpy(cursor, v.data(), sizeof(TDate) * v.size())
-cdef inline unsigned char* serialize_string(const string& s, unsigned char* cursor) nogil:
- cdef size_t size = s.length()
- memcpy(cursor, &size, sizeof(size_t))
- cursor += sizeof(size_t)
- cursor += s.copy(<char*>cursor, s.length(), 0)
- return cursor
cdef inline unsigned char* deserialize(unsigned char* buf, TCurve* curve) nogil:
memcpy(&curve.fNumItems, buf, sizeof(curve.fNumItems))
@@ -210,20 +204,56 @@ cdef extern from "<memory>" namespace "std" nogil:
shared_ptr()
shared_ptr(T*, D)
T* get()
+ T& operator*()
void reset(T*, D)
bool operator!()
long use_count()
+ cdef shared_ptr[T] make_shared[T](...)
+
+cdef extern from "survival_curve.hpp" nogil:
+ cdef cppclass CurveName:
+ enum Seniority:
+ Senior
+ Subordinated
+
+ enum DocClause:
+ XR14
+ MR14
+ MM14
+ CR14
+
+ string ticker
+ Seniority seniority
+ DocClause doc_clause
+ CurveName(string&, Seniority, DocClause)
+ CurveName(const unsigned char* buf)
+ void serialize(unsigned char* buf)
+ void serialize(unsigned char* buf, size_t)
+ string full_ticker()
+ size_t size()
+
+cpdef enum DocClause:
+ XR14
+ MR14
+ MM14
+ CR14
+
+cpdef enum Seniority:
+ Senior
+ Subordinated
+
+cdef inline const TCurve* get_TCurve(Curve c) nogil:
+ return <TCurve*>c._thisptr.get()
cdef class Curve:
cdef shared_ptr[TCurve] _thisptr
- cdef size_t size(self)
- cdef const TCurve* curve(self)
+ cdef size_t size(self) nogil
cdef class YieldCurve(Curve):
cdef vector[TDate] dates
cdef class SpreadCurve(Curve):
- cdef public string ticker
+ cdef shared_ptr[CurveName] name
cdef shared_ptr[double] recovery_rates
cdef TDate defaulted
diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx
index a9cbbcf..cb472e2 100644
--- a/pyisda/curve.pyx
+++ b/pyisda/curve.pyx
@@ -1,3 +1,4 @@
+from cython.operator import dereference as deref
from libc.math cimport log1p, log, exp, isnan
from .date cimport (JpmcdsStringToDateInterval, pydate_to_TDate, dcc, TMonthDayYear,
JpmcdsDateIntervalToFreq, JpmcdsDateFwdThenAdjust, TDate_to_pydate,
@@ -29,14 +30,11 @@ cdef extern from "numpy/arrayobject.h":
cdef int SUCCESS = 0
-cdef inline shared_ptr[TCurve] make_shared(TCurve* ptr) nogil:
- return shared_ptr[TCurve](ptr, JpmcdsFreeTCurve)
-
cdef inline void double_free(double* ptr) nogil:
free(ptr)
-cdef double survival_prob(TCurve* curve, TDate start_date, TDate maturity_date, double eps) nogil:
+cdef double survival_prob(const TCurve* curve, TDate start_date, TDate maturity_date, double eps) nogil:
cdef:
double lambda1, lambda2
double t1, t2, u
@@ -151,7 +149,7 @@ cdef class Curve(object):
if isinstance(self, YieldCurve):
name = 'forward_rates'
elif isinstance(self, SpreadCurve):
- name = (<SpreadCurve>self).ticker
+ name = (<SpreadCurve>self).name.get().ticker
if name == "":
name = "hazard_rates"
return pd.Series(h, index=d.view('M8[D]'), name=name)
@@ -455,19 +453,13 @@ cdef void tweak_curve(const TCurve* sc, TCurve* sc_tweaked, double epsilon,
h1 = t1 = c = 0
cdef size_t i
- if mask == 0:
- for i in range(sc.fNumItems):
- h2 = sc.fArray[i].fRate
- t2 = (sc.fArray[i].fDate - sc.fBaseDate) / 365.
- c += h2 * t2 - h1 * t1
- sc_tweaked.fArray[i].fRate = c / t2
- h1 = h2
- t1 = t2
+ if mask == 0 or epsilon == 0.:
+ return
else:
for i in range(sc.fNumItems):
h2 = sc.fArray[i].fRate
t2 = (sc.fArray[i].fDate - sc.fBaseDate) / 365.
- c += (h2 * t2 - h1 * t1) * ( 1 + epsilon * ((mask >> i) & 1))
+ c += (h2 * t2 - h1 * t1) * (1 + epsilon * ((mask >> i) & 1))
sc_tweaked.fArray[i].fRate = c / t2
h1 = h2
t1 = t2
@@ -498,12 +490,15 @@ cdef class SpreadCurve(Curve):
cash_settle_date, end_dates,
double[:] coupon_rates, double[:] upfront_rates,
double[:] recovery_rates, bint pay_accrued_on_default=True,
- str ticker=None, bint fill_curve=True, defaulted=None):
+ str ticker="", Seniority seniority=Senior,
+ DocClause doc_clause=XR14,
+ bint fill_curve=True, defaulted=None):
cdef TDate today_c = pydate_to_TDate(today)
cdef TDate step_in_date_c
cdef TDate cash_settle_date_c
cdef TDate start_date_c
+ cdef string ticker_cpp = ticker
if start_date is None:
start_date_c = _previous_twentieth(today_c, True)
@@ -605,15 +600,16 @@ cdef class SpreadCurve(Curve):
curve = new_curve
if freeup:
free(end_dates_c)
- self._thisptr = make_shared(curve)
+ self._thisptr.reset(curve, JpmcdsFreeTCurve)
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
+ self.name = make_shared[CurveName](ticker_cpp,
+ <CurveName.Seniority>seniority,
+ <CurveName.DocClause>doc_clause)
if curve is NULL:
if freeup:
@@ -626,7 +622,7 @@ cdef class SpreadCurve(Curve):
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)
+ sizeof(size_t) + sizeof(TDate) + 16
def __getstate__(self):
cdef:
@@ -635,37 +631,35 @@ cdef class SpreadCurve(Curve):
size_t size_recovery = curve.fNumItems * sizeof(double)
unsigned char* buf = <unsigned char*>malloc(buf_size)
unsigned char* cursor = serialize(curve, buf)
-
- cursor = serialize_string(self.ticker, cursor)
memcpy(cursor, self.recovery_rates.get(), size_recovery)
cursor += size_recovery
memcpy(cursor, &self.defaulted, sizeof(TDate))
- cdef bytes r = buf[:buf_size]
+ strcpy(<char*>cursor, self.ticker.c_str())
free(buf)
- return r
+ return buf[:buf_size]
def __setstate__(self, bytes state):
cdef:
TCurve* curve = <TCurve*>malloc(sizeof(TCurve))
unsigned char* cursor = state
size_t ticker_length, recovery_size
+ double* recovery_rates
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
recovery_size = curve.fNumItems * sizeof(double)
- self.recovery_rates = shared_ptr[double](<double*>malloc(recovery_size),
- double_free)
- memcpy(self.recovery_rates.get(), cursor, recovery_size)
+ recovery_rates = <double*>malloc(recovery_size)
+ memcpy(recovery_rates, cursor, recovery_size)
+ cursor += recovery_size
+ self.recovery_rates.reset(recovery_rates, double_free)
cursor += recovery_size
memcpy(&self.defaulted, cursor, sizeof(TDate))
+ cursor += sizeof(TDate)
+ self.ticker = string(<const char*>cursor)
def __deepcopy__(self, dict memo):
cdef SpreadCurve sc = SpreadCurve.__new__(SpreadCurve)
- cdef const TCurve* curve = self.curve()
+ cdef TCurve* curve = self._thisptr.get()
cdef size_t size = curve.fNumItems * sizeof(double)
sc._thisptr = make_shared(JpmcdsCopyCurve(<TCurve*>curve))
sc.ticker = self.ticker
@@ -690,7 +684,7 @@ cdef class SpreadCurve(Curve):
SpreadCurve instance = SpreadCurve.__new__(SpreadCurve)
unsigned char* cursor
TCurve* curve = <TCurve*>malloc(sizeof(TCurve))
- size_t ticker_length, recovery_size
+ size_t recovery_size
Py_buffer* py_buf
if PyMemoryView_Check(state):
@@ -701,38 +695,38 @@ cdef class SpreadCurve(Curve):
cursor = deserialize(cursor, curve)
instance._thisptr = make_shared(curve)
- memcpy(&ticker_length, cursor, sizeof(size_t))
- cursor += sizeof(size_t)
- instance.ticker = string(<char*>cursor, ticker_length)
- cursor += ticker_length
recovery_size = curve.fNumItems * sizeof(double)
instance.recovery_rates = shared_ptr[double](<double*>malloc(recovery_size),
- double_free)
+ double_free)
memcpy(instance.recovery_rates.get(), cursor, recovery_size)
cursor += recovery_size
memcpy(&instance.defaulted, cursor, sizeof(TDate))
+ cursor += sizeof(TDate)
+ instance.name = make_shared[CurveName](cursor)
return instance
def __hash__(self):
# same code as __getstate__
cdef:
- const TCurve* curve = self.curve()
+ const TCurve* curve = get_TCurve(self)
size_t buf_size = self.size()
size_t size_recovery = curve.fNumItems * sizeof(double)
unsigned char* buf = <unsigned char*>malloc(buf_size)
unsigned char* cursor = serialize(curve, buf)
-
- cursor = serialize_string(self.ticker, cursor)
memcpy(cursor, self.recovery_rates.get(), size_recovery)
cursor += size_recovery
memcpy(cursor, &self.defaulted, sizeof(TDate))
+ cursor += sizeof(TDate)
+ self.name.get().serialize(cursor)
cdef uint64_t r = Hash64(<char*>buf, buf_size)
free(buf)
return r
@classmethod
def from_flat_hazard(cls, base_date, double rate, Basis basis=CONTINUOUS,
- str day_count_conv='Actual/365F'):
+ str day_count_conv='Actual/365F', double recov=0.4,
+ str ticker="", Seniority sen=Senior,
+ DocClause doc=XR14):
"""
Alternative constructor for flat hazard rate Curve.
@@ -751,9 +745,17 @@ cdef class SpreadCurve(Curve):
cdef TDate base_date_c = pydate_to_TDate(base_date)
cdef SpreadCurve sc = SpreadCurve.__new__(SpreadCurve)
cdef TDate max_date = 200000 # can go higher but this should be more than enough
+ cdef string ticker_cpp = ticker
+ cdef double* recovery_rates
- sc._thisptr = make_shared(JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1,
- <double>basis, dcc(day_count_conv)))
+ sc._thisptr.reset(JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1,
+ <double>basis, dcc(day_count_conv)),
+ JpmcdsFreeTCurve)
+ recovery_rates = <double*>malloc(sizeof(double))
+ recovery_rates[0] = recov
+ sc.recovery_rates.reset(recovery_rates, double_free)
+ sc.name = make_shared[CurveName](ticker_cpp, <CurveName.Seniority>(sen),
+ <CurveName.DocClause>(doc))
return sc
@cython.boundscheck(False)
@@ -851,12 +853,29 @@ cdef class SpreadCurve(Curve):
@property
def recovery_rates(self):
- cdef np.npy_intp shape = self.curve().fNumItems
+ cdef np.npy_intp shape = get_TCurve(self).fNumItems
cdef np.ndarray[np.float64_t] out = \
np.PyArray_SimpleNewFromData(1, &shape, np.NPY_DOUBLE,
self.recovery_rates.get())
return out
+ @property
+ def ticker(self):
+ return self.name.get().ticker
+
+ @property
+ def full_ticker(self):
+ return self.name.get().full_ticker()
+
+ @property
+ def seniority(self):
+ return Seniority(<int>self.name.get().seniority)
+
+ @property
+ def doc_clause(self):
+ return DocClause(<int>self.name.get().doc_clause)
+
+
@cython.cdivision(True)
@cython.boundscheck(False)
cdef TCurve* _fill_curve(const TCurve* sc, const TDate* end_dates, int n_dates) nogil: