Finance.TVM (finance v1.2.0)

Copy Markdown View Source

Time-value-of-money scalars: fv/5, pv/5, pmt/5, nper/5, and rate/6.

Each solves the standard annuity equation for one unknown:

pv·(1+r)^n + pmt·(1 + r·type)·((1+r)^n  1)/r + fv = 0

type is 0 for payments at the end of each period (ordinary annuity) or 1 for the beginning (annuity due). The sign convention follows spreadsheets: money you receive is positive, money you pay out is negative.

Summary

Functions

Works out the future value of an investment: what it grows to after nper periods, starting from a present value of pv, with a fixed payment of pmt each period, all compounding at rate.

Same as fv/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

Works out how many periods it takes for payments of pmt to pay off a present value pv (reaching future value fv) at rate.

Same as nper/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

Works out the level payment per period needed to pay off a present value pv (and arrive at a future value fv) over nper periods at rate.

Same as pmt/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

Works out the present value of an investment: what a future stream is worth today. The stream is pmt paid each period for nper periods plus a lump sum fv at the end, all discounted back at rate.

Same as pv/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

Works out the interest rate per period of an annuity described by nper payments of pmt, a present value pv, and a future value fv. nper has to be a whole number of periods.

Same as rate/6, but hands back the rate on its own and raises ArgumentError if the calculation fails.

Types

error()

@type error() :: Finance.error()

option()

@type option() :: Finance.option()

rate()

@type rate() :: Finance.rate()

Functions

fv(rate, nper, pmt, pv \\ 0.0, type \\ 0)

@spec fv(number(), number(), number(), number(), 0 | 1) ::
  {:ok, float()} | {:error, error()}

Works out the future value of an investment: what it grows to after nper periods, starting from a present value of pv, with a fixed payment of pmt each period, all compounding at rate.

Use this to answer "if I put this much in now and add this much every period, what will I have at the end?". As with the rest of the time-value-of-money functions, type chooses when each payment happens — 0 for the end of the period (an ordinary annuity) or 1 for the beginning (an annuity due) — and the sign convention follows spreadsheets, so money you receive is positive and money you pay out is negative.

iex> {:ok, value} = Finance.TVM.fv(0.05, 10, -100, -1000)
iex> Float.round(value, 2)
2886.68

fv!(rate, nper, pmt, pv \\ 0.0, type \\ 0)

@spec fv!(number(), number(), number(), number(), 0 | 1) :: float()

Same as fv/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

nper(rate, pmt, pv, fv \\ 0.0, type \\ 0)

@spec nper(number(), number(), number(), number(), 0 | 1) ::
  {:ok, float()} | {:error, error()}

Works out how many periods it takes for payments of pmt to pay off a present value pv (reaching future value fv) at rate.

This is the "how long until it's paid off?" question. When the numbers don't describe a situation that ever resolves, it returns {:error, :undefined}.

iex> {:ok, periods} = Finance.TVM.nper(0.05, -100, 1000)
iex> Float.round(periods, 2)
14.21

nper!(rate, pmt, pv, fv \\ 0.0, type \\ 0)

@spec nper!(number(), number(), number(), number(), 0 | 1) :: float()

Same as nper/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

pmt(rate, nper, pv, fv \\ 0.0, type \\ 0)

@spec pmt(number(), number(), number(), number(), 0 | 1) ::
  {:ok, float()} | {:error, error()}

Works out the level payment per period needed to pay off a present value pv (and arrive at a future value fv) over nper periods at rate.

This is the loan-payment question: given an amount borrowed today, what fixed installment clears it over the term? The same type and sign conventions apply, so a loan you take out is a positive pv and the payment comes back negative.

iex> {:ok, payment} = Finance.TVM.pmt(0.10, 10, 1000)
iex> Float.round(payment, 2)
-162.75

pmt!(rate, nper, pv, fv \\ 0.0, type \\ 0)

@spec pmt!(number(), number(), number(), number(), 0 | 1) :: float()

Same as pmt/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

pv(rate, nper, pmt, fv \\ 0.0, type \\ 0)

@spec pv(number(), number(), number(), number(), 0 | 1) ::
  {:ok, float()} | {:error, error()}

Works out the present value of an investment: what a future stream is worth today. The stream is pmt paid each period for nper periods plus a lump sum fv at the end, all discounted back at rate.

It answers the mirror image of fv/5's question — "how much would I need to put in now to fund these future payments?". The same type and sign conventions apply.

iex> {:ok, value} = Finance.TVM.pv(0.05, 10, -100, -1000)
iex> Float.round(value, 2)
1386.09

pv!(rate, nper, pmt, fv \\ 0.0, type \\ 0)

@spec pv!(number(), number(), number(), number(), 0 | 1) :: float()

Same as pv/5, but hands back the value on its own and raises ArgumentError if the calculation fails.

rate(nper, pmt, pv, fv \\ 0.0, type \\ 0, opts \\ [])

@spec rate(number(), number(), number(), number(), 0 | 1, [option()]) ::
  {:ok, rate()} | {:error, error()}

Works out the interest rate per period of an annuity described by nper payments of pmt, a present value pv, and a future value fv. nper has to be a whole number of periods.

There is no closed form for the rate, so this reuses the same numerical solver as Finance.CashFlow.irr/1 and takes the same options. If it can't pin down a rate, it returns {:error, :did_not_converge}.

iex> Finance.TVM.rate(10, -100, 1000)
{:ok, 0.0}

rate!(nper, pmt, pv, fv \\ 0.0, type \\ 0, opts \\ [])

@spec rate!(number(), number(), number(), number(), 0 | 1, [option()]) :: rate()

Same as rate/6, but hands back the rate on its own and raises ArgumentError if the calculation fails.