financialkit.time_value#
Compounding at any frequency and equivalent rates; the rule of 72 and
compound-interest tables; present value, net present value and Fisher’s
real rate; annuities, perpetuities, life annuities and sinking funds; the
internal rate of return (scipy.optimize.brentq), every root of the
NPV polynomial (numpy.roots) and the modified IRR; amortization
schedules and the Truth-in-Lending APR; day counts, year fractions and
accrued interest for every DayCount convention.
financialkit.time_value: the time value of money.
Compounding at any frequency and the equivalence of rates (continuous by
default); Pacioli’s rule of 72 and Witt’s compound-interest tables;
present value, Fisher’s net present value and real rate of interest;
annuities, perpetuities, De Witt’s life annuities and Price’s sinking
fund; the internal rate of return (scipy.optimize.brentq()), every
root of the NPV polynomial (numpy.roots()) with a warning when
there are several, and Baldwin’s modified IRR; level-payment
amortization schedules and the Truth-in-Lending APR; day counts, year
fractions and accrued interest for every
DayCount convention.
The year-fraction functions here are the package’s single implementation; later domains import them rather than redefining them.
- class financialkit.time_value.AmortizationSchedule(periods, payment, interest, principal, balance, periods_per_year=12)[source]#
Bases:
objectA level-payment loan schedule, one row per payment.
- Parameters:
- class financialkit.time_value.CompoundingTable(rate, periods, amount, discount, annuity_present, annuity_future)[source]#
Bases:
objectA compound-interest table for one rate, in the layout of Witt (1613).
- Parameters:
- annuity_future: ndarray#
Accumulated value of 1 per period, \(s_{\overline{k}|}\).
- Type:
ndarray, shape (n,)
- exception financialkit.time_value.MultipleIRRWarning[source]#
Bases:
UserWarningRaised when a cash-flow stream has more than one internal rate of return.
By Descartes’ rule of signs a stream with more than one sign change can have several IRRs (Lorie and Savage, 1955), and then no single one of them is a meaningful rate of return.
- class financialkit.time_value.NPVProfile(rates, npv, irrs)[source]#
Bases:
objectNet present value as a function of the discount rate.
- class financialkit.time_value.SinkingFundSchedule(periods, deposit, interest, balance)[source]#
Bases:
objectLevel deposits accumulating at interest to repay a debt at maturity.
- financialkit.time_value.accrued_interest(face, coupon_rate, last_coupon, settlement, convention=DayCount.THIRTY_360_US)[source]#
Coupon interest accrued from the last coupon date to settlement.
- Parameters:
- Returns:
float or ndarray
Examples
Hull (10th ed.), Sec. 6.1: a 10% corporate bond, coupons on March 1 and September 1, settling July 3, 2018 (30/360).
>>> round(accrued_interest(100.0, 0.10, "2018-03-01", "2018-07-03"), 4) 3.3889
- financialkit.time_value.amortization_schedule(principal, annual_rate, n_payments, periods_per_year=12)[source]#
Split each level payment into interest and principal.
- Parameters:
- Return type:
- Returns:
AmortizationSchedule
Examples
>>> s = amortization_schedule(1000.0, 0.12, 12) >>> round(s.payment, 2), float(s.interest[0]), abs(float(s.balance[-1])) < 1e-9 (88.85, 10.0, True)
- financialkit.time_value.annual_percentage_rate(amount_financed, payment, n_payments, periods_per_year=12)[source]#
Truth-in-Lending APR of a level-payment loan.
- Parameters:
- Return type:
- Returns:
float – Nominal annual rate
periods_per_year * i, whereisolvespayment * a_n(i) == amount_financed.
Examples
A 1,000 loan at 12% with a 20 fee deducted up front:
>>> payment = loan_payment(1000.0, 0.12, 12) >>> round(annual_percentage_rate(1000.0, payment, 12), 6) 0.12 >>> round(annual_percentage_rate(980.0, payment, 12), 4) 0.1585
- financialkit.time_value.annuity_factor(rate, n, due=False)[source]#
Present value of 1 per period for n periods, \(a_{\overline{n}|}\).
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(annuity_factor(0.05, 10), 6) 7.721735
- financialkit.time_value.annuity_future_value(payment, rate, n, due=False)[source]#
Accumulated value after n level payments, \(P s_{\overline{n}|}\).
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(annuity_future_value(100.0, 0.05, 10), 2) 1257.79
- financialkit.time_value.annuity_payment(present_value, rate, n, due=False)[source]#
Level payment whose n-period annuity is worth present_value.
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(annuity_payment(10_000.0, 0.01, 12), 2) 888.49
- financialkit.time_value.annuity_present_value(payment, rate, n, due=False)[source]#
Present value of n level payments.
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(annuity_present_value(1000.0, 0.06, 5), 2) 4212.36
- financialkit.time_value.compound_interest_table(rate, n_periods)[source]#
Build a compound-interest table for periods
1, ..., n_periods.Witt (1613) printed, for each rate, the amount of 1, the present value of 1 and the values of an annuity of 1 per period; with them a clerk could price a loan, a lease or an annuity by look-up and multiplication.
- Parameters:
- Return type:
- Returns:
CompoundingTable
Examples
>>> table = compound_interest_table(0.10, 3) >>> table.amount.round(3).tolist(), table.annuity_present.round(4).tolist() ([1.1, 1.21, 1.331], [0.9091, 1.7355, 2.4869])
- financialkit.time_value.continuous_rate(rate, compounding=None)[source]#
Restate a rate as its continuously compounded equivalent, \(m \ln(1 + r/m)\).
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(continuous_rate(0.10, 1), 6) 0.09531
- financialkit.time_value.day_count(start, end, convention=DayCount.ACT_365F)[source]#
Days between two dates under a day-count convention.
- Parameters:
start (date-like or array-like of date-likes)
end (date-like or array-like of date-likes)
convention (DayCount or str) – One of
DayCount; theACTconventions count actual days.
- Returns:
int or ndarray of int
Examples
Hull (10th ed.), Sec. 6.1: March 1 to July 3, 2018.
>>> day_count("2018-03-01", "2018-07-03", "30/360 US"), day_count("2018-03-01", "2018-07-03", "ACT/360") (122, 124)
- financialkit.time_value.de_witt_survival(age, times, base_hazard=0.01)[source]#
Survival probabilities under De Witt’s (1671) mortality hypothesis.
De Witt assumed that between ages 3 and 53 the chance of dying is the same in every half-year, and that it is 1.5, 2 and 3 times as large in the bands 53-63, 63-73 and 73-80, with no one living beyond 80. Here this is a piecewise-constant force of mortality
base_hazard * w.- Parameters:
- Return type:
- Returns:
ndarray – Probability of being alive at each time.
Examples
>>> de_witt_survival(70.0, [0.0, 5.0, 9.0, 10.0]).round(4).tolist() [1.0, 0.8869, 0.7866, 0.0]
- financialkit.time_value.discount_factor(rate, t, compounding=None)[source]#
Value today of 1 paid at time
t.- Parameters:
- Returns:
float or ndarray
Examples
>>> round(discount_factor(0.05, 2.0), 6) 0.904837 >>> round(discount_factor(0.05, 2.0, compounding=1), 6) 0.907029
- financialkit.time_value.doubling_time(rate, compounding=None)[source]#
Exact time, in years, for money to double at rate.
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(doubling_time(0.06, compounding=1), 4) 11.8957
- financialkit.time_value.effective_annual_rate(rate, compounding=None)[source]#
Annual effective rate, \((1 + r/m)^m - 1\), equivalent to rate.
Examples
>>> round(effective_annual_rate(0.12, 12), 6) 0.126825
- financialkit.time_value.equivalent_rate(rate, from_compounding, to_compounding)[source]#
Convert a rate between compounding frequencies at equal growth.
- Parameters:
- Returns:
float or ndarray
Examples
Hull (10th ed.), Example 4.1: 10% compounded semiannually is 9.758% continuously compounded.
>>> round(equivalent_rate(0.10, 2, None), 5) 0.09758
- financialkit.time_value.fisher_nominal_rate(real, inflation)[source]#
Nominal rate implied by a real rate and inflation, \((1 + r)(1 + \pi) - 1\).
Examples
>>> round(fisher_nominal_rate(0.02, 0.03), 4) 0.0506
- financialkit.time_value.fisher_real_rate(nominal, inflation, exact=True)[source]#
Real interest rate from a nominal rate and inflation (Fisher, 1896).
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(fisher_real_rate(0.10, 0.06), 6), round(fisher_real_rate(0.10, 0.06, exact=False), 6) (0.037736, 0.04)
- financialkit.time_value.future_value(present_value, rate, t, compounding=None)[source]#
Accumulated value at time
tof present_value invested today.- Parameters:
- Returns:
float or ndarray
Examples
Bernoulli’s question: 1 at 100% a year, compounded ever more often.
>>> [round(future_value(1.0, 1.0, 1.0, m), 6) for m in (1, 12, 365)] [2.0, 2.613035, 2.714567] >>> round(future_value(1.0, 1.0, 1.0), 6) 2.718282
- financialkit.time_value.irr(cash_flows, times=None, compounding=1, bracket=(-0.99, 10.0), n_grid=2001)[source]#
Internal rate of return: the rate at which
npv()is zero.- Parameters:
cash_flows (array-like, shape (n,))
times (array-like, shape (n,), optional) – Payment times; defaults to
0, 1, ..., n - 1.compounding (
int|None) – Compounding of the returned rate; default annual.bracket (
tuple[float,float]) – Search interval for the rate.n_grid (
int) – Grid points used to bracket sign changes before root polishing.
- Return type:
- Returns:
float – The lowest IRR in bracket.
- Raises:
ValueError – If the NPV does not change sign in bracket.
- Warns:
MultipleIRRWarning – If the NPV has more than one root in bracket.
Examples
>>> round(irr([-100.0, 60.0, 60.0]), 6) 0.130662
- financialkit.time_value.irr_all(cash_flows)[source]#
Every real IRR above -100% of cash flows at periods
0, 1, ..., n.With \(x = 1/(1 + r)\) the NPV is the polynomial \(\sum_k c_k x^k\); its positive real roots give the IRRs.
- Parameters:
cash_flows (array-like, shape (n + 1,))
- Return type:
- Returns:
ndarray – IRRs per period, ascending (empty if there is none).
Examples
Lorie and Savage’s oil pump (1955): 25% and 400%.
>>> irr_all([-1600, 10000, -10000]).round(6).tolist() [0.25, 4.0]
- financialkit.time_value.life_annuity_value(payment, rate, survival, due=False)[source]#
Expected present value of a life annuity, \(P \sum_k {}_k p_x v^k\).
- Parameters:
payment (float) – Payment per period while the annuitant lives.
rate (float or array-like) – Effective rate per period.
survival (array-like, shape (n,)) –
survival[k - 1]is the probability of being alive at periodk(or atk - 1if due), e.g. fromde_witt_survival().due (
bool)
- Returns:
float or ndarray
Examples
With certain survival the life annuity is an annuity-certain:
>>> round(life_annuity_value(1.0, 0.04, [1.0, 1.0, 1.0]), 6) == round(annuity_factor(0.04, 3), 6) True
- financialkit.time_value.loan_payment(principal, annual_rate, n_payments, periods_per_year=12)[source]#
Level payment of a fully amortizing loan.
- Parameters:
- Returns:
float or ndarray
Examples
A 30-year, 200,000 mortgage at 6%:
>>> round(loan_payment(200_000.0, 0.06, 360), 2) 1199.1
- financialkit.time_value.mirr(cash_flows, finance_rate, reinvest_rate)[source]#
Baldwin’s modified internal rate of return.
Inflows are compounded to the horizon at reinvest_rate, outflows are discounted to today at finance_rate, and the MIRR is the single rate linking the two: \((FV^+ / |PV^-|)^{1/n} - 1\).
- Parameters:
- Return type:
- Returns:
float
Examples
>>> round(mirr([-1600, 10000, -10000], 0.10, 0.10), 6) 0.05599
- financialkit.time_value.npv(rate, cash_flows, times=None, compounding=1)[source]#
Fisher’s net present value of a project, outflows negative.
Unlike
present_value()the defaults follow capital budgeting: cash flows at the end of periods0, 1, ..., n - 1and an annually compounded rate.- Parameters:
rate (float or array-like) – Discount rate (the opportunity cost of capital).
cash_flows (array-like, shape (n,)) –
cash_flows[0]is usually the (negative) initial investment.times (array-like, shape (n,), optional) – Payment times; defaults to
0, 1, ..., n - 1.compounding (
int|None) – Periods per year of rate; default 1.
- Returns:
float or ndarray
Examples
Brealey-Myers-Allen (13th ed.), Sec. 2.1: an office block costing 370,000 that sells for 420,000 in a year, at 5%:
>>> round(npv(0.05, [-370_000, 420_000])) 30000
- financialkit.time_value.npv_profile(cash_flows, rates)[source]#
NPV across a range of discount rates, with every IRR marked.
- Parameters:
cash_flows (array-like, shape (n + 1,)) – Cash flows at periods
0, ..., n.rates (array-like) – Annually compounded discount rates.
- Return type:
- Returns:
NPVProfile
Examples
>>> profile = npv_profile([-100.0, 60.0, 60.0], [0.0, 0.1, 0.2]) >>> profile.npv.round(2).tolist() [20.0, 4.13, -8.33]
- financialkit.time_value.perpetuity_present_value(payment, rate, growth=0.0, due=False)[source]#
Value of a payment that continues forever, \(P / (i - g)\).
- Parameters:
- Returns:
float or ndarray
Examples
A 3% consol paying 3 a year, when long yields are 4%:
>>> round(perpetuity_present_value(3.0, 0.04), 6) 75.0
- financialkit.time_value.plot_amortization(schedule, ax=None)[source]#
Stacked interest and principal per payment, with the balance on a twin axis.
- Parameters:
schedule (AmortizationSchedule) – From
amortization_schedule().ax (matplotlib.axes.Axes, optional)
- Returns:
matplotlib.axes.Axes
- financialkit.time_value.plot_cash_flows(cash_flows, times=None, ax=None, title='Cash flows')[source]#
Bar timeline of a cash-flow stream, inflows up and outflows down.
- Parameters:
cash_flows (array-like, shape (n,))
times (array-like, shape (n,), optional) – Defaults to
0, 1, ..., n - 1.ax (matplotlib.axes.Axes, optional) – Axes to draw on; a new figure is created if omitted.
title (
str)
- Returns:
matplotlib.axes.Axes
- financialkit.time_value.plot_compounding_growth(rate, T, compoundings=(1, 4, 12, None), ax=None)[source]#
Growth of 1 at rate under several compounding frequencies.
- financialkit.time_value.plot_npv_profile(profile, ax=None, label=None)[source]#
NPV against the discount rate, with each IRR marked.
- Parameters:
profile (NPVProfile) – From
npv_profile().ax (matplotlib.axes.Axes, optional)
- Returns:
matplotlib.axes.Axes
- financialkit.time_value.present_value(cash_flows, times, rate, compounding=None)[source]#
Discounted value today of payments
cash_flowsmade attimes.- Parameters:
- Returns:
float or ndarray – Same shape as rate.
Examples
>>> round(present_value([100.0, 100.0], [1.0, 2.0], 0.10, compounding=1), 4) 173.5537
- financialkit.time_value.rule_of_72(rate, numerator=72.0)[source]#
Pacioli’s rule: money doubles in about
72 / (100 * rate)years.The rule approximates the exact annual-compounding doubling time \(\ln 2 / \ln(1 + r)\); 72 rather than \(100 \ln 2 \approx 69.3\) corrects for the curvature of \(\ln(1 + r)\) near 8%, and 72 has many divisors. Use
numerator=69.3for continuous compounding.- Parameters:
- Returns:
float or ndarray
Examples
>>> rule_of_72(0.06) 12.0
- financialkit.time_value.sign_changes(cash_flows)[source]#
Number of sign changes in a cash-flow stream, ignoring zeros.
By Descartes’ rule of signs this bounds the number of positive roots of the NPV polynomial in the discount factor, i.e. the number of internal rates of return above -100%.
- Parameters:
cash_flows (array-like)
- Return type:
- Returns:
int
Examples
>>> sign_changes([-1600, 10000, -10000]) 2
- financialkit.time_value.sinking_fund_payment(target, rate, n)[source]#
Level deposit that accumulates to target after n periods (Price, 1772).
- Parameters:
- Returns:
float or ndarray
Examples
>>> round(sinking_fund_payment(1000.0, 0.05, 10), 4) 79.5046
- financialkit.time_value.sinking_fund_schedule(target, rate, n)[source]#
Period-by-period growth of a sinking fund.
- Parameters:
- Return type:
- Returns:
SinkingFundSchedule
Examples
>>> round(float(sinking_fund_schedule(1000.0, 0.05, 10).balance[-1]), 6) 1000.0
- financialkit.time_value.year_fraction(start, end, convention=DayCount.ACT_365F)[source]#
Year fraction between two dates.
- Parameters:
start (date-like or array-like of date-likes)
end (date-like or array-like of date-likes)
convention (DayCount or str)
- Returns:
float or ndarray
Examples
ISDA (1998), Sec. 3, Example 1: November 1, 2003 to May 1, 2004 is 61/365 + 121/366 under actual/actual ISDA.
>>> round(year_fraction("2003-11-01", "2004-05-01", "ACT/ACT ISDA"), 5) 0.49772