A pure Clojure library for accessing European Central Bank (ECB) data, starting with historical currency conversion. Designed to grow into a broader ECB data client.
clojure-finance.ecbjure.sdmxtech.ml.dataset integration — wide and tidy/long format datasets (optional alias);; deps.edn
com.github.clojure-finance/ecbjure {:mvn/version "0.1.2"}
(require '[clojure-finance.ecbjure.fx :as fx])
(import '[java.time LocalDate])
;; Fetch latest data from ECB (default)
(def c (fx/make-converter))
;; Convert 100 USD to JPY using the latest available rate
(fx/convert c 100 "USD" "JPY")
;; => 15791.89
;; Convert on a specific date
(fx/convert c 100 "USD" "EUR" (LocalDate/of 2013 3 21))
;; => 77.46
;; Omit target currency — defaults to EUR
(fx/convert c 100 "USD")
;; => 90.91
;; Fetch from ECB URL (default)
(fx/make-converter)
;; From ECB URL (fetches latest)
(fx/make-converter fx/ecb-url)
;; From local file (ZIP or CSV)
(fx/make-converter "/path/to/eurofxref-hist.zip")
;; With options
(fx/make-converter fx/ecb-url {:fallback-on-wrong-date true
:cast-fn bigdec})
;; From a seq of CSV lines (useful for testing or custom data)
(fx/make-converter-from-lines lines opts)
Options:
| Key | Default | Description |
|---|---|---|
:cast-fn | double | Rate coercion function. Use bigdec for exact arithmetic. |
:fallback-on-wrong-date | false | Clamp to first/last available date when out of bounds. |
:ref-currency | "EUR" | Reference currency (triangulation pivot). |
;; amount from → EUR (default target)
(fx/convert c 100 "USD")
;; amount from → to, latest available date
(fx/convert c 100 "USD" "JPY")
;; amount from → to, specific date
(fx/convert c 100 "USD" "JPY" (LocalDate/of 2014 3 28))
;; EUR-referenced rate for a currency on a date
(fx/get-rate c "USD" (LocalDate/of 2014 3 28))
;; => 1.3759
;; Implied cross rate (not through EUR amounts, just the ratio)
(fx/cross-rate c "USD" "GBP" (LocalDate/of 2014 3 28))
;; => 0.5999...
;; Full sorted date→rate history for a currency
(fx/rate-history c "USD")
;; => {#object[LocalDate "1999-01-04"] 1.1789, ...}
The converter is a plain map — inspect it directly:
(:currencies c) ;; => #{"EUR" "USD" "JPY" "GBP" ...}
(:bounds c) ;; => {"USD" {:first-date #object[LocalDate "1999-01-04"]
;; :last-date #object[LocalDate "2026-03-06"]} ...}
(:ref-currency c) ;; => "EUR"
fx/ecb-url
;; => "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist.zip"
Requires the :dataset alias (techascent/tech.ml.dataset):
(require '[clojure-finance.ecbjure.dataset :as ds])
;; Wide format — one row per date, one column per currency
(ds/rates-wide c)
;; => ecb-rates-wide [6846 43]:
;; | :date | USD | JPY | ... |
;; |------------|-------:|-------:|
;; | 1999-01-04 | 1.1789 | 133.73 | ... |
;; | ... | ... | ... | ... |
;; Long/tidy format — one row per (date, currency) observation
(ds/rates-long c)
;; => ecb-rates-long [~280000 3]:
;; | :date | :currency | :rate |
;; |------------|-----------|--------:|
;; | 1999-01-04 | EUR | 1.0000 |
;; | 1999-01-04 | GBP | 0.7111 |
;; | 1999-01-04 | USD | 1.1789 |
;; | ... | ... | ... |
Start the REPL with both aliases: clj -M:nrepl:dataset
All errors are ex-info with a :type key:
:type | Cause |
|---|---|
:unknown-currency | Currency code not in the dataset |
:rate-not-found | No rate available for the requested date |
(try
(fx/convert c 100 "USD" "EUR" (LocalDate/of 2024 1 6)) ; Saturday — no ECB data
(catch clojure.lang.ExceptionInfo e
(ex-data e)))
;; => {:type :rate-not-found, :currency "USD", :date #object[LocalDate "2024-01-06"]}
Use :fallback-on-wrong-date true to clamp out-of-bounds dates to the nearest available boundary instead of throwing.
No interpolation. The ECB publishes rates on business days only. When a date has no rate (weekends, holidays), ecbjure throws rather than silently inventing a number. Interpolating financial data introduces look-ahead bias in backtesting. If you need gap-filling, do it explicitly in your own pipeline where the assumption is visible.
The converter is a map. No defrecord, no mutable state. make-converter returns a plain Clojure map; convert is a pure function. The converter is inspectable, serializable, and composable.
Minimal dependencies. Core library depends only on org.clojure/data.csv. No HTTP client needed — the ECB ZIP is fetched via java.net.URI/.openStream.
With the :cli alias:
clj -M:cli 100 USD --to EUR
# 100.000 USD = 90.909 EUR on 2026-03-06
clj -M:cli 100 USD --to JPY --date 2013-03-21
# 100.000 USD = 12051.282 JPY on 2013-03-21
clj -M:cli 100 USD -v
# 100.000 USD
# 41 available currencies:
# AUD BGN BRL CAD CHF CNY CZK DKK EUR GBP ...
Options: --to <currency>, --date <yyyy-MM-dd>, --source <url-or-path>.
clj-yfinance integration for live spot rates.Access broader ECB statistical data via clojure-finance.ecbjure.sdmx:
(require '[clojure-finance.ecbjure.sdmx :as sdmx])
;; EURIBOR 3-month, last 3 months
(sdmx/get-series sdmx/euribor-3m {:last-n 3})
;; => [{:time-period #object[LocalDate "2025-12-01"] :obs-value 2.0457 :currency "EUR" ...} ...]
;; Euro area HICP inflation since 2020
(sdmx/get-series sdmx/hicp-euro-area {:start-period "2020-01"})
;; Arbitrary ECB SDMX series key
(sdmx/get-series "EXR/D.USD.EUR.SP00.A"
{:start-period "2024-01-01" :end-period "2024-01-31"})
Predefined constants: exr-daily, exr-monthly, euribor-1w, euribor-1m, euribor-3m, euribor-6m, euribor-1y, euribor-overnight, estr-daily, hicp-euro-area.
Each observation is a map with :time-period (LocalDate), :obs-value (double), and all dimension columns from the ECB CSV response. No additional dependencies — uses data.csv and JDK HTTP.
Copyright © 2026 clojure-finance
Released under the Eclipse Public License 2.0.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |