Skip to content

Commit b692c75

Browse files
committed
Work on improving encapsulation of DiscountCurves
1 parent 3be11f2 commit b692c75

38 files changed

+669
-585
lines changed

financepy/__init__.template

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
if 1==1:
1+
use_banner = true
2+
3+
if use_banner:
24
cr = "\n"
35

46
s = "####################################################################" + cr

financepy/market/curves/discount_curve.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ class DiscountCurve:
3333
def __init__(
3434
self,
3535
value_dt: Date,
36-
df_dates: list,
37-
df_values: np.ndarray,
36+
df_dates: list = None,
37+
df_values: np.ndarray = None,
3838
interp_type: InterpTypes = InterpTypes.FLAT_FWD_RATES,
3939
):
4040
"""Create the discount curve from a vector of times and discount
@@ -46,11 +46,11 @@ def __init__(
4646
check_argument_types(self.__init__, locals())
4747

4848
# Validate curve
49-
if len(df_dates) < 1:
50-
raise FinError("Times has zero length")
49+
if df_dates is None:
50+
df_dates = [value_dt]
5151

52-
if len(df_dates) != len(df_values):
53-
raise FinError("Times and Values are not the same")
52+
if df_values is None:
53+
df_values = [1.0]
5454

5555
self._times = [0.0]
5656
self._dfs = [1.0]
@@ -85,6 +85,18 @@ def __init__(
8585
self._interpolator = Interpolator(self._interp_type)
8686
self._interpolator.fit(self._times, self._dfs)
8787

88+
###############################################################################
89+
90+
@property
91+
def times(self) -> np.ndarray:
92+
"""Return the internal array of times (in years) from the anchor date."""
93+
return self._times.copy() # return a copy to prevent external modification
94+
95+
@property
96+
def dfs(self) -> np.ndarray:
97+
"""Return the internal array of discount factors corresponding to times."""
98+
return self._dfs.copy() # return a copy to prevent external modification
99+
88100
###########################################################################
89101

90102
def _zero_to_df(

financepy/market/curves/discount_curve_flat.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class DiscountCurveFlat(DiscountCurve):
2626
"""A very simple discount curve based on a single zero rate with its
2727
own specified compounding method. Hence, the curve is assumed to be flat.
2828
It is used for quick and dirty analysis and when limited information is
29-
available. It inherits several methods from FinDiscountCurve."""
29+
available. It inherits several methods from DiscountCurve."""
3030

3131
###############################################################################
3232

@@ -44,7 +44,7 @@ def __init__(
4444
As the curve is flat, no interpolation scheme is required.
4545
"""
4646

47-
# super().__init__()
47+
super().__init__(value_dt)
4848

4949
check_argument_types(self.__init__, locals())
5050

@@ -56,25 +56,24 @@ def __init__(
5656
# This is used by some inherited functions, so we choose the simplest
5757
self._interp_type = InterpTypes.FLAT_FWD_RATES
5858

59-
# Need to set up a grid of times and discount factors
59+
# Need to set up a 3M grid of times and discount factors
60+
# Those beyond 10 years are extrapolated
6061
years = np.linspace(0.0, 10.0, 41)
6162
dts = self.value_dt.add_years(years)
6263

63-
# Set up a grid of times and discount factors for functions
64-
self._dfs = self.df(dts)
64+
# Set up a grid of dc adjusted times and discount factors for functions
6565
self._times = times_from_dates(dts, self.value_dt, dc_type)
66+
self._dfs = self.df(dts)
6667

6768
###############################################################################
6869

69-
def bump(self, bump_size: float):
70-
"""Create a new FinDiscountCurveFlat object with the entire curve
71-
bumped up by the bumpsize. All other parameters are preserved."""
70+
def times(self) -> np.ndarray:
71+
"""Return the cached grid of times."""
72+
return self._times
7273

73-
rate_bumped = self.flat_rate + bump_size
74-
disc_curve = DiscountCurveFlat(
75-
self.value_dt, rate_bumped, freq_type=self.freq_type, dc_type=self.dc_type
76-
)
77-
return disc_curve
74+
def dfs(self) -> np.ndarray:
75+
"""Return the cached grid of discount factors."""
76+
return self._dfs
7877

7978
###############################################################################
8079

@@ -99,6 +98,18 @@ def df(self, dts: Union[Date, list]):
9998

10099
###############################################################################
101100

101+
def bump(self, bump_size: float):
102+
"""Create a new FinDiscountCurveFlat object with the entire curve
103+
bumped up by the bumpsize. All other parameters are preserved."""
104+
105+
rate_bumped = self.flat_rate + bump_size
106+
disc_curve = DiscountCurveFlat(
107+
self.value_dt, rate_bumped, freq_type=self.freq_type, dc_type=self.dc_type
108+
)
109+
return disc_curve
110+
111+
###############################################################################
112+
102113
def __repr__(self):
103114
s = label_to_string("OBJECT TYPE", type(self).__name__)
104115
s += label_to_string("VALUE DATE", (self.value_dt))

financepy/market/curves/discount_curve_ns.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class DiscountCurveNS(DiscountCurve):
2525
The internal rate is a continuously compounded rate but you can calculate
2626
alternative frequencies by providing a corresponding compounding frequency.
2727
A day count convention is needed to ensure that dates are converted to the
28-
correct time in years. The class inherits methods from FinDiscountCurve."""
28+
correct time in years. The class inherits methods from DiscountCurve."""
2929

3030
def __init__(
3131
self,
@@ -64,7 +64,7 @@ def zero_rate(
6464
dc_type: DayCountTypes = DayCountTypes.ACT_360,
6565
):
6666
"""Calculation of zero rates with specified frequency according to
67-
NS parametrisation. This method overrides that in FinDiscountCurve.
67+
NS parametrisation. This method overrides that in DiscountCurve.
6868
The parametrisation is not strictly in terms of continuously compounded
6969
zero rates, this function allows other compounding and day counts.
7070
This function returns a single or vector of zero rates given a vector

financepy/market/curves/discount_curve_nss.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class DiscountCurveNSS(DiscountCurve):
2525
zero rate curve. The zero rate is assumed to be continuously compounded.
2626
This can be changed when calling for zero rates. A day count convention is
2727
needed to ensure that dates are converted to the correct time in years. The
28-
class inherits methods from FinDiscountCurve."""
28+
class inherits methods from DiscountCurve."""
2929

3030
def __init__(
3131
self,
@@ -71,7 +71,7 @@ def zero_rate(
7171
dc_type: DayCountTypes = DayCountTypes.ACT_360,
7272
):
7373
"""Calculation of zero rates with specified frequency according to
74-
NSS parametrisation. This method overrides that in FinDiscountCurve.
74+
NSS parametrisation. This method overrides that in DiscountCurve.
7575
The NSS parametrisation is no strictly terms of continuously compounded
7676
zero rates, this function allows other compounding and day counts.
7777
This function returns a single or vector of zero rates given a vector

financepy/market/curves/discount_curve_poly.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class DiscountCurvePoly(DiscountCurve):
2525
polynomial. The zero rate is assumed to be continuously compounded but
2626
this can be amended by providing a frequency when extracting zero rates.
2727
We also need to specify a Day count convention for time calculations.
28-
The class inherits all of the methods from FinDiscountCurve."""
28+
The class inherits all of the methods from DiscountCurve."""
2929

3030
def __init__(
3131
self,
@@ -55,7 +55,7 @@ def zero_rate(
5555
dc_type: DayCountTypes = DayCountTypes.ACT_360,
5656
):
5757
"""Calculation of zero rates with specified frequency according to
58-
polynomial parametrisation. This method overrides FinDiscountCurve.
58+
polynomial parametrisation. This method overrides DiscountCurve.
5959
The parametrisation is not strictly in terms of continuously compounded
6060
zero rates, this function allows other compounding and day counts.
6161
This function returns a single or vector of zero rates given a vector

financepy/market/curves/discount_curve_pwf.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
class DiscountCurvePWF(DiscountCurve):
2525
"""Curve is made up of a series of zero rates sections with each having
2626
a piecewise flat zero rate. The default compounding assumption is
27-
continuous. The class inherits methods from FinDiscountCurve."""
27+
continuous. The class inherits methods from DiscountCurve."""
2828

2929
def __init__(
3030
self,
@@ -54,9 +54,9 @@ def __init__(
5454

5555
dc_times = times_from_dates(zero_dts, self.value_dt, self.dc_type)
5656

57-
self.times = np.array(dc_times)
57+
self._times = np.array(dc_times)
5858

59-
if test_monotonicity(self.times) is False:
59+
if test_monotonicity(self._times) is False:
6060
raise FinError("Times are not sorted in increasing order")
6161

6262
###########################################################################
@@ -78,9 +78,9 @@ def _zero_rate(self, times: Union[float, np.ndarray, list]):
7878
l_index = 0
7979
found = 0
8080

81-
num_times = len(self.times)
81+
num_times = len(self._times)
8282
for i in range(1, num_times):
83-
if self.times[i] > t:
83+
if self._times[i] > t:
8484
l_index = i - 1
8585
found = 1
8686
break

financepy/market/curves/discount_curve_pwl.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class DiscountCurvePWL(DiscountCurve):
2424
"""Curve is made up of a series of sections assumed to each have a
2525
piece-wise linear zero rate. The zero rate has a specified frequency
2626
which defaults to continuous. This curve inherits all of the extra methods
27-
from FinDiscountCurve."""
27+
from DiscountCurve."""
2828

2929
def __init__(
3030
self,
@@ -53,7 +53,7 @@ def __init__(
5353

5454
dc_times = times_from_dates(zero_dts, self.value_dt, self.dc_type)
5555

56-
self.times = np.array(dc_times)
56+
self._times = np.array(dc_times)
5757

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

financepy/market/curves/discount_curve_zeros.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class DiscountCurveZeros(DiscountCurve):
3030
compute the year fraction correctly and for this we require a day count
3131
convention. Finally, we need to interpolate the zero rate for the times
3232
between the zero rates given and for this we must specify an interpolation
33-
convention. The class inherits methods from FinDiscountCurve."""
33+
convention. The class inherits methods from DiscountCurve."""
3434

3535
###############################################################################
3636

@@ -101,7 +101,7 @@ def __init__(
101101
# t = times[i]
102102
# discount_factors[i] = discount_factors[i] * np.exp(-bump_size*t)
103103

104-
# disc_curve = FinDiscountCurve(self.value_dt, times,
104+
# disc_curve = DiscountCurve(self.value_dt, times,
105105
# discount_factors,
106106
# self._interp_type)
107107

financepy/products/bonds/bond_yield_curve.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class BondYieldCurve:
3030
"""Class to do fitting of the yield curve and to enable interpolation of
3131
yields. Because yields assume a flat term structure for each bond, this
3232
class does not allow discounting to be done and so does not inherit from
33-
FinDiscountCurve. It should only be used for visualisation and simple
33+
DiscountCurve. It should only be used for visualisation and simple
3434
interpolation but not for full term-structure-consistent pricing."""
3535

3636
def __init__(

0 commit comments

Comments
 (0)