Skip to content

Exchange Rates

The extension provides table functions to fetch exchange rates from 10 different sources - 7 free central bank APIs and 3 paid commercial APIs.

-- Load extension
INSTALL monetary FROM community;
LOAD monetary;
-- Fetch ECB rates (free, no API key needed)
SELECT currency_from, currency_to, rate, valid_from
FROM ecb_exchange_rates()
LIMIT 5;

For production use, store rates locally rather than fetching on every query:

-- Create a persistent rates table
CREATE TABLE exchange_rates AS
SELECT * FROM ecb_exchange_rates();
-- Check what we have
SELECT COUNT(*) as total_rates,
MIN(valid_from) as oldest,
MAX(valid_from) as newest
FROM exchange_rates;
-- Replace with fresh rates
CREATE OR REPLACE TABLE exchange_rates AS
SELECT * FROM ecb_exchange_rates();
-- Or append historical data
INSERT INTO exchange_rates
SELECT * FROM ecb_exchange_rates()
WHERE valid_from > (SELECT MAX(valid_from) FROM exchange_rates);

Combine multiple sources for better coverage:

CREATE TABLE exchange_rates AS
-- ECB for EUR-based rates
SELECT * FROM ecb_exchange_rates()
UNION ALL
-- Bank of Canada for CAD rates
SELECT * FROM boc_exchange_rates()
UNION ALL
-- RBA for AUD rates
SELECT * FROM rba_exchange_rates();

All exchange rate functions return the same schema:

ColumnTypeDescription
currency_fromENUMSource currency (ISO 4217)
currency_toENUMTarget currency (ISO 4217)
rateDECIMAL(20,10)Exchange rate
valid_fromTIMESTAMPTZRate publication timestamp
valid_toTIMESTAMPTZRate expiry (NULL if current)
sourceENUMData source identifier
source_idVARCHARSource-specific identifier
fetched_atTIMESTAMPTZWhen data was fetched

The European Central Bank publishes daily reference rates for 30+ currencies.

SELECT currency_from, currency_to, rate, valid_from
FROM ecb_exchange_rates()
WHERE currency_to IN ('USD', 'GBP', 'JPY', 'CHF');
  • Base: EUR
  • Update: Daily ~16:00 CET (weekdays)
  • Currencies: USD, GBP, JPY, CHF, SEK, NOK, DKK, PLN, CZK, HUF, RON, BGN, TRY, AUD, CAD, CNY, HKD, IDR, ILS, INR, KRW, MXN, MYR, NZD, PHP, SGD, THB, ZAR, BRL
SELECT currency_to, rate, valid_from
FROM boc_exchange_rates()
ORDER BY valid_from DESC;
  • Base: CAD
  • Update: Daily ~16:30 ET
SELECT * FROM rba_exchange_rates()
WHERE currency_to = 'USD';
  • Base: AUD
  • Update: Daily 4:00 PM AEST
  • License: CC BY 4.0 (attribution required)
SELECT * FROM norges_bank_exchange_rates();
  • Base: NOK
  • Update: Daily ~16:00 CET
SELECT * FROM cnb_exchange_rates();
  • Base: CZK
  • Update: Daily ~14:30 CET
SELECT * FROM snb_exchange_rates();
  • Base: CHF
  • Update: Daily 11:00 Zurich
  • Currencies: EUR, USD, GBP, JPY (limited set)

768 years of gold price history!

-- Get recent gold prices
SELECT valid_from, rate as usd_per_oz, data_source
FROM freegold_exchange_rates()
WHERE data_source = 'yahoo_finance'
ORDER BY valid_from DESC
LIMIT 10;

Filter by data source for different timeframes:

-- Daily Yahoo Finance (2025+)
SELECT * FROM freegold_exchange_rates()
WHERE data_source = 'yahoo_finance';
-- Monthly World Bank (1960-2024)
SELECT * FROM freegold_exchange_rates()
WHERE data_source = 'worldbank';
-- Annual historical (1257-1959)
SELECT * FROM freegold_exchange_rates()
WHERE data_source = 'historical';

Configure API keys using DuckDB secrets:

-- Option 1: Direct secret
CREATE SECRET (TYPE monetary, SOURCE <source>, SECRET 'your-api-key');
-- Option 2: From environment variable
CREATE SECRET (TYPE monetary, PROVIDER env, SOURCE <source>);

Real-time forex and crypto rates.

-- Set API key (get free key at twelvedata.com)
CREATE SECRET (TYPE monetary, SOURCE twelvedata, SECRET 'your-key');
-- Or from TWELVEDATA_API_KEY env var
CREATE SECRET (TYPE monetary, PROVIDER env, SOURCE twelvedata);
-- Fetch rates
SELECT * FROM twelvedata_exchange_rates();
  • Base: USD
  • Update: Real-time
  • Free tier: 800 API calls/day
  • Includes: Forex, crypto (BTC, ETH)
CREATE SECRET (TYPE monetary, SOURCE openexchangerates, SECRET 'your-app-id');
SELECT * FROM openexchangerates_exchange_rates();
  • Base: USD (free tier), configurable (paid)
  • Update: Hourly
  • Free tier: 1,000 requests/month

Real-time precious metal prices.

CREATE SECRET (TYPE monetary, SOURCE goldapi, SECRET 'your-token');
SELECT * FROM goldapi_exchange_rates();
  • Returns: XAU/USD, XAG/USD
  • Update: Real-time
WITH all_rates AS (
SELECT 'ECB' as provider, * FROM ecb_exchange_rates()
UNION ALL
SELECT 'BOC' as provider, * FROM boc_exchange_rates()
)
SELECT provider, currency_from, currency_to, rate, valid_from
FROM all_rates
WHERE currency_to = 'USD'
ORDER BY valid_from DESC
LIMIT 5;
-- Store historical rates
CREATE TABLE rate_history AS
SELECT *, current_timestamp as snapshot_time
FROM ecb_exchange_rates();
-- Later, append new snapshot
INSERT INTO rate_history
SELECT *, current_timestamp as snapshot_time
FROM ecb_exchange_rates();
-- Compare EUR/USD over time
SELECT snapshot_time, rate
FROM rate_history
WHERE currency_from = 'EUR' AND currency_to = 'USD'
ORDER BY snapshot_time;
COPY (SELECT * FROM ecb_exchange_rates())
TO 'ecb_rates.parquet' (FORMAT PARQUET);
FunctionProviderAPI KeyBaseUpdate
ecb_exchange_rates()ECBNoEURDaily
boc_exchange_rates()Bank of CanadaNoCADDaily
rba_exchange_rates()RBANoAUDDaily
norges_bank_exchange_rates()Norges BankNoNOKDaily
cnb_exchange_rates()CNBNoCZKDaily
snb_exchange_rates()SNBNoCHFDaily
freegold_exchange_rates()FreeGoldAPINoUSDDaily
twelvedata_exchange_rates()Twelve DataYesUSDReal-time
openexchangerates_exchange_rates()OXRYesUSDHourly
goldapi_exchange_rates()GoldAPIYesUSDReal-time