diff options
| -rw-r--r-- | pyisda/curve.pyx | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/pyisda/curve.pyx b/pyisda/curve.pyx index a62e103..aa8a40b 100644 --- a/pyisda/curve.pyx +++ b/pyisda/curve.pyx @@ -368,3 +368,67 @@ cdef class SpreadCurve(Curve): sc._thisptr = JpmcdsMakeTCurve(base_date_c, &max_date, &rate, 1, <double>basis, dcc(day_count_conv)) return sc + + def tweak_curve(self, double epsilon, bint multiplicative=True, + bint[:] mask=None, inplace=True): + """ + + Tweak the survival curve in place. + + Parameters + ---------- + epsilon : double + tweaking factor (either additive or multiplicative) + multiplicative : bool, optional + do we scale by 1+epsilon or add epsilon (default multiplicative) + mask : array of bool or None + If None (default), tweak everything, otherwise only tweak values + in the mask + """ + ## We want to tweak in the forward space, so we convert the hazard rates + ## into forward rates and then back + cdef double t1, h1, t2, h2 + cdef TCurve* newcurve = NULL + cdef SpreadCurve sc + cdef int num_items = self._thisptr.fNumItems + if not inplace: + sc = SpreadCurve.__new__(SpreadCurve) + newcurve = <TCurve*>malloc(sizeof(TCurve)) + newcurve.fNumItems = num_items + newcurve.fBaseDate = self._thisptr.fBaseDate + newcurve.fDayCountConv = self._thisptr.fDayCountConv + newcurve.fArray = <TRatePt*>malloc(sizeof(TRatePt) * num_items) + newcurve.fBasis = self._thisptr.fBasis + sc._thisptr = newcurve + + t1 = 0 + h1 = 0 + cdef double* h = <double*>malloc(num_items * sizeof(double)) + cdef double* T = <double*>malloc(num_items * sizeof(double)) + if mask is not None: + if mask.size != self._thisptr.fNumItems: + raise ValueError("mask size need to be the same as the number of Items") + for i in range(num_items): + h2 = log1p(self._thisptr.fArray[i].fRate) + t2 = T[i] = (self._thisptr.fArray[i].fDate - self._thisptr.fBaseDate)/365. + h[i] = (h2 * t2 - h1 * t1) / (t2 - t1) + if mask is None or mask[i]: + h[i] *= (1+epsilon) + h1 = h2 + t1 = t2 + t1 = 0 + cdef double c = 0 + cdef TRatePt* update + if not inplace: + update = self._thisptr.fArray + else: + update = sc._thisptr.fArray + + for i in range(self._thisptr.fNumItems): + c += (T[i] - t1) * h[i] + update[i].fRate = expm1(c/T[i]) + t1 = T[i] + free(h) + free(T) + if not inplace: + return sc |
