Skip to content

edvinassvedas-dev/ecbfx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ecbfx

PyPI version Python License: MIT

A minimal command-line tool and Python library for fetching EUR foreign exchange rates directly from the ECB SDMX API.


Install

pip install ecbfx

For development (includes test dependencies):

git clone https://github.com/edvinassvedas-dev/ecbfx.git
cd ecbfx
pip install -e ".[dev]"
pytest

CLI usage

# Today's rate for USD (indirect: USD per 1 EUR — ECB native)
# Note: ECB publishes rates ~16:00 CET on trading days.
# If today's rate isn't available yet, use --latest instead.
ecbfx USD

# Specific date
ecbfx USD 2025-01-15

# Multiple currencies, specific date
ecbfx USD GBP CHF 2025-01-15

# Date range
ecbfx USD GBP --from 2025-01-01 --to 2025-03-31

# Direct convention: EUR per 1 foreign unit (inverted)
ecbfx USD 2025-01-15 --direct

# Most recent available rate (ignores today being a weekend/holiday)
ecbfx USD --latest

# Single value only — ideal for shell scripting
ecbfx USD --latest --quiet
RATE=$(ecbfx USD --quiet)

# Control decimal precision (default: 4)
ecbfx USD 2025-01-15 --decimal 6

# Strict mode — error instead of gap-filling on weekends/holidays
ecbfx USD 2025-01-15 --no-gap-fill

# CSV output (pipe-friendly)
ecbfx USD --from 2025-01-01 --to 2025-01-31 --csv
ecbfx USD --from 2025-01-01 --to 2025-01-31 --csv > rates.csv

# Read pairs from a file — one HTTP call per currency
ecbfx --pairs transactions.csv --direct --csv

# Read pairs from stdin
cat transactions.csv | ecbfx --pairs - --direct --csv

# Combine with date filter
ecbfx --pairs transactions.csv --from 2025-01-01 --to 2025-03-31 --csv

Convention

Flag Formula Example
(default) foreign units per 1 EUR 1 EUR = 1.0830 USD
--direct EUR per 1 foreign unit 1 USD = 0.9234 EUR

ECB publishes indirect natively. --direct inverts the rate. The convention column in CSV output (USD/EUR or EUR/USD) makes the direction explicit for downstream pipelines.

Flags reference

Flag Default Description
--direct off EUR per 1 foreign unit instead of ECB native
--latest off Most recent available rate, regardless of date
--quiet / -q off Print rate value(s) only — ideal for scripting
--decimal N 4 Decimal places in output rate
--no-gap-fill off Raise an error on weekends/holidays instead of substituting the nearest rate
--csv off CSV output instead of formatted table
--pairs FILE|- Read date,currency pairs from a file or stdin

Weekend and holiday gap-filling

ECB only publishes rates on trading days. By default, ecbfx automatically uses the most recent prior trading day's rate (Last Observation Carried Forward) when a requested date falls on a weekend or public holiday — including the first date in a range that starts on a holiday such as January 1st.

Use --no-gap-fill to disable this and receive an explicit error instead — useful in audit workflows where a substituted rate is not acceptable.


Exit codes

Code Meaning
0 Success
1 Runtime error (ECB API failure, network issue, no data returned)
2 Usage error (invalid arguments, bad date format, missing required flag)

Useful for scripting:

ecbfx USD --quiet || echo "fetch failed, exit $?"

Python API

from datetime import date
from ecbfx import fetch_rates, fetch_rates_for_pairs, fetch_latest

# Indirect (default) — foreign units per 1 EUR, contiguous range
rows = fetch_rates(["USD", "GBP"], date(2025, 1, 1), date(2025, 1, 31))

# Direct — EUR per 1 foreign unit
rows = fetch_rates(["USD"], date(2025, 1, 15), date(2025, 1, 15), direct=True)

# Most recent available rate
rows = fetch_latest(["USD", "CHF"])

# Sparse transaction dates — one HTTP call per currency regardless of pair count
pairs = [
    (date(2025, 1, 15), "USD"),
    (date(2025, 1, 20), "GBP"),
    (date(2025, 2,  3), "USD"),
    (date(2025, 2,  3), "CHF"),
]
rows = fetch_rates_for_pairs(pairs, direct=True)

# Custom decimal precision
rows = fetch_rates(["USD"], date(2025, 1, 15), date(2025, 1, 15), decimals=6)

# Strict mode — raises ECBError on weekends/holidays
rows = fetch_rates(["USD"], date(2025, 1, 13), date(2025, 1, 13), gap_fill=False)
rows = fetch_rates_for_pairs([(date(2025, 1, 13), "USD")], gap_fill=False)

for r in rows:
    print(r["date"], r["currency"], r["convention"], r["rate"])

Each row is a dict: {date, currency, rate, convention}.

Input validation

from ecbfx import validate_currency, ECBError

# Normalises and validates a currency code — raises ECBError if invalid
print(validate_currency("usd"))   # → "USD"
print(validate_currency("  GBP ")) # → "GBP"

try:
    validate_currency("US$")
except ECBError as e:
    print(e)  # Invalid currency code 'US$'. Expected 2–4 ASCII letters.

Use ECBError in try/except blocks when calling any ecbfx function to handle API failures, network errors, or invalid inputs cleanly.

fetch_rates vs fetch_rates_for_pairs

fetch_rates fetch_rates_for_pairs
Input currency list + date range list of (date, currency) tuples
Returns every calendar day in range exactly the requested dates
Best for daily pipelines, backfill transaction enrichment, broker CSVs
HTTP calls one per currency one per currency (full span, regardless of gaps)

Note: fetch_rates_for_pairs always fetches the full date span from the earliest to the latest date per currency in a single HTTP call. For very sparse data (e.g. two transactions 10 years apart), this fetches the entire intervening range. A warning is logged when the span exceeds one year.


License

MIT

About

Fetch EUR exchange rates from the ECB -- CLI tool and Python library

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages