from libc.stdlib cimport free, malloc from libc.string cimport memcpy from .date cimport (pydate_to_TDate, TDate_to_pydate, dcc, JpmcdsStringToStubMethod, MODIFIED) from .date import dcc_tostring from .curve cimport YieldCurve, SpreadCurve cdef class ContingentLeg: """ Initialize a ContingentLeg. Parameters ---------- startdate : :class:`datetime.date` end_date : :class:`datetime.date` notional : float protect_start : bool, optional if True, protection starts at beginning of day. Default to True. """ def __cinit__(self, start_date, end_date, double notional, bint protect_start=True): self._thisptr = JpmcdsCdsContingentLegMake(pydate_to_TDate(start_date), pydate_to_TDate(end_date), notional, protect_start) if self._thisptr is NULL: raise ValueError def __dealloc__(self): if self._thisptr is not NULL: free(self._thisptr) def __reduce__(self): return (self.__class__, (TDate_to_pydate(self._thisptr.startDate + self._thisptr.protectStart), TDate_to_pydate(self._thisptr.endDate), self._thisptr.notional, self._thisptr.protectStart)) def __hash__(self): return hash((self._thisptr.startDate + self._thisptr.protectStart, self._thisptr.endDate, self._thisptr.notional, self._thisptr.protectStart)) @property def end_date(self): return TDate_to_pydate(self._thisptr.endDate) def pv(self, today, step_in_date, value_date, YieldCurve yc not None, SpreadCurve sc not None, double recovery_rate): """ Present Value of the ContingentLeg cashflows. Parameters ---------- today : :class:`datetime.date` step_in_date : :class:`datetime.date` date at which protection starts (usually `today` + 1) value_date : :class:`datetime.date` date at which cashflows are exchanged (usually `today` + 3 business days) yc : :class:`~pyisda.curve.YieldCurve` sc : :class:`~pyisda.curve.SpreadCurve` recovery_rate : float """ cdef TDate today_c = pydate_to_TDate(today) cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) 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.get_TCurve(), sc.get_TCurve(), recovery_rate, &pv) == 0: return pv else: raise ValueError cdef class FeeLeg: """ Initialize a FeeLeg. Parameters ---------- startdate : :class:`datetime.date` date when protection begins. Either start or end of day (depending on `protect_start`) end_date : :class:`datetime.date` date when protection ends (end of day) pay_accrued_on_default : bool Usually set to True notional : float coupon_rate : float payment_dcc : string, optional Default 'ACT/360' protect_start : bool, optional if True, protection starts at beginning of day. Default to True. stub : string, one of 'f/s', 'b/s', 'f/l', 'b/l', optional Default 'f/s' cal : string, default NONE """ def __cinit__(self, start_date, end_date, bint pay_accrued_on_default, double notional, double coupon_rate, str payment_dcc='ACT/360', bint protect_start=True, str stub="f/s", str cal="NONE"): cdef TStubMethod stub_type if JpmcdsStringToStubMethod(stub, &stub_type) != 0: raise ValueError(f"can't convert stub {stub}") self._thisptr = JpmcdsCdsFeeLegMake(pydate_to_TDate(start_date), pydate_to_TDate(end_date), pay_accrued_on_default, NULL, &stub_type, notional, coupon_rate, dcc(payment_dcc), MODIFIED, cal, protect_start) if self._thisptr is NULL: raise ValueError def __reduce__(self): return (self.__class__, (TDate_to_pydate(self._thisptr.accStartDates[0]), TDate_to_pydate(self._thisptr.payDates[self._thisptr.nbDates-1]), self._thisptr.accrualPayConv, self._thisptr.notional, self._thisptr.couponRate, dcc_tostring(self._thisptr.dcc), self._thisptr.obsStartOfDay)) def __hash__(self): return hash((self._thisptr.accStartDates[0], self._thisptr.payDates[self._thisptr.nbDates-1], self._thisptr.accrualPayConv, self._thisptr.notional, self._thisptr.couponRate, self._thisptr.dcc, self._thisptr.obsStartOfDay)) def inspect(self): """convenience method to study the C struct""" cdef list acc_start_dates = [] cdef list acc_end_dates = [] cdef list pay_dates = [] cdef size_t i for i in range(self._thisptr.nbDates): acc_start_dates.append(TDate_to_pydate(self._thisptr.accStartDates[i])) acc_end_dates.append(TDate_to_pydate(self._thisptr.accEndDates[i])) pay_dates.append(TDate_to_pydate(self._thisptr.payDates[i])) return {'acc_start_dates': acc_start_dates, 'acc_end_dates': acc_end_dates, 'pay_dates': pay_dates} @property def cashflows(self): """Cashflow schedule""" cdef TCashFlowList* cfl = JpmcdsFeeLegFlows(self._thisptr) cdef TCashFlow cf result = [] for i in range(cfl.fNumItems): cf = cfl.fArray[i] result.append((TDate_to_pydate(cf.fDate), cf.fAmount)) return result def pv(self, today, step_in_date, value_date, YieldCurve yc not None, SpreadCurve sc not None, bint pay_accrued_at_start): """ Present Value of FeeLeg cashflows. Parameters ---------- today : :class:`datetime.date` step_in_date : :class:`datetime.date` date at which protection starts (usually `today` + 1) value_date : :class:`datetime.date` date at which cashflows are exchanged (usually `today` + 3 business days) yc : :class:`~pyisda.curve.YieldCurve` sc : :class:`~pyisda.curve.SpreadCurve` pay_accrued_at_start : bool True means clean """ cdef TDate today_c = pydate_to_TDate(today) cdef TDate step_in_date_c = pydate_to_TDate(step_in_date) 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.get_TCurve(), sc.get_TCurve(), pay_accrued_at_start, &pv) == 0: return pv else: raise ValueError def accrued(self, today): """Accrued amount as of today Parameters ---------- today : :class:`datetime.date` Return ------ float """ cdef double ai FeeLegAI(self._thisptr, pydate_to_TDate(today), &ai) return ai def __dealloc__(self): if self._thisptr is not NULL: JpmcdsFeeLegFree(self._thisptr) cdef void fee_leg_copy(const TFeeLeg* orig, TFeeLeg* copy) noexcept nogil: cdef int n = orig.nbDates copy.nbDates = n copy.notional = orig.notional copy.couponRate = orig.couponRate copy.dcc = orig.dcc copy.accrualPayConv = orig.accrualPayConv copy.obsStartOfDay = orig.obsStartOfDay copy.accStartDates = malloc(n * sizeof(TDate)) copy.accEndDates = malloc(n * sizeof(TDate)) copy.payDates = malloc(n * sizeof(TDate)) memcpy(copy.accStartDates, orig.accStartDates, n * sizeof(TDate)) memcpy(copy.accEndDates, orig.accEndDates, n * sizeof(TDate)) memcpy(copy.payDates, orig.payDates, n * sizeof(TDate))