Source code for yieldcurves.compounding

# -*- coding: utf-8 -*-

# yieldcurves
# -----------
# A Python library for financial yield curves.
#
# Author:   sonntagsgesicht
# Version:  0.2.6.1, copyright Monday, 14 October 2024
# Website:  https://github.com/sonntagsgesicht/yieldcurves
# License:  Apache License 2.0 (see LICENSE file)


from math import exp, log, pow
from .tools import vectorize


[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def simple_compounding(rate_value, maturity_value): r"""simple compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $\frac{1}{1+r\cdot \tau}$ """ return 1.0 / (1.0 + rate_value * float(maturity_value))
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def simple_rate(df, period_fraction): r"""interest rate from simple compounded dicount factor :param df: discount factor $df$ :param period_fraction: interest rate period $\tau$ :return: $\frac{1}{df-1}\cdot \frac{1}{\tau}$ """ return (1.0 / df - 1.0) / float(period_fraction)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def continuous_compounding(rate_value, maturity_value): r"""continuous compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $\exp(-r\cdot \tau)$ """ return exp(-1.0 * rate_value * float(maturity_value))
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def continuous_rate(df, period_fraction): r"""interest rate from continuous compounded dicount factor :param df: discount factor $df$ :param period_fraction: interest rate period $\tau$ :return: $-\log(df)\cdot \frac{1}{\tau}$ """ if not df: pass return -log(df) / float(period_fraction)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def periodic_compounding(rate_value, maturity_value, frequency): r"""periodically compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :param frequency: number of interest rate periods $m$ :return: $(1+\frac{r}{m})^{-\tau\cdot m}$ """ if frequency is None: return continuous_compounding(rate_value, maturity_value) if frequency == 0: return simple_compounding(rate_value, maturity_value) ex = -frequency * float(maturity_value) return pow(1.0 + float(rate_value) / frequency, ex)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def periodic_rate(df, period_fraction, frequency): r"""interest rate from continuous compounded discount factor :param df: discount factor $df$ :param period_fraction: interest rate period $\tau$ :param frequency: number of interest rate periods $m$ :return: $(df^{-\frac{1}{\tau\cdot m}}-1) \cdot m$ """ period_fraction = float(period_fraction) return (pow(df, -1.0 / (period_fraction * frequency)) - 1.0) * frequency
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def annually_compounding(rate_value, maturity_value): r"""annually compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $(1+r)^{-\tau}$ """ return periodic_compounding(rate_value, maturity_value, 1)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def semi_compounding(rate_value, maturity_value): r"""semi compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $(1+\frac{r}{2})^{-\tau\cdot 2}$ """ return periodic_compounding(rate_value, maturity_value, 2)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def quarterly_compounding(rate_value, maturity_value): r"""quarterly compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $(1+\frac{r}{4})^{-\tau\cdot 4}$ """ return periodic_compounding(rate_value, maturity_value, 4)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def monthly_compounding(rate_value, maturity_value): r"""monthly compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $(1+\frac{r}{12})^{-\tau\cdot 12}$ """ return periodic_compounding(rate_value, maturity_value, 12)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def daily_compounding(rate_value, maturity_value): r"""daily compounded discount factor :param rate_value: interest rate $r$ :param maturity_value: loan maturity $\tau$ :return: $(1+\frac{r}{365})^{-\tau\cdot 365}$ """ return periodic_compounding(rate_value, maturity_value, 365)
[docs] @vectorize(['rate_value', 'maturity_value'], zipped=True) def compounding_factor(rate_value, maturity_value, frequency=None): r"""compounded discount factor :param rate_value: interest rate $r$ per year :param maturity_value: maturity $\tau$ in years :param frequency: number of interest rate periods per year as in |periodic_compounding()| if **frequency** is **None** |continuous_compounding()| is used and if **period_value** is **0** |simple_compounding()| is used. :return: """ if frequency is None or frequency < 0: return continuous_compounding(rate_value, maturity_value) if frequency == 0: return simple_compounding(rate_value, maturity_value) return periodic_compounding(rate_value, maturity_value, frequency)
[docs] @vectorize(['df', 'period_fraction'], zipped=True) def compounding_rate(df, period_fraction, frequency): r"""interest rate from compounded discount factor :param df: discount factor $df$ :param period_fraction: interest rate period $\tau$ in years :param frequency: number of interest rate periods $m$ per year as in |periodic_rate()| if **frequency** is **None** |continuous_rate()| is used and if **frequency** is **0** |simple_rate()| is used. """ if frequency is None or frequency < 0: return continuous_rate(df, period_fraction) if frequency == 0: return simple_rate(df, period_fraction) return periodic_rate(df, period_fraction, frequency)
def _validate_compounding_pair(rate, factor): r, f = rate, factor for t in (0.00002737850787, 0.25, 0.5, .9, 1., 2., 5., 10.): for i in (0.0, 0.001, 0.001, 0.01, 0.1, 1): if not i == r(f(i, t), t) or \ not f(r(f(i, t)), t) == f(i, t): raise TypeError("compounding must be tuple" " of inverse functions.") # todo: check exp(-t*r) <= f(r, t) <= 1/(1+r*t)