Source code for qfinbox.tvm.annuities

"""Annuity calculations."""

from ..core.validators import validate_positive


[docs] def ordinary_annuity_pv( payment: float, rate: float, periods: int, ) -> float: """ Calculate present value of ordinary annuity. Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. Returns ------- float Present value of ordinary annuity. Examples -------- >>> ordinary_annuity_pv(1000, 0.05, 10) 7721.73 """ validate_positive(payment, "payment") validate_positive(rate, "rate") validate_positive(periods, "periods") return payment * (1 - (1 + rate) ** -periods) / rate
[docs] def ordinary_annuity_fv( payment: float, rate: float, periods: int, ) -> float: """ Calculate future value of ordinary annuity. Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. Returns ------- float Future value of ordinary annuity. Examples -------- >>> ordinary_annuity_fv(1000, 0.05, 10) 12577.89 """ validate_positive(payment, "payment") validate_positive(rate, "rate") validate_positive(periods, "periods") return payment * (((1 + rate) ** periods - 1) / rate)
[docs] def annuity_due_pv( payment: float, rate: float, periods: int, ) -> float: """ Calculate present value of annuity due. Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. Returns ------- float Present value of annuity due. Examples -------- >>> annuity_due_pv(1000, 0.05, 10) 8107.82 """ return ordinary_annuity_pv(payment, rate, periods) * (1 + rate)
[docs] def annuity_due_fv( payment: float, rate: float, periods: int, ) -> float: """ Calculate future value of annuity due. Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. Returns ------- float Future value of annuity due. Examples -------- >>> annuity_due_fv(1000, 0.05, 10) 13206.79 """ return ordinary_annuity_fv(payment, rate, periods) * (1 + rate)
[docs] def annuity_pv( payment: float, rate: float, periods: int, due: bool = False, ) -> float: """ Calculate present value of annuity (ordinary or due). Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. due : bool, default False If True, calculate annuity due. If False, ordinary annuity. Returns ------- float Present value of annuity. """ if due: return annuity_due_pv(payment, rate, periods) return ordinary_annuity_pv(payment, rate, periods)
[docs] def annuity_fv( payment: float, rate: float, periods: int, due: bool = False, ) -> float: """ Calculate future value of annuity (ordinary or due). Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). periods : int Number of periods. due : bool, default False If True, calculate annuity due. If False, ordinary annuity. Returns ------- float Future value of annuity. """ if due: return annuity_due_fv(payment, rate, periods) return ordinary_annuity_fv(payment, rate, periods)
[docs] def perpetuity_value( payment: float, rate: float, ) -> float: """ Calculate present value of a perpetuity. A perpetuity is a stream of equal payments that continues forever. Parameters ---------- payment : float Periodic payment amount. rate : float Interest rate per period (as decimal). Returns ------- float Present value of perpetuity. Raises ------ ValidationError If any parameter is invalid. Examples -------- >>> perpetuity_value(50000, 0.04) 1250000.0 Notes ----- The formula for a perpetuity is simply: PV = Payment / Rate """ validate_positive(payment, "payment") validate_positive(rate, "rate") return payment / rate
[docs] def growing_annuity_pv( payment: float, rate: float, growth_rate: float, periods: int, ) -> float: """ Calculate present value of a growing annuity. A growing annuity has payments that grow at a constant rate each period. Parameters ---------- payment : float Initial payment amount. rate : float Interest rate per period (as decimal). growth_rate : float Growth rate of payments per period (as decimal). periods : int Number of periods. Returns ------- float Present value of growing annuity. Raises ------ ValidationError If any parameter is invalid. Examples -------- >>> growing_annuity_pv(2, 0.09, 0.05, 20) 24.36 Notes ----- If rate equals growth_rate, the formula becomes: PV = PMT * n / (1 + r) Otherwise: PV = PMT * [(1 - ((1 + g) / (1 + r))^n) / (r - g)] """ validate_positive(payment, "payment") validate_positive(rate, "rate") validate_positive(periods, "periods") # Special case when rate equals growth rate if abs(rate - growth_rate) < 1e-10: return payment * periods / (1 + rate) # Standard growing annuity formula return ( payment * (1 - ((1 + growth_rate) / (1 + rate)) ** periods) / (rate - growth_rate) )