Skip to content

Commit

Permalink
Fixed bug in df_t
Browse files Browse the repository at this point in the history
  • Loading branch information
domokane committed Oct 7, 2024
1 parent b349979 commit b97468b
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 32 deletions.
2 changes: 1 addition & 1 deletion financepy/market/curves/composite_discount_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, child_curves: List[DiscountCurve]):

###############################################################################

def _df(self, t: Union[float, np.ndarray]):
def df_t(self, t: Union[float, np.ndarray]):
"""
Return discount factors given a single or vector of dates.
ParentRate = Sum of children rates => Parent DF = product of children dfs
Expand Down
76 changes: 45 additions & 31 deletions financepy/market/curves/discount_curve_pwf_onf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@


class DiscountCurvePWFONF(DiscountCurve):
""" Curve with piece-wise flat instantaneous (ON) fwd rates. Curve is made up of a series of sections with each having
"""Curve with piece-wise flat instantaneous (ON) fwd rates. Curve is made up of a series of sections with each having
a flat instantaneous forward rate. The default compounding assumption is
continuous. The class inherits methods from DiscountCurve. """

def __init__(self,
value_dt: Date,
knot_dates: list,
onfwd_rates: Union[list, np.ndarray]):
"""
continuous. The class inherits methods from DiscountCurve."""

def __init__(
self,
value_dt: Date,
knot_dates: list,
onfwd_rates: Union[list, np.ndarray],
):
"""
Creates a discount curve using a vector of times and ON fwd rates
The fwd rate is right-continuous i.e. a given value in the input is applied to the left of that date until the previous date exclusive
The last fwd rate is extrapolated into the future
Expand All @@ -52,25 +54,37 @@ def __init__(self,
self._freq_type = FrequencyTypes.CONTINUOUS
self._day_count_type = DayCountTypes.SIMPLE

dc_times = times_from_dates(self._knot_dates,
self.value_dt,
self._day_count_type)
dc_times = times_from_dates(
self._knot_dates, self.value_dt, self._day_count_type
)

self._times = np.atleast_1d(dc_times)

# it is easier to deal in log(dfs), log(df[Ti]) = -\int_0^T_i f(u) du
self._logdfs = - \
np.cumsum(np.diff(self._times, prepend=0.0) * self._onfwd_rates)
self._logdfs = -np.cumsum(
np.diff(self._times, prepend=0.0) * self._onfwd_rates
)
self._logdfs_interp = interpolate.interp1d(
np.concatenate(([0.0], self._times)), np.concatenate(([0.0], self._logdfs)), kind='linear', bounds_error=False, fill_value='extrapolate')
np.concatenate(([0.0], self._times)),
np.concatenate(([0.0], self._logdfs)),
kind="linear",
bounds_error=False,
fill_value="extrapolate",
)

if test_monotonicity(self._times) is False:
raise FinError("Times are not sorted in increasing order")

###############################################################################

@classmethod
def brick_wall_curve(cls, valuation_date: Date, start_date: Date, end_date: Date, level: float = 1.0*g_basis_point):
def brick_wall_curve(
cls,
valuation_date: Date,
start_date: Date,
end_date: Date,
level: float = 1.0 * g_basis_point,
):
"""Generate a discount curve of the shape f(t) = level*1_{startdate < t <= enddate} where f(.) is the instantaneous forward rate
Mostly useful for applying bumps to other discount_curve's, see composite_discount_curve.py
Args:
Expand All @@ -82,23 +96,24 @@ def brick_wall_curve(cls, valuation_date: Date, start_date: Date, end_date: Date
Returns:
DiscountCurve: discount curve of the required shape
"""
knot_dates = [start_date, end_date, end_date.add_tenor('1D')]
knot_dates = [start_date, end_date, end_date.add_tenor("1D")]
onfwd_rates = [0.0, level, 0.0]
return cls(valuation_date, knot_dates, onfwd_rates)

###############################################################################

@classmethod
def flat_curve(cls, valuation_date: Date, level: float = 1.0*g_basis_point):
knot_dates = [valuation_date.add_tenor('1Y')]
def flat_curve(
cls, valuation_date: Date, level: float = 1.0 * g_basis_point
):
knot_dates = [valuation_date.add_tenor("1Y")]
onfwd_rates = [level]
return cls(valuation_date, knot_dates, onfwd_rates)

###############################################################################

def _zero_rate(self,
times: Union[float, np.ndarray, list]):
"""
def _zero_rate(self, times: Union[float, np.ndarray, list]):
"""
Piecewise flat instantaneous (ON) fwd rate is the same as linear logDfs
"""

Expand All @@ -109,25 +124,23 @@ def _zero_rate(self,

times = np.maximum(times, g_small)
ldfs = self._logdfs_interp(times)
zero_rates = -ldfs/times
zero_rates = -ldfs / times
return zero_rates

###############################################################################

def _df(self, t: Union[float, np.ndarray]):
""" Return discount factors given a single or vector of times in years. The
def df_t(self, t: Union[float, np.ndarray]):
"""Return discount factors given a single or vector of times in years. The
discount factor depends on the rate and this in turn depends on its
compounding frequency and it defaults to continuous compounding. It
also depends on the day count convention. This was set in the
construction of the curve to be ACT_ACT_ISDA. """
construction of the curve to be ACT_ACT_ISDA."""

zero_rates = self._zero_rate(t)

df = self._zero_to_df(self.value_dt,
zero_rates,
t,
self._freq_type,
self._day_count_type)
df = self._zero_to_df(
self.value_dt, zero_rates, t, self._freq_type, self._day_count_type
)

return df

Expand All @@ -145,7 +158,8 @@ def __repr__(self):
###############################################################################

def _print(self):
""" Simple print function for backward compatibility. """
"""Simple print function for backward compatibility."""
print(self)


###############################################################################

0 comments on commit b97468b

Please sign in to comment.