summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Horel <guillaume.horel@gmail.com>2017-02-14 17:10:43 -0500
committerGuillaume Horel <guillaume.horel@gmail.com>2017-02-14 17:42:47 -0500
commit4353bc7fa5a20afedb7d40767114b8a7b25767c4 (patch)
tree3cfe43e0cbacfc7ecd1e942a14abe08ff0c3bc31
parent2d1015b1a9307854b61bcccd7eda47fae6297508 (diff)
downloadpyisda-4353bc7fa5a20afedb7d40767114b8a7b25767c4.tar.gz
method to tweak curves
-rw-r--r--pyisda/curve.pyx64
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