Tutorial¶
To start with import the package.
>>> from dcf import Curve, DateCurve, RateCurve
Interest Rate Curve Objects¶
Curves Types¶
Interest rate curves can be expressed in various ways. Each for different type of storing rate information and purpose.
There are four different types of interest rate curves:
They meet all the same interface, i.e. have the same properties and methods. They differ only in data which can be given for constructing the curves. This sets how rates are stored and interpolated. Moreover an large list of interpolation methods are provided.
As the names indicate, these curves take either
Getting Curve Values¶
From each class offers teh same methods to calculate each of those four types of rate by
Casting Curves¶
Even casting one type to another is as easy as
>>> from businessdate import BusinessDate
>>> from dcf import ZeroRateCurve, DiscountFactorCurve
>>> today = BusinessDate(20201031)
>>> date = today + '1m'
>>> zr_curve = ZeroRateCurve([today, today + '2y'], [-.005, .01])
>>> df_curve = DiscountFactorCurve(zr_curve)
>>> re_curve = ZeroRateCurve(df_curve)
>>> zr_curve(date), df_curve(date), re_curve(date)
(-0.004383561643835616, 1.0003601109552978, -0.004383561643827753)
Credit Curve Objects¶
Similar to dcf.curves.interestratecurve.InterestRateCurve
dcf.curves.creditcurve.CreditCurve
come in different (storage) types.
Curves Types¶
These are
Getting Curve Values¶
From each class offers teh same methods to calculate each of those four types of rate by
Casting Curves¶
Even casting works the same way it does for interest rate curves.
Basic Curve Objects and Attributes¶
All of the mentioned curve classes inherit from these base classes.
Curve¶
Most fundamental is the dcf.curves.curve.Curve
which sets the interpolation method.
But note, even domain data (x-values),
accessed by dcf.curves.curve.Curve.domain
, are assume to be float.
The x-values can be shifted left or right
by add in a negative or positive float via dcf.curves.curve.Curve.shifted()
.
Operations¶
DateCurve¶
Different is dcf.curves.curve.DateCurve
. Here are x-values given by date.
But also easily casted
>>> from businessdate import BusinessDate
>>> from dcf import Curve, DateCurve
>>> today = BusinessDate(20200915)
>>> date_curve = DateCurve([today, today + '4y'], [0.1, 0.3])
>>> curve = Curve(date_curve)
>>> x = date_curve.day_count(date_curve.origin, today + '2y')
>>> curve(x), date_curve(today + '2y')
(0.19993155373032168, 0.19993155373032168)
Already use was the domain property dcf.curves.curve.Curve.domain
or dcf.curves.curve.DateCurve.domain
which reveals the x-values of the curve.
As we have to measure distances by a day counting method (aka. year fraction) dcf.curves.curve.DateCurve.day_count()
,
which is mainly turning days into float
.
See wikipedia for details and also businessdate for an implementation.
Moreover a date dcf.curves.curve.DateCurve.origin
is marking the origin of the x-axis
Finally, many curves can be integrated as well as the derivative can be derived.
Same works for dcf.curves.curve.DateCurve
:
Cashflow Objects and Valuation¶
Payment Plans¶
>>> from businessdate import BusinessDate, BusinessSchedule
>>> today = BusinessDate(20201031)
>>> schedule = BusinessSchedule(today, today + "8q", step="1q")
>>> schedule
[BusinessDate(20201031), BusinessDate(20210131), BusinessDate(20210430), BusinessDate(20210731), BusinessDate(20211031), BusinessDate(20220131), BusinessDate(20220430), BusinessDate(20220731), BusinessDate(20221031)]
To build payment plans for, e.g. annuity loans, pick a plan function and generate an redemption amount list for paying back the loan notional amount.
>>> from dcf.plans import annuity, outstanding
>>> number_of_payments = 8
>>> interest_rate = 0.02
>>> notional = 1000.
>>> plan = annuity(number_of_payments, amount=notional, fixed_rate=interest_rate)
>>> plan
[116.50979913376267, 118.83999511643792, 121.21679501876667, 123.64113091914203, 126.11395353752485, 128.63623260827535, 131.20895726044085, 133.83313640564967]
>>> sum(plan)
1000.0
>>> out = outstanding(plan, amount=notional)
>>> out
[1000.0, 883.4902008662373, 764.6502057497994, 643.4334107310327, 519.7922798118907, 393.6783262743659, 265.0420936660905, 133.83313640564967]
>>> compound = [o * interest_rate + p for o, p in zip(out, plan)]
>>> compound
[136.50979913376267, 136.50979913376267, 136.50979913376267, 136.50979913376267, 136.50979913376267, 136.50979913376267, 136.50979913376267, 136.50979913376267]
CashFlowList Objects¶
Putting all together and feeding the plan into a FixedCashFlowList and the list of outstanding into a `RateCashflowList gives the legs of a loan.
>>> from businessdate import BusinessDate, BusinessSchedule
>>> from dcf.plans import amortize, outstanding
>>> from dcf import FixedCashFlowList, RateCashFlowList
Again, build a date schedule.
>>> today = BusinessDate(20201031)
>>> schedule = BusinessSchedule(today, today + "8q", step="1q")
>>> start_date, payment_dates = schedule[0], schedule[1:]
Fixing the properties of the product and rolling out the payment plan and list of notional outstanding.
>>> number_of_payments = 8
>>> interest_rate = 0.01
>>> notional = 1000.
>>> plan = amortize(number_of_payments, amount=notional)
>>> out = outstanding(plan, amount=notional)
Finally, create for each leg a dcf.cashflows.cashflow.CashFlowList
.
>>> principal = FixedCashFlowList([start_date], [-notional], origin=start_date)
>>> print(principal)
FixedCashFlowList([BusinessDate(20201031) ... BusinessDate(20201031)], [-1000.0 ... -1000.0], origin=BusinessDate(20201031))
>>> redemption = FixedCashFlowList(payment_dates, plan, origin=start_date)
>>> print(redemption)
FixedCashFlowList([BusinessDate(20210131) ... BusinessDate(20221031)], [125.0 ... 125.0], origin=BusinessDate(20201031))
>>> interest = RateCashFlowList(payment_dates, out, origin=start_date, fixed_rate=interest_rate)
>>> print(interest)
RateCashFlowList([BusinessDate(20210131) ... BusinessDate(20221031)], [1000.0 ... 125.0], origin=BusinessDate(20201031))
Valuation¶
Add those legs to dcf.cashflows.cashflow.CashFlowLegList
provides a smart container for valuation (dcf.pricer.get_present_value()
).
>>> from dcf import CashFlowLegList, ZeroRateCurve, get_present_value
>>> loan = CashFlowLegList([principal, redemption, interest])
>>> curve = ZeroRateCurve([today, today + '2y'], [-.005, .01])
>>> pv = get_present_value(cashflow_list=loan, discount_curve=curve, valuation_date=today)
>>> pv
4.935421637918839