summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Horel <guillaume.horel@gmail.com>2017-05-17 14:12:05 -0400
committerGuillaume Horel <guillaume.horel@gmail.com>2017-05-17 14:12:05 -0400
commit1f09c1b4a66146d19c8f6ad5f616900a34457adb (patch)
tree6f18aa720528660b7f10446c6a5d091e585b12d7
parent80c57d8132f43cb734442aa2e852413ef7658c19 (diff)
downloadpyisda-1f09c1b4a66146d19c8f6ad5f616900a34457adb.tar.gz
more C++
-rw-r--r--pyisda/credit_index.pxd23
-rw-r--r--pyisda/credit_index.pyx482
2 files changed, 284 insertions, 221 deletions
diff --git a/pyisda/credit_index.pxd b/pyisda/credit_index.pxd
index c6a76ab..3da57f9 100644
--- a/pyisda/credit_index.pxd
+++ b/pyisda/credit_index.pxd
@@ -2,18 +2,21 @@ from legs cimport TContingentLeg, TFeeLeg
from date cimport TDate
from curve cimport TCurve, TRatePt, shared_ptr
from libcpp.vector cimport vector
-from libcpp.map cimport map
+from libcpp.unordered_map cimport unordered_map
from libcpp.string cimport string
cdef class CurveList:
- cdef TDate _base_date
- cdef vector[shared_ptr[TCurve]] _curves
- cdef vector[double] _weights
- cdef vector[double] _T
- cdef map[string, size_t] _tickers
+ cdef TDate base_date
+ cdef public vector[double] weights
+ cdef vector[double] T
+ cdef unordered_map[string, shared_ptr[TCurve]] curves
cdef class CreditIndex(CurveList):
- cdef _start_date
- cdef vector[TDate] _maturities
- cdef TContingentLeg** _contingent_legs
- cdef TFeeLeg** _fee_legs
+ cdef TDate start_date
+ cdef vector[TDate] maturities
+ cdef TContingentLeg** contingent_legs
+ cdef TFeeLeg** fee_legs
+
+cdef extern from "<algorithm>" namespace "std" nogil:
+ Iter find[Iter, T](Iter first, Iter last, const T& val)
+ Iter lower_bound[Iter, T](Iter first, Iter last, const T& value)
diff --git a/pyisda/credit_index.pyx b/pyisda/credit_index.pyx
index 48d188d..1474dd5 100644
--- a/pyisda/credit_index.pyx
+++ b/pyisda/credit_index.pyx
@@ -1,5 +1,7 @@
from libc.stdlib cimport malloc, free
-from cython.operator cimport dereference as deref, preincrement as preinc
+from libcpp.pair cimport pair
+from cython.operator cimport dereference as deref
+
cimport cython
from legs cimport (JpmcdsCdsContingentLegMake, JpmcdsCdsFeeLegMake,
JpmcdsContingentLegPV, JpmcdsFeeLegPV, FeeLegAI, JpmcdsFeeLegFree)
@@ -8,13 +10,15 @@ from curve cimport (SpreadCurve, JpmcdsCopyCurve, tweak_curve, YieldCurve,
from date cimport pydate_to_TDate, TDate_to_pydate, ACT_365F
from cdsone cimport JpmcdsStringToStubMethod, TStubMethod
from date cimport ACT_365F
+from dateutil.relativedelta import relativedelta
cimport numpy as np
np.import_array()
import pandas as pd
cdef class CurveList:
@cython.cdivision(True)
- def __init__(self, curves, double[:] weights=None):
+ @cython.boundscheck(False)
+ def __init__(self, list curves, double[:] weights=None):
cdef:
SpreadCurve sc
size_t i
@@ -23,45 +27,47 @@ cdef class CurveList:
sc = <SpreadCurve>curves[0]
else:
raise TypeError("curves need to be a list of SpreadCurve")
- self._T = vector[double](sc._thisptr.get().fNumItems)
- self._base_date = sc._thisptr.get().fBaseDate
- for i in range(self._T.size()):
- self._T[i] = (sc._thisptr.get().fArray[i].fDate - self._base_date) / 365.
- for i, sc in enumerate(curves):
- self._curves.push_back(sc._thisptr)
- self._tickers[sc.ticker.encode()] = i
+ self.T = vector[double](sc._thisptr.get().fNumItems)
+ self.base_date = sc._thisptr.get().fBaseDate
+ for i in range(self.T.size()):
+ self.T[i] = (sc._thisptr.get().fArray[i].fDate - self.base_date) / 365.
+
+ for sc in curves:
+ self.curves[sc.ticker] = sc._thisptr
if weights is not None:
for i in range(weights.shape[0]):
- self._weights.push_back(weights[i])
+ self.weights.push_back(weights[i])
else:
- self._weights = vector[double](self._curves.size(), 1./self._curves.size())
+ self.weights = vector[double](self.curves.size(), 1./self.curves.size())
def __getitem__(self, str ticker):
cdef:
- map[string, size_t].iterator got = \
- self._tickers.find(ticker.encode())
+ string ticker_cpp = ticker.encode()
+ unordered_map[string, shared_ptr[TCurve]].iterator got = \
+ self.curves.find(ticker_cpp)
SpreadCurve sc
- if got == self._tickers.end():
+ if got == self.curves.end():
raise KeyError(ticker)
else:
sc = SpreadCurve.__new__(SpreadCurve)
- sc._thisptr = self._curves[deref(got).second]
- sc.ticker = ticker
+ sc._thisptr = deref(got).second
+ sc.ticker = ticker_cpp
return sc
def items(self):
## would need to use a shared pointer to avoid a copy
- cdef SpreadCurve sc
- cdef map[string, size_t].const_iterator it = self._tickers.const_begin()
- while it != self._tickers.const_end():
+ cdef:
+ SpreadCurve sc
+ pair[string, shared_ptr[TCurve]] p
+
+ for p in self.curves:
sc = SpreadCurve.__new__(SpreadCurve)
- sc._thisptr = self._curves[deref(it).second]
- sc.ticker = (deref(it).first).decode()
- yield (sc.ticker, sc)
- preinc(it)
+ sc._thisptr = p.second
+ sc.ticker = p.first
+ yield (sc.ticker.decode(), sc)
@property
def curves(self):
@@ -71,84 +77,105 @@ cdef class CurveList:
cdef:
list r = []
SpreadCurve sc
- map[string, size_t].const_iterator it = self._tickers.const_begin()
+ pair[string, shared_ptr[TCurve]] p
- while it != self._tickers.const_end():
+ for p in self.curves:
sc = SpreadCurve.__new__(SpreadCurve)
- sc._thisptr = self._curves[deref(it).second]
- sc.ticker = (deref(it).first).decode()
+ sc._thisptr = p.second
+ sc.ticker = p.first
r.append(sc)
- preinc(it)
return r
@curves.setter
def curves(self, list l):
- cdef size_t len_l = len(l)
- if len_l != self._curves.size():
- self._curves.resize(len_l)
+ cdef:
+ size_t len_l = len(l)
+ size_t i
+ SpreadCurve c
+
+ if len_l != self.curves.size():
+ self.curves.clear()
+
+ c = l[0]
+ self.T.resize(c._thisptr.get().fNumItems)
+ self.base_date = c._thisptr.get().fBaseDate
+
+ for i in range(self.T.size()):
+ self.T[i] = (c._thisptr.get().fArray[i].fDate - self.base_date) / 365.
- cdef size_t i
for i, c in enumerate(l):
- self._curves[i] = (<SpreadCurve?>c)._thisptr
+ self.curves[c.ticker] = c._thisptr
cdef class CreditIndex(CurveList):
- def __init__(self, start_date, maturities, curves, double[:] weights=None):
+ def __init__(self, start_date, maturities, list curves, double[:] weights=None):
CurveList.__init__(self, curves, weights)
- self._start_date = pydate_to_TDate(start_date)
+ self.start_date = pydate_to_TDate(start_date)
for d in maturities:
- self._maturities.push_back(pydate_to_TDate(d))
+ self.maturities.push_back(pydate_to_TDate(d))
- self._contingent_legs = <TContingentLeg**> malloc(self._maturities.size() *
+ self.contingent_legs = <TContingentLeg**> malloc(self.maturities.size() *
sizeof(TContingentLeg))
- self._fee_legs = <TFeeLeg**> malloc(self._maturities.size() *
+ self.fee_legs = <TFeeLeg**> malloc(self.maturities.size() *
sizeof(TFeeLeg))
cdef TStubMethod stub_type
if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0:
raise ValueError("can't convert stub")
cdef size_t i
- for i in range(self._maturities.size()):
- self._contingent_legs[i] = JpmcdsCdsContingentLegMake(self._start_date,
- self._maturities[i],
- 1.,
- True)
+ for i in range(self.maturities.size()):
+ self.contingent_legs[i] = JpmcdsCdsContingentLegMake(self.start_date,
+ self.maturities[i],
+ 1.,
+ True)
- self._fee_legs[i] = JpmcdsCdsFeeLegMake(self._start_date,
- self._maturities[i],
- True,
- NULL,
- &stub_type,
- 1.,
- 1.0,
- 3, #ACT_360
- <long>'M', # MODIFIED
- b'NONE',
- True)
+ self.fee_legs[i] = JpmcdsCdsFeeLegMake(self.start_date,
+ self.maturities[i],
+ True,
+ NULL,
+ &stub_type,
+ 1.,
+ 1.0,
+ 3, #ACT_360
+ <long>'M', # MODIFIED
+ b'NONE',
+ True)
def __dealloc__(self):
- if self._contingent_legs is not NULL:
- for i in range(self._maturities.size()):
- free(self._contingent_legs[i])
- if self._fee_legs is not NULL:
- for i in range(self._maturities.size()):
- JpmcdsFeeLegFree(self._fee_legs[i])
+ if self.contingent_legs is not NULL:
+ for i in range(self.maturities.size()):
+ free(self.contingent_legs[i])
+ if self.fee_legs is not NULL:
+ for i in range(self.maturities.size()):
+ JpmcdsFeeLegFree(self.fee_legs[i])
#@cython.initializedcheck(False)
@cython.boundscheck(False)
def pv_vec(self, step_in_date, value_date, YieldCurve yc, double recovery_rate):
- cdef TDate step_in_date_c = pydate_to_TDate(step_in_date)
- cdef TDate value_date_c = pydate_to_TDate(value_date)
- cdef np.npy_intp[2] n = [self._curves.size(), self._maturities.size()]
- cdef double accrued
- FeeLegAI(self._fee_legs[0], self._base_date, &accrued)
- cdef size_t i, j
+ cdef:
+ TDate step_in_date_c = pydate_to_TDate(step_in_date)
+ TDate value_date_c = pydate_to_TDate(value_date)
+ np.npy_intp[2] n = [self.curves.size(), self.maturities.size()]
+ double accrued
+ size_t i = 0, j = 0
+ np.ndarray[np.float64_t,ndim=2] cl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0)
+ np.ndarray[np.float64_t,ndim=2] fl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0)
+ 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,shared_ptr[TCurve]] p
+
+ FeeLegAI(self.fee_legs[0], self.base_date, &accrued)
+
+ for maturity in self.maturities:
+ d[j] = maturity - 134774
+ j += 1
+ j = 0
- cdef np.ndarray[np.float64_t,ndim=2] cl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0)
- cdef np.ndarray[np.float64_t,ndim=2] fl_pv = np.PyArray_EMPTY(2, n, np.NPY_DOUBLE, 0)
- cdef TCurve* sc
- for i in range(self._curves.size()):
- sc = self._curves[i].get()
- for j in range(self._maturities.size()):
- JpmcdsContingentLegPV(self._contingent_legs[j],
+ for p in self.curves:
+ sc = p.second.get()
+ tickers.append(p.first.decode())
+ for j in range(self.maturities.size()):
+ JpmcdsContingentLegPV(self.contingent_legs[j],
sc.fBaseDate,
value_date_c,
step_in_date_c,
@@ -156,7 +183,7 @@ cdef class CreditIndex(CurveList):
sc,
recovery_rate,
&cl_pv[i,j])
- JpmcdsFeeLegPV(self._fee_legs[j],
+ JpmcdsFeeLegPV(self.fee_legs[j],
sc.fBaseDate,
step_in_date_c,
value_date_c,
@@ -164,14 +191,16 @@ cdef class CreditIndex(CurveList):
sc,
True,
&fl_pv[i,j])
+ i += 1
+
return pd.concat({'duration':
pd.DataFrame(fl_pv - accrued,
- columns=pd.DatetimeIndex(self.maturities),
- index=self._tickers),
+ columns=d.view('M8[D]'),
+ index=tickers),
'protection_pv':
pd.DataFrame(cl_pv,
- columns=pd.DatetimeIndex(self.maturities),
- index=self._tickers)})
+ columns=d.view('M8[D]'),
+ index=tickers)})
@cython.boundscheck(False)
def pv(self, step_in_date, value_date, maturity, YieldCurve yc not None,
@@ -181,59 +210,27 @@ cdef class CreditIndex(CurveList):
TDate step_in_date_c = pydate_to_TDate(step_in_date)
TDate value_date_c = pydate_to_TDate(value_date)
TDate maturity_c = pydate_to_TDate(maturity)
- TContingentLeg* cl
- TFeeLeg* fl
- TStubMethod stub_type
-
- for i in range(self._maturities.size()):
- if self._maturities[i] == maturity_c:
- cl = self._contingent_legs[i]
- fl = self._fee_legs[i]
- break
- else:
- raise ValueError("maturity is not correct")
-
+ unsigned long mask = 0
+ vector[double] h
+ double accrued
+ pair[TContingentLeg,TFeeLeg] legs = get_legs(maturity_c,
+ self.start_date,
+ self.contingent_legs,
+ self.fee_legs,
+ self.maturities)
- cdef bint* mask
- cdef vector[double] h
- cdef TCurve* tweaked_curve
- if epsilon != 0:
- mask = fill_mask(maturity_c, self._maturities, self._curves[0])
- if mask == NULL:
+ if epsilon != 0.:
+ mask = fill_mask(maturity_c, self.maturities, deref(self.curves.begin()).second)
+ if mask == 0:
raise ValueError("maturity is not correct")
- h = vector[double](self._T.size())
- tweaked_curve = JpmcdsCopyCurve(self._curves[0].get())
+ h = vector[double](self.T.size())
+ FeeLegAI(self.fee_legs[0], self.base_date, &accrued)
- cdef:
- double accrued, fl_pv, cl_pv, r = 0
- FeeLegAI(self._fee_legs[0], self._base_date, &accrued)
+ r = pv(self.curves, self.base_date, step_in_date_c, value_date_c,
+ yc._thisptr.get(), legs, recovery_rate, fixed_rate,
+ self.weights, epsilon, h, self.T, mask)
- for i in range(self._curves.size()):
- if epsilon != 0:
- tweak_curve(self._curves[i].get(), tweaked_curve, epsilon, h, self._T, mask)
- else:
- tweaked_curve = self._curves[i].get()
- JpmcdsContingentLegPV(cl,
- self._base_date,
- value_date_c,
- step_in_date_c,
- yc._thisptr.get(),
- tweaked_curve,
- recovery_rate,
- &cl_pv)
- JpmcdsFeeLegPV(fl,
- self._base_date,
- step_in_date_c,
- value_date_c,
- yc._thisptr.get(),
- tweaked_curve,
- True,
- &fl_pv)
- r += self._weights[i] * (cl_pv - (fl_pv - accrued) * fixed_rate)
- if epsilon != 0:
- JpmcdsFreeTCurve(tweaked_curve)
- free(mask)
- return r
+ return r - fixed_rate * accrued
def theta(self, step_in_date, value_date, maturity, YieldCurve yc not None,
double recovery_rate, double fixed_rate):
@@ -241,55 +238,22 @@ cdef class CreditIndex(CurveList):
TDate step_in_date_c = pydate_to_TDate(step_in_date)
TDate value_date_c = pydate_to_TDate(value_date)
TDate maturity_c = pydate_to_TDate(maturity)
- TStubMethod stub_type
- double accrued
-
- FeeLegAI(self._fee_legs[0], self._base_date, &accrued)
- if JpmcdsStringToStubMethod(b"f/s", &stub_type) != 0:
- raise ValueError("can't convert stub")
- cdef:
- TContingentLeg* cl = JpmcdsCdsContingentLegMake(self._start_date,
- maturity_c,
- 1.,
- True)
-
- TFeeLeg* fl = JpmcdsCdsFeeLegMake(self._start_date,
- maturity_c,
- True,
- NULL,
- &stub_type,
- 1.,
- 1.0,
- 3, #ACT_360
- <long>'M', # MODIFIED
- b'NONE',
- True)
+ vector[double] h
+ pair[TContingentLeg,TFeeLeg] legs = get_legs(maturity_c,
+ self.start_date,
+ self.contingent_legs,
+ self.fee_legs,
+ self.maturities)
- vector[shared_ptr[TCurve]].iterator it = self._curves.begin()
- vector[double].iterator w = self._weights.begin()
- double fl_pv, cl_pv, r = 0
-
- while it != self._curves.end():
- JpmcdsContingentLegPV(cl,
- self._base_date,
- value_date_c,
- step_in_date_c,
- yc._thisptr.get(),
- deref(it).get(),
- recovery_rate,
- &cl_pv)
- JpmcdsFeeLegPV(fl,
- self._base_date,
- step_in_date_c,
- value_date_c,
- yc._thisptr.get(),
- deref(it).get(),
- True,
- &fl_pv)
- r += deref(w) * (cl_pv - (fl_pv - accrued) * fixed_rate)
- preinc(it)
- preinc(w)
- return r
+ cdef double old_pv = pv(self.curves, self.base_date, step_in_date_c,
+ value_date_c, yc._thisptr.get(), legs,
+ recovery_rate, fixed_rate, self.weights,
+ 0., h, self.T, 0)
+ maturity_c = pydate_to_TDate(maturity - relativedelta(years=1))
+ return pv(self.curves, self.base_date, step_in_date_c, value_date_c,
+ yc._thisptr.get(), legs, recovery_rate, fixed_rate,
+ self.weights, 0., h, self.T, 0) - \
+ old_pv + fixed_rate
@cython.boundscheck(False)
def duration(self, step_in_date, value_date, maturity, YieldCurve yc not None):
@@ -298,67 +262,163 @@ cdef class CreditIndex(CurveList):
TDate step_in_date_c = pydate_to_TDate(step_in_date)
TDate value_date_c = pydate_to_TDate(value_date)
TDate maturity_c = pydate_to_TDate(maturity)
+ double accrued
+
+ FeeLegAI(self.fee_legs[0], self.base_date, &accrued)
- cdef double accrued
- FeeLegAI(self._fee_legs[0], self._base_date, &accrued)
cdef:
TFeeLeg* fl
+ size_t i
- for i in range(self._maturities.size()):
- if self._maturities[i] == maturity_c:
- fl = self._fee_legs[i]
+ for i in range(self.maturities.size()):
+ if self.maturities[i] == maturity_c:
+ fl = self.fee_legs[i]
break
else:
raise ValueError("maturity is not correct")
-
cdef:
double fl_pv, r = 0
+ pair[string,shared_ptr[TCurve]] p
- for i in range(self._curves.size()):
+ i = 0
+ for p in self.curves:
JpmcdsFeeLegPV(fl,
- self._base_date,
+ self.base_date,
step_in_date_c,
value_date_c,
yc._thisptr.get(),
- self._curves[i].get(),
+ p.second.get(),
True,
&fl_pv)
- r += self._weights[i] * fl_pv
+ r += self.weights[i] * fl_pv
+ i += 1
return r - accrued
@property
def maturities(self):
- cdef list r = []
- for i in range(self._maturities.size()):
- r.append(TDate_to_pydate(self._maturities[i]))
+ cdef:
+ list r = []
+ TDate maturity
+
+ for maturity in self.maturities:
+ r.append(TDate_to_pydate(maturity))
return r
- def tweak_portfolio(self, double epsilon, maturity):
- cdef TDate maturity_c = pydate_to_TDate(maturity)
- cdef bint* mask = fill_mask(maturity_c, self._maturities, self._curves[0])
- cdef vector[double] h = vector[double](self._T.size())
- cdef size_t i
- cdef TCurve* sc
- for i in range(self._curves.size()):
- sc = self._curves[i].get()
- tweak_curve(sc, sc, epsilon, h, self._T, mask)
- free(mask)
+ def tweak_portfolio(self, double epsilon, maturity, inplace=True):
+ cdef:
+ TDate maturity_c = pydate_to_TDate(maturity)
+ unsigned long mask = fill_mask(maturity_c, self.maturities,
+ deref(self.curves.begin()).second)
+ vector[double] h = vector[double](self.T.size())
+ TCurve* sc
+ pair[string, shared_ptr[TCurve]] p
+
+ for p in self.curves:
+ sc = p.second.get()
+ tweak_curve(sc, sc, epsilon, h, self.T, mask)
+
+cdef unsigned long fill_mask(const TDate maturity, const vector[TDate]& maturities,
+ const shared_ptr[TCurve]& sc) nogil:
+ cdef:
+ TDate prev_maturity = 0
+ size_t i
+ vector[TDate].const_iterator index = lower_bound(maturities.const_begin(),
+ maturities.const_end(),
+ maturity)
+ unsigned long mask = 0
+
+ if index == maturities.end():
+ return 0
+ elif index != maturities.begin():
+ prev_maturity = deref(index-1)
+
+ cdef TRatePt* it = sc.get().fArray
+ for i in range(sc.get().fNumItems):
+ if (it[i].fDate <= maturity ) and \
+ (it[i].fDate > prev_maturity):
+ mask |= 1 << i
+ return mask
+
+cdef pair[TContingentLeg,TFeeLeg] get_legs(TDate maturity,
+ TDate start_date,
+ TContingentLeg** contingent_legs,
+ TFeeLeg** fee_legs,
+ vector[TDate]& maturities) nogil:
+ cdef:
+ pair[TContingentLeg,TFeeLeg] r
+ TStubMethod stub_type
-cdef bint* fill_mask(TDate maturity, const vector[TDate]& maturities,
- const shared_ptr[TCurve]& sc) nogil:
- cdef TDate prev_maturity = 0
- cdef size_t i
for i in range(maturities.size()):
if maturities[i] == maturity:
- if i > 0:
- prev_maturity = maturities[i-1]
break
else:
- return NULL
- cdef bint* mask = <bint*>malloc(sc.get().fNumItems * sizeof(bint))
- cdef TRatePt* it = sc.get().fArray
- for i in range(sc.get().fNumItems):
- mask[i] = (it[i].fDate <= maturity ) and \
- (it[i].fDate > prev_maturity)
- return mask
+ JpmcdsStringToStubMethod(b"f/s", &stub_type)
+ r.first = deref(JpmcdsCdsContingentLegMake(start_date,
+ maturity,
+ 1.,
+ True))
+ r.second = deref(JpmcdsCdsFeeLegMake(start_date,
+ maturity,
+ True,
+ NULL,
+ &stub_type,
+ 1.,
+ 1.0,
+ 3, #ACT_360
+ <long>'M', # MODIFIED
+ b'NONE',
+ True))
+ return r
+ r.first = deref(contingent_legs[i])
+ r.second = deref(fee_legs[i])
+ return r
+
+cdef double pv(unordered_map[string,shared_ptr[TCurve]]& curves,
+ TDate base_date,
+ TDate step_in_date,
+ TDate value_date,
+ TCurve* yc,
+ pair[TContingentLeg,TFeeLeg]& legs,
+ double recovery_rate,
+ double fixed_rate,
+ vector[double]& weights,
+ double epsilon,
+ vector[double]& h,
+ vector[double]& T,
+ unsigned long mask) nogil:
+ cdef:
+ double fl_pv, cl_pv, r = 0
+ TCurve* tweaked_curve
+ pair[string, shared_ptr[TCurve]] p
+ size_t i = 0
+ TFeeLeg* fl
+ TContingentLeg* cl
+
+ if epsilon != 0.:
+ tweaked_curve = JpmcdsCopyCurve(deref(curves.begin()).second.get())
+
+ for p in curves:
+ if epsilon != 0.:
+ tweak_curve(p.second.get(), tweaked_curve, epsilon, h, T, mask)
+ else:
+ tweaked_curve = p.second.get()
+ JpmcdsContingentLegPV(&legs.first,
+ base_date,
+ value_date,
+ step_in_date,
+ yc,
+ tweaked_curve,
+ recovery_rate,
+ &cl_pv)
+ JpmcdsFeeLegPV(&legs.second,
+ base_date,
+ step_in_date,
+ value_date,
+ yc,
+ tweaked_curve,
+ True,
+ &fl_pv)
+ r += weights[i] * (cl_pv - fl_pv * fixed_rate)
+ i += 1
+ return r