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