Simple checked fixed-point currencies for Julia.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
docs Delete .documenter.enc (#82) May 14, 2017
src
test Update for 1.0 Oct 16, 2018
.gitignore Migrate from Sphinx to Documenter.jl (#22) Jun 5, 2016
.travis.yml Drop v0.5 support (#89) Sep 5, 2017
LICENSE.md Update LICENSE.md (#70) Feb 24, 2017
README.md
REQUIRE Update for 1.0 Oct 16, 2018
appveyor.yml Drop v0.5 support (#89) Sep 5, 2017

README.md

Currencies.jl

Join the chat at https://gitter.im/JuliaFinance/Currencies.jl Build Status Build status Coverage Status codecov

Purpose

This package provides a simple interface to using a wide variety of currencies with performant checked arithmetic in Julia. Creating and using monetary values is clean and easy. For advanced users, it also offers rich formatting and other powerful features, such as integration with currency conversion APIs.

Data Source

The currency-related information for this package comes from this Wikipedia page, the official ISO standard, and other Wikipedia pages. It is compiled manually and may be in error; please do submit a pull request to correct any errors.

Usage

This README.md file provides a basic guide to getting started. It is not a replacement for the documentation. Please file any corrections or missing parts of the documentation as issues, or even better, send in a pull request.

The Currencies module exports the Monetary type. To access currencies, use the @usingcurrencies macro. Basic operation is as follows:

@usingcurrencies USD
1USD + 2USD  # 3.00 USD
3 * 1.5USD   # 4.50 USD

Mixed arithmetic is not supported:

@usingcurrencies USD, CAD
10USD + 3CAD  # ArgumentError

Monetary amounts can be compared:

@usingcurrencies USD, EUR
1USD < 2USD        # true
sort([2EUR, 1EUR]) # [1EUR, 2EUR]

Baskets, effectively collections of many different currencies, are supported using the Basket type. To catch likely errors, Monetary objects don't support mixed arithmetic. But if mixed arithmetic is desired, it is still possible by promoting one of the objects to a Basket type:

@usingcurrencies USD, CAD
money = 100USD
basket = Basket(money)  # Basket([100USD])
basket += 20CAD         # Basket([100USD, 20CAD])

To access an individual component of a basket, indexing notation is supported.

@usingcurrencies USD, EUR, GBP
sdr = Basket([1USD, 2EUR, 3GBP])
sdr[:USD] = 3USD
sdr[:GBP]  # 3.00 GBP

Because of the nature of holding multiple currencies, some operations are not supported. In particular, one cannot divide baskets by baskets or compare baskets with baskets (equality, however, is still supported). Baskets however can be iterated over to get their components, in undefined order. Basket objects additionally support push!.

@usingcurrencies USD, EUR, GBP, JPY
basket = Basket([300USD, 400EUR, 500GBP, 600JPY])
for amount::Monetary in basket
    println(amount)
end
push!(basket, 200USD)
basket[:USD]

For convenience, it's possible to add Basket values to regular Monetary values. But as seen earlier, adding two Monetary values does not result in a Basket value. If it's desired to combine two values of unknown type (either Basket or Monetary), the constructor for Basket can be used directly:

@usingcurrencies USD, EUR, GBP
a = Basket([20USD, 20EUR])
b = 10USD
c = Basket([5EUR, 40GBP])
Basket([a, b, c])  # Basket([30USD, 25EUR, 40GBP])

Note that for consistency with the constructor, push! for Basket accepts a Basket object as an argument. This is somewhat inconsistent with other containers, which use append! or union!.

Using Monetary in Practice

Monetary types behave a lot like integer types, and they can be used like them for a lot of practical situations. For example, here is a (quite fast) function to give optimal change using the common European system of having coins and bills worth 0.01€, 0.02€, 0.05€, 0.10€, 0.20€, 0.50€, 1.00€, and so forth until 500.00€ (this algorithm doesn't necessarily work for all combinations of coin values).

@usingcurrencies EUR
COINS = [500EUR, 200EUR, 100EUR, 50EUR, 20EUR, 10EUR, 5EUR, 2EUR, 1EUR, 0.5EUR,
    0.2EUR, 0.1EUR, 0.05EUR, 0.02EUR, 0.01EUR]
function change(amount::Monetary{:EUR,Int})
    coins = Dict{Monetary{:EUR,Int}, Int}()
    for denomination in COINS
        coins[denomination], amount = divrem(amount, denomination)
    end
    coins
end

sum([k*v for (k, v) in change(167.25EUR)])  # 167.25EUR

Valuation

Sometimes it is useful to value a Basket or a single Monetary value into a different currency, using an exchange rate. One way to do this is with the valuate function, and by constructing an ExchangeRateTable. An example follows:

@usingcurrencies USD, CAD, JPY
rates = ExchangeRateTable(
    :USD => 1.0,
    :CAD => 0.7,
    :JPY => 0.02)
valuate(rates, :USD, 100JPY)  # 2.00 USD

For more on valuation, as usual, see the documentation.

Floating Points & Other Reals

Advanced users may be interested in a cautionary note on rounding.

Custom Currencies & Names

Advanced users may also be interested in using currencies that are not in ISO 4217.

Related Packages

Please see FinancialMarkets.jl package in case that suits your needs better.