Dated Money is a Python library for manipulating monetary values with control over the date on which currency conversions take place. It represents each monetary value as an amount (stored as a Decimal in cents) and a currency, along with a corresponding date.
It differs from the money package in that it treats the date as a first-class element.
It downloads and saves today's conversion rates from https://www.exchangerate-api.com/ using your API key (see below). You may need a paid account for the fetching of rates for days other than today to work.
- Perform arithmetic operations on monetary values with different currencies and dates
- Convert monetary values between currencies based on exchange rates for specific dates
- Fetch and cache exchange rates from external APIs or local repositories
- Flexible configuration through environment variables
You can install Dated Money using pip:
pip install dated-money
from decimal import Decimal as Dec
from dmon import Money, Currency
# Create a Money class with EUR as the base currency and conversion rates from a specific date
date_a = '2022-07-14'
Eur = Money(Currency.EUR, date_a)
# Create a Money class with AUD as the base currency and conversion rates from the same date
Aud = Money(base_currency='A$', base_date=date_a)
# Create monetary values in different currencies
price_eur = Eur(100) # €100
price_usd = Eur(120, Currency.USD) # $120
price_gbp = Eur(80, '£') # £80
# Values are stored in cents and can be accessed in any currency
assert Eur(23, '€').cents('eur') == 2300
assert Eur(40).cents('usd') == Dec('4020.100502512562832012897042')
# Values can be created in any currency, regardless of the base currency
assert Eur(20, '£') == Aud(20, '£')
# Perform arithmetic operations
total = price_eur + price_usd + price_gbp
assert str(total) == '€270.40' # Total in the base currency (EUR)
# Convert to a specific currency
total_usd = total.to(Currency.USD)
assert str(total_usd) == '$303.89'
# Compare monetary values
assert price_eur < price_usd
assert price_gbp == Eur(80, Currency.GBP)
You can perform operations on monetary values with different currencies and conversion dates:
date_a = '2022-07-14'
date_b = '2022-01-07'
Eur = Money(Currency.EUR, date_a)
OldEur = Money('€', date_b)
Aud = Money(Currency.AUD, date_a)
# Operations between instances with different dates return an instance with the base date of the first element
adds = OldEur(10) + Eur(30)
assert adds.amount() == 40
assert adds.on_date == OldEur.base_date
# Operations between instances with different currencies return a result in the base currency
result = Eur(10, '$') + Eur(20, 'CAD')
assert result.currency == Currency.EUR
# Changing the reference dates affects the operation results
assert Eur(10, '$', date_a) + Eur(20, 'CAD', date_a) != Eur(10, '$', date_b) + Eur(20, 'CAD', date_b)
# Perform various arithmetic operations
assert Aud(10) + Eur(20) == Aud(39.70) == Eur(39.7, 'aud')
assert Eur(20) + Aud(10) == Eur(26.73)
assert (Aud(10) + Eur(20)).currency == Currency.AUD
assert (Eur(20) + Aud(10)).currency == Currency.EUR
assert Eur(20, 'aud') + Eur(20, 'gbp') == Aud(20, 'aud') + Aud(20, 'gbp')
In normal use, you will probably create a single Money class with your preferred base currency and use it to handle monetary values in various currencies:
Eur = Money(Currency.EUR)
price_eur = Eur(100) # €100
price_usd = Eur(120, Currency.USD) # $120
price_gbp = Eur(80, '£') # £80
total = price_eur + price_usd + price_gbp
assert str(total) == '€304.71' # Total in the base currency (EUR)
assert price_usd.currency == Currency.USD
assert price_gbp.currency == Currency.GBP
Dated Money provides flexibility in configuring exchange rates through environment variables:
-
DMON_RATES_CACHE
: Set this to a directory where the library can maintain a cache of exchange rates (stored in an SQLite database). -
DMON_EXCHANGERATE_API_KEY
: If the rates file for a given date is not found in the repository or cache, the library will attempt to download it from https://exchangerate-api.com. Set this environment variable to your API key. Note that you may need a paid account to download historical data. -
DMON_RATES_REPO
: Set this to a directory containing a git repository with the exchange rates in amoney
subdirectory. The rates should be stored in files namedyyyy-mm-dd-rates.json
, and contain a dictionary like:
{
"conversion_rates":{
"USD":1,
"AED":3.6725,
"AFN":71.3141,
...}
}
To create the cache database, follow these steps:
-
Set the
DMON_RATES_CACHE
environment variable:export DMON_RATES_CACHE=~/.dmon
-
Create the database cache table:
dmon-rates --create-table
If you have a paid API key for https://exchangerate-api.com, you can set the DMON_EXCHANGERATE_API_KEY
environment variable and create your cache with:
dmon-rates --fetch-rates 2021-10-10:2021-10-20
Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on the GitHub repository.
Dated Money is released under the MIT License.