Skip to main content

OfflineCurrencyConverter

Historical fiat and cryptocurrency conversion for offline Python applications. Requires Python 3.10 or newer.

OfflineCurrencyConverter follows the familiar CurrencyConverter API, including CurrencyConverter, convert(), date=, currency bounds, and optional fallback settings. It extends this interface with cryptocurrency coverage, configurable date windows, and exchange-rate quotes with snapshot metadata. See API compatibility for supported behavior.

Exchange-rate data is included in every package. Automated daily builds refresh the bundled historical dataset and produce a date-versioned wheel. Applications receive updated rates by installing a newer package build; conversion and rate lookup never require access to external data services. This supports air-gapped deployments using an internal Python package index or a local wheelhouse.

Currency data

Fiat reference rates come from the European Central Bank. Cryptocurrency and stablecoin rates come from CoinMarketCap. All source rates are stored as units per EUR, enabling conversion between supported currencies through EUR.

Each wheel contains one cumulative CSV snapshot. Its calendar starts on 1999-01-04 and ends on the day before the snapshot's run date. Individual currencies have different periods of coverage. Crypto uses completed daily closing prices; unfinished current-day observations are excluded.

A scheduled GitHub Action generates updated data and a wheel daily at 16:30 Europe/Amsterdam. Successful builds are committed to output/ and made available as workflow artifacts. Versions follow the snapshot date: 2026.11.9 identifies the November 9, 2026 snapshot. Publication to public PyPI is a separate, manually triggered workflow.

Fiat observations may be absent on weekends and holidays. Missing or failed source observations remain unavailable until a subsequent update obtains them. The installed dataset stays fixed until the package or local snapshot is replaced; the converter does not refresh it automatically.

Installation

Download a wheel from output/, then install it in a virtual environment:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install /path/to/offlinecurrencyconverter-2026.11.9-py3-none-any.whl

For air-gapped systems, make the wheel and its dependencies available through an internal PyPI mirror or a local wheelhouse. For example:

python -m pip install --no-index --find-links=/path/to/wheelhouse OfflineCurrencyConverter

The wheel bundles the rates, but its dependencies must also be installed. To replace an installed build with an updated wheel of the same version, use python -m pip install --force-reinstall /path/to/package.whl.

Python API

Create a converter once and reuse it:

from offline_currency_converter import CurrencyConverter

c = CurrencyConverter()
euros = c.convert(100, "USD")          # EUR is the default destination.
yen = c.convert(100, "USD", "JPY")    # Latest common observation.

Choose a historical date with date=:

from datetime import date

amount = c.convert(100, "USD", "EUR", date=date(2026, 11, 2))

Omitting date, or passing None, uses the latest common observation in the loaded snapshot. An explicit date requires an exact observation unless a date window or fallback is enabled. Dates also accept datetime objects, YYYY-MM-DD strings, and D.M.YYYY strings.

Decimal amounts and rounding

Conversions return floats by default. Enable decimal=True for Decimal results, and pass string or Decimal amounts to preserve input precision:

from decimal import Decimal, ROUND_HALF_UP
from offline_currency_converter import CurrencyConverter

c = CurrencyConverter(decimal=True)
eur = c.convert("100", "USD", date="2026-11-02")
eur = eur.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)

The converter does not apply monetary rounding. Round the final amount to the destination currency's minor unit: EUR and USD use two decimal places, while some currencies use zero or three. Formatting with f"{eur:.2f}" changes only the displayed text; quantize() returns a rounded Decimal value.

Date windows

Pass date_window to select the nearest usable observation within an inclusive window of calendar days before or after the requested date:

amount = c.convert("100", "USD", "EUR", date="2026-11-02", date_window=30)

An equally distant pair of observations resolves to the earlier date. Both currencies must have valid rates on the same observation date. Zero requires an exact match. An explicit window overrides fallback settings, including out-of-range fallback, and raises RateNotFoundError if no match exists.

Applications requiring a 30-day policy must explicitly pass their selected date and date_window=30.

Fallbacks

Enable last-known fallback for missing dates within the currencies' date bounds:

c = CurrencyConverter(fallback_on_missing_rate=True, decimal=True)

Enable boundary fallback for requested dates outside the available range:

c = CurrencyConverter(
    fallback_on_missing_rate=True,
    fallback_on_wrong_date=True,
    decimal=True,
)

Last-known fallback selects a common observation on or before the requested date. Boundary fallback uses the first or last common available observation. The supported method is fallback_on_missing_rate_method="last_known"; linear interpolation is not implemented. All quotes identify actual observations.

Rate quotes

get_rate() returns an immutable RateQuote containing:

Field Meaning
rate Decimal multiplier: destination units per one source unit
rate_date Actual selected observation date, as datetime.date
snapshot_version Snapshot filename date, such as "2026.11.09"; None for unrecognized custom filenames
from decimal import Decimal

quote = c.get_rate("USD", "EUR", date="2026-11-02", date_window=30)
euro_amount = Decimal("100") * quote.rate
print(quote.rate_date, quote.snapshot_version)

The multiplier is destination-units-per-EUR divided by source-units-per-EUR. EUR has an implicit rate of 1. For identical supported currencies, the rate is 1 and rate_date is the resolved requested date, without requiring a historical observation. The snapshot version describes the dataset, not per-observation source provenance.

Supported currencies and date bounds

print(sorted(c.currencies))
first_date, last_date = c.bounds["USD"]
print(first_date, last_date)

currencies includes EUR, fiat, crypto, and historical currency symbols present in the snapshot. A listed currency may have no rate for a particular date. bounds includes only currencies with usable observations. EUR bounds cover the snapshot calendar, although EUR identity conversions also work outside it.

Custom data

Load an explicit local CSV, using the same units-per-EUR format:

c = CurrencyConverter("/path/to/snapshot.csv", decimal=True)
# Also accepted: CurrencyConverter(currency_file="/path/to/snapshot.csv")

By default, the newest filename-dated snapshot is selected across local output/ and the package's bundled data. output_dir= restricts selection to a chosen directory. URL and ZIP inputs are not supported.

Exceptions

  • UnknownCurrencyError: a requested symbol is not supported by the snapshot.
  • RateNotFoundError: no snapshot or suitable observation is available.
  • ValueError: invalid amounts, dates, date windows, or unsupported fallback options.

Blank, ERROR, zero, negative, and non-finite rates are never used for conversion.

Command line

offline-currency-converter 100 USD --to EUR
offline-currency-converter 100 USD --to EUR --date 2026-11-02 --date-window 30
offline-currency-converter currencies

The equivalent module command is python -m offline_currency_converter followed by the same arguments. Use --rates-path /path/to/snapshot.csv for an explicit CSV. Commands use the latest common observation when no date is supplied; with --date, supply --date-window if an exact match is not required. Amounts are printed without monetary rounding.

API compatibility

This package implements the common CurrencyConverter calling interface with offline fiat and crypto data. It is not a complete drop-in implementation: network sources, ZIP inputs, and linear interpolation are not supported. Rates for cross-currency conversion always come from the same observation date. date_window and get_rate() are additional capabilities.

The original Converter, module-level convert(), and module-level get_rate() remain available. They use transaction_date=, default to yesterday in Europe/Amsterdam, interpret explicit None as today, and default to a +/-10-day window. They always use Decimal amounts and rates:

from offline_currency_converter import get_rate, convert

quote = get_rate("USD", "EUR", transaction_date="2026-11-02", date_window=30)
amount = convert("100", "USD", "EUR", transaction_date="2026-11-02", date_window=30)

Development and data maintenance

See Data generation and package maintenance for source configuration, daily scheduling, CSV/Excel formats, caching, wheel builds, and optional PyPI publication.

python -m pip install -r requirements.txt -r requirements-release.txt
python -m unittest discover -v
python build_wheel.py

build_wheel.py packages the newest existing snapshot without downloading data. python rates.py performs the network-enabled data update separately.

Metadata

Release files for OfflineCurrencyConverter 2026.11.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for OfflineCurrencyConverter 2026.11.9
File Size Uploaded Provenance Actions
offlinecurrencyconverter-2026.11.9.tar.gz 1.2 MB With provenance Details for offlinecurrencyconverter-2026.11.9.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for OfflineCurrencyConverter 2026.11.9
File Interpreter ABI Platform Actions
offlinecurrencyconverter-2026.11.9-py3-none-any.whl Python 3 none any Details for offlinecurrencyconverter-2026.11.9-py3-none-any.whl

Total release size: 2.5 MB

Release files / offlinecurrencyconverter-2026.11.9.tar.gz

Download URL offlinecurrencyconverter-2026.11.9.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
c92ee7d8f61e76af397d1bf191f9f204e641fda4bb40f7d8e4a5063437594435
BLAKE2b-256 checksum
How to use checksums
6e0f9b132008ad96bd3d89d23e0b63528743664ff412204e25b01aa53b4fcd42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Release files / offlinecurrencyconverter-2026.11.9-py3-none-any.whl

Download URL offlinecurrencyconverter-2026.11.9-py3-none-any.whl
Size 1.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
f163dbf7e21e034ae0107c6da785b7a876e0ef21147b6a256d833313432ea5f2
BLAKE2b-256 checksum
How to use checksums
9a80681df7ed65fba6dcb3faeafd76d4998976a7f65893432ec7a6c33d82526f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Security for OfflineCurrencyConverter 2026.11.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for offlinecurrencyconverter-2026.11.9.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page