Packages

Money functions for operations on and localization of a money data type with support for ISO 4217 currencies and ISO 24165 digial tokens (crypto currencies).

Retired package: Deprecated

Current section

Files

Jump to
ex_money lib money financial.ex
Raw

lib/money/financial.ex

defmodule Money.Financial do
@moduledoc false
# Some algorithms from http://www.financeformulas.net
alias Cldr.Number.Math
defmacro __using__(_opts) do
quote do
@doc """
Calculates the future value for a %Money{} present value, an interest rate
and a number of periods.
* `present_value` is a %Money{} representation of the present value
* `interest_rate` is a float representation of an interest rate. For
example, 12% would be represented as `0.12`
* `periods` in an integer number of periods
## Examples
iex> Money.future_value Money.new(:USD, 10000), 0.08, 1
#Money<:USD, 10800.00>
iex> Money.future_value Money.new(:USD, 10000), 0.04, 2
#Money<:USD, 10816.0000>
iex> Money.future_value Money.new(:USD, 10000), 0.02, 4
#Money<:USD, 10824.32160000>
"""
@one Decimal.new(1)
def future_value(%Money{currency: currency, amount: amount} = present_value, interest_rate, periods)
when is_number(interest_rate) and is_number(periods) do
fv = interest_rate
|> Decimal.new
|> Decimal.add(@one)
|> Math.power(periods)
|> Decimal.mult(amount)
Money.new(currency, fv)
end
@doc """
Calculates the present value for %Money{} future value, an interest rate
and a number of periods
* `future_value` is a %Money{} representation of the future value
* `interest_rate` is a float representation of an interest rate. For
example, 12% would be represented as `0.12`
* `periods` in an integer number of periods
## Examples
iex> Money.present_value Money.new(:USD, 100), 0.08, 2
#Money<:USD, 85.73388203017832647462277092>
iex> Money.present_value Money.new(:USD, 1000), 0.10, 20
#Money<:USD, 148.6436280241436864020760472>
"""
def present_value(%Money{currency: currency, amount: amount} = future_value, interest_rate, periods)
when is_number(interest_rate) and interest_rate > 0 and is_number(periods) and periods > 0 do
pv_1 = interest_rate
|> Decimal.new
|> Decimal.add(@one)
|> Math.power(periods)
pv = Decimal.div(@one, pv_1)
|> Decimal.mult(amount)
Money.new(currency, pv)
end
@doc """
Calculates the effective interest rate for a given %Money{} present value,
a %Money{} future value and a number of periods.
* `present_value` is a %Money{} representation of the present value
* `future_value` is a %Money{} representation of the future value
* `periods` is an integer number of periods
## Examples
iex> Money.interest_rate Money.new(:USD, 10000), Money.new(:USD, 10816), 2
#Decimal<0.04>
iex> Money.interest_rate Money.new(:USD, 10000), Money.new(:USD, 10824.3216), 4
#Decimal<0.02>
"""
def interest_rate(%Money{currency: pv_currency, amount: pv_amount} = present_value,
%Money{currency: fv_currency, amount: fv_amount} = future_value,
periods)
when pv_currency == fv_currency and is_number(periods) and periods > 0 do
Decimal.div(fv_amount, pv_amount)
|> Math.root(periods)
|> Decimal.sub(@one)
end
@doc """
Calculates the number of periods between a %Money{} present value and
a %Money{} future value with a given interest rate.
* `present_value` is a %Money{} representation of the present value
* `future_value` is a %Money{} representation of the future value
* `interest_rate` is a float representation of an interest rate. For
example, 12% would be represented as `0.12`
## Example
iex> Money.periods Money.new(:USD, 1500), Money.new(:USD, 2000), 0.005
#Decimal<57.68013595323872502502238648>
"""
def periods(%Money{currency: pv_currency, amount: pv_amount} = present_value,
%Money{currency: fv_currency, amount: fv_amount} = future_value,
interest_rate)
when pv_currency == fv_currency and is_number(interest_rate) and interest_rate > 0 do
Decimal.div(Math.log(Decimal.div(fv_amount, pv_amount)),
Math.log(Decimal.add(@one, Decimal.new(interest_rate))))
end
@doc """
Calculates the payment for a given loan or annuity given a %Money{}
present value, an interest rate and a number of periods.
* `present_value` is a %Money{} representation of the present value
* `interest_rate` is a float representation of an interest rate. For
example, 12% would be represented as `0.12`
* `periods` is an integer number of periods
## Example
iex> Money.payment Money.new(:USD, 100), 0.12, 20
#Money<:USD, 13.38787800396606622792492299>
"""
def payment(%Money{currency: pv_currency, amount: pv_amount} = present_value,
interest_rate, periods)
when is_number(interest_rate) and interest_rate > 0 and is_number(periods) and periods > 0 do
interest_rate = Decimal.new(interest_rate)
p1 = Decimal.mult(pv_amount, interest_rate)
p2 = Decimal.sub(@one, Decimal.add(@one, interest_rate) |> Math.power(-periods))
Money.new(pv_currency, Decimal.div(p1, p2))
end
end
end
end