Money v0.0.15 Money

Money implements a set of functions to store, retrieve and perform arithmetic on a %Money{} type that is composed of a currency code and a currency amount.

Money is very opinionated in the interests of serving as a dependable library that can underpin accounting and financial applications. In its initial release it can be expected that this contract may not be fully met.

How is this opinion expressed:

  1. Money must always have both a amount and a currency code.

  2. The currency code must always be valid.

  3. Money arithmetic can only be performed when both operands are of the same currency.

  4. Money amounts are represented as a Decimal.

  5. Money is serialised to the database as a custom Postgres composite type that includes both the amount and the currency. Therefore for Ecto serialization Postgres is assumed as the data store. Serialization is entirely optional and Ecto is not a package dependency.

  6. All arithmetic functions work in fixed point decimal. No rounding occurs automatically (unless expressly called out for a function).

  7. Explicit rounding obeys the rounding rules for a given currency. The rounding rules are defined by the Unicode consortium in its CLDR repository as implemented by the hex package ex_cldr. These rules define the number of fractional digits for a currency and the rounding increment where appropriate.

Summary

Types

t()

Money is composed of an atom representation of an ISO4217 currency code and a Decimal representation of an amount

Functions

Add two Money values

Compares two Money values numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned

Compares two Money values numerically. If the first number is greater than the second #Integer<1> is returned, if less than Integer<-1> is returned. Otherwise, if both numbers are equal Integer<0> is returned

Divide a Money value by a number

Returns a boolean indicating if two Money values are equal

Calculates the future value for a list of cash flows and an interest rate

Calculates the future value for a present value, an interest rate and a number of periods

Calculates the effective interest rate for a given present value, a future value and a number of periods

Calculates the interal rate of return for a given list of cash flows

Multiply a Money value by a number

Calculates the net present value of an initial investment, a list of cash flows and an interest rate

Calculates the net present value of an initial investment, a recurring payment, an interest rate and a number of periods

Returns a %Money{} struct from a tuple consistenting of a currency code and a currency amount. The format of the argument is a 2-tuple where

Returns a %Money{} struct from a currency code and a currency amount

Calculates the payment for a given loan or annuity given a present value, an interest rate and a number of periods

Calculates the number of periods between a present value and a future value with a given interest rate

Calculates the present value for a list of cash flows and an interest rate

Calculates the present value for future value, an interest rate and a number of periods

Round a Money value into the acceptable range for the defined currency

Split a Money value into a number of parts maintaining the currency’s precision and rounding and ensuring that the parts sum to the original amount

Called when an application is started

Subtract one Money value struct from another

Returns the amount part of a Money{} as a Decimal

Returns a formatted string representation of a Money{}

Types

t()
t() :: %Money{amount: Decimal, currency: atom}

Money is composed of an atom representation of an ISO4217 currency code and a Decimal representation of an amount.

Functions

add(money1, money2)

Add two Money values.

Example

iex> Money.add Money.new(:USD, 200), Money.new(:USD, 100)
#Money<:USD, 300>
cmp(money1, money2)

Compares two Money values numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned.

Examples

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 100)
:gt

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 200)
:eq

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 500)
:lt
compare(money1, money2)

Compares two Money values numerically. If the first number is greater than the second #Integer<1> is returned, if less than Integer<-1> is returned. Otherwise, if both numbers are equal Integer<0> is returned.

Examples

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 100)
1

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 200)
0

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 500)
-1
div(money, number)
div(Money.t, number) :: Money.t

Divide a Money value by a number.

  • money is a %Money{} struct

  • number is an integer or float

Note that dividing one %Money{} by another is not supported.

Example

iex> Money.div Money.new(:USD, 200), 2
#Money<:USD, 100>
equal?(arg1, arg2)
equal?(Money.t, Money.t) :: boolean

Returns a boolean indicating if two Money values are equal

Example

iex> Money.equal? Money.new(:USD, 200), Money.new(:USD, 200)
true

iex> Money.equal? Money.new(:USD, 200), Money.new(:USD, 100)
false
future_value(flows, interest_rate)

Calculates the future value for a list of cash flows and an interest rate.

  • flows is a list of tuples representing a cash flow. Each flow is represented as a tuple of the form {period, %Money{}}

  • interest_rate is a float representation of an interest rate. For example, 12% would be represented as 0.12

Example

iex> Money.future_value([{4, Money.new(:USD, 10000)}, {5, Money.new(:USD, 10000)}, {6, Money.new(:USD, 10000)}], 0.13)
#Money<:USD, 34068.99999999999999999999999>

iex> Money.future_value [{0, Money.new(:USD, 5000)},{1, Money.new(:USD, 2000)}], 0.12
#Money<:USD, 7600.000000000000000000000000>
future_value(present_value, interest_rate, periods)

Calculates the future value for a 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>
get_env(key, default \\ nil)
interest_rate(present_value, future_value, periods)

Calculates the effective interest rate for a given present value, a 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 a period

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>
internal_rate_of_return(flows)

Calculates the interal rate of return for a given list of cash flows.

  • flows is a list of tuples representing a cash flow. Each flow is represented as a tuple of the form {period, %Money{}}
mult(money, number)
mult(Money.t, number) :: Money.t

Multiply a Money value by a number.

  • money is a %Money{} struct

  • number is an integer or float

Note that multipling one %Money{} by another is not supported.

Example

iex> Money.mult Money.new(:USD, 200), 2
#Money<:USD, 400>
net_present_value(flows, interest_rate)

Calculates the net present value of an initial investment, a list of cash flows and an interest rate.

  • flows is a list of tuples representing a cash flow. Each flow is represented as a tuple of the form {period, %Money{}}

  • interest_rate is a float representation of an interest rate. For example, 12% would be represented as 0.12

  • investment is a %Money{} struct representing the initial investment

Example

iex> flows = [{0, Money.new(:USD, 5000)},{1, Money.new(:USD, 2000)},{2, Money.new(:USD, 500)},{3, Money.new(:USD,10_000)}]
iex> Money.net_present_value flows, 0.08, Money.new(:USD, 100)
#Money<:USD, 15118.84367220444038002337042>
iex> Money.net_present_value flows, 0.08
#Money<:USD, 15218.84367220444038002337042>
net_present_value(flows, interest_rate, investment)

Calculates the net present value of an initial investment, a recurring payment, an interest rate and a number of periods

  • investment is a %Money{} struct representing the initial investment

  • 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 a period

Example

iex> Money.net_present_value Money.new(:USD, 10000), 0.13, 2
#Money<:USD, 7831.466833737959119743127888>

iex> Money.net_present_value Money.new(:USD, 10000), 0.13, 2, Money.new(:USD, 100)
#Money<:USD, 7731.466833737959119743127888>
net_present_value(future_value, interest_rate, periods, investment)
new(money_tuple)
new({binary, number}) :: Money.t

Returns a %Money{} struct from a tuple consistenting of a currency code and a currency amount. The format of the argument is a 2-tuple where:

  • currency_code is an ISO4217 three-character upcased binary

  • amount is an integer, float or Decimal

This function is typically called from Ecto when it’s loading a %Money{} struct from the database.

Example

Money.new({"USD", 100})
#Money<:USD, 100>
new(currency_code, amount)
new(number, binary) :: Money.t

Returns a %Money{} struct from a currency code and a currency amount.

  • currency_code is an ISO4217 three-character upcased binary or atom

  • amount is an integer, float or Decimal

Examples

iex> Money.new(:USD, 100)
#Money<:USD, 100>

iex> Money.new("USD", 100)
#Money<:USD, 100>

iex> Money.new("thb", 500)
#Money<:THB, 500>

iex> Money.new(500, "thb")
#Money<:THB, 500>

iex> Money.new("EUR", Decimal.new(100))
#Money<:EUR, 100>
payment(present_value, interest_rate, periods)

Calculates the payment for a given loan or annuity given a 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>
periods(present_value, future_value, interest_rate)

Calculates the number of periods between a present value and a 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>
present_value(flows, interest_rate)

Calculates the present value for a list of cash flows and an interest rate.

  • flows is a list of tuples representing a cash flow. Each flow is represented as a tuple of the form {period, %Money{}}

  • interest_rate is a float representation of an interest rate. For example, 12% would be represented as 0.12

Example

iex> Money.present_value([{4, Money.new(:USD, 10000)}, {5, Money.new(:USD, 10000)}, {6, Money.new(:USD, 10000)}], 0.13)
#Money<:USD, 16363.97191111964880256655144>

iex> Money.present_value [{0, Money.new(:USD, -1000)},{1, Money.new(:USD, -4000)}], 0.1
#Money<:USD, -4636.363636363636363636363636>
present_value(future_value, interest_rate, periods)

Calculates the present value for 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>
round(money, opts \\ [])

Round a Money value into the acceptable range for the defined currency.

  • money is a %Money{} struct

  • opts is a keyword list with the following keys:

  • :rounding_mode that defines how the number will be rounded. See Decimal.Context. The default is :half_even which is also known as “banker’s rounding”

  • :cash which determines whether the rounding is being applied to an accounting amount or a cash amount. Some currencies, such as the :AUD and :CHF have a cash unit increment minimum which requires a different rounding increment to an arbitrary accounting amount. The default is false.

There are two kinds of rounding applied:

  1. Round to the appropriate number of fractional digits

  2. Apply an appropriate rounding increment. Most currencies round to the same precision as the number of decimal digits, but some such as :AUD and :CHF round to a minimum such as 0.05 when its a cash amount.

Examples

iex> Money.round Money.new(123.7456, :CHF), cash: true
#Money<:CHF, 125>

iex> Money.round Money.new(123.7456, :CHF)
#Money<:CHF, 123.75>

Money.round Money.new(123.7456, :JPY)
#Money<:JPY, 124>
split(money, parts)

Split a Money value into a number of parts maintaining the currency’s precision and rounding and ensuring that the parts sum to the original amount.

  • money is a %Money{} struct

  • parts is an integer number of parts into which the money is split

Returns a tuple {dividend, remainder} as the function result derived as follows:

  1. Round the money amount to the required currency precision using Money.round/1

  2. Divide the result of step 1 by the integer divisor

  3. Round the result of the division to the precision of the currency using Money.round/1

  4. Return two numbers: the result of the division and any remainder that could not be applied given the precision of the currency.

Examples

Money.split Money.new(123.5, :JPY), 3
{¥41, ¥1}

Money.split Money.new(123.4, :JPY), 3
{¥41, ¥0}

Money.split Money.new(123.7, :USD), 9
{$13.74, $0.04}
start(type, args)

Called when an application is started.

This function is called when an the application is started using Application.start/2 (and functions on top of that, such as Application.ensure_started/2). This function should start the top-level process of the application (which should be the top supervisor of the application’s supervision tree if the application follows the OTP design principles around supervision).

start_type defines how the application is started:

  • :normal - used if the startup is a normal startup or if the application is distributed and is started on the current node because of a failover from another mode and the application specification key :start_phases is :undefined.
  • {:takeover, node} - used if the application is distributed and is started on the current node because of a failover on the node node.
  • {:failover, node} - used if the application is distributed and is started on the current node because of a failover on node node, and the application specification key :start_phases is not :undefined.

start_args are the arguments passed to the application in the :mod specification key (e.g., mod: {MyApp, [:my_args]}).

This function should either return {:ok, pid} or {:ok, pid, state} if startup is successful. pid should be the PID of the top supervisor. state can be an arbitrary term, and if omitted will default to []; if the application is later stopped, state is passed to the stop/1 callback (see the documentation for the c:stop/1 callback for more information).

use Application provides no default implementation for the start/2 callback.

Callback implementation for Application.start/2.

sub(money1, money2)

Subtract one Money value struct from another.

Example

iex> Money.sub Money.new(:USD, 200), Money.new(:USD, 100)
#Money<:USD, 100>
to_currency(money, to_currency, rates \\ Money.ExchangeRates.latest_rates())

Convert money from one currency to another.

  • money is a %Money{} struct

  • currency is a valid currency code. An exception is raised if the currency code is invalid or if there is no known exchange rate.

  • rates is a Map of currency rates where the map key is an upcase atom and the value is a decimal convertion factor. The default is the latest available exchange rates from Open Exchange Rates

to_currency converts one money amount to another currency via a map of currency conversion values.

##Example

#> Money.to_currency Money.new(:USD, 100), :AUD
to_decimal(money)

Returns the amount part of a Money{} as a Decimal

Example

iex> m = Money.new("USD", 100)
iex> Money.to_decimal(m)
#Decimal<100>
to_string(money, options \\ [])

Returns a formatted string representation of a Money{}.

Formatting is performed according to the rules defined by CLDR. See Cldr.Number.to_string/2 for formatting options. The default is to format as a currency which applies the appropriate rounding and fractional digits for the currency.

Examples

iex> Money.to_string Money.new(:USD, 1234)
"$1,234.00"

iex> Money.to_string Money.new(:JPY, 1234)
"¥1,234"

iex> Money.to_string Money.new(:THB, 1234)
"THB1,234.00"

iex> Money.to_string Money.new(:USD, 1234), format: :long
"1,234 US dollars"