Latest rates with requests
import os
import requests
API_KEY = os.environ["CURRENCYAPI_KEY"]
def latest_rates(base="USD", currencies=("EUR", "GBP", "JPY")):
res = requests.get(
"https://api.currencyapi.com/v3/latest",
params={"base_currency": base, "currencies": ",".join(currencies)},
headers={"apikey": API_KEY},
timeout=10,
)
res.raise_for_status()
return {code: item["value"] for code, item in res.json()["data"].items()}
print(latest_rates())
# {'EUR': 0.8828, 'GBP': 0.7556, 'JPY': 157.98}
Converting amounts correctly
from decimal import Decimal, ROUND_HALF_UP
def convert(amount: str, rate: float, decimals: int = 2) -> Decimal:
result = Decimal(amount) * Decimal(str(rate))
return result.quantize(Decimal(1).scaleb(-decimals), rounding=ROUND_HALF_UP)
rates = latest_rates("USD", ["EUR"])
print(convert("199.99", rates["EUR"])) # e.g. Decimal('176.56')
Use decimals=0 for currencies without minor units such as JPY or KRW; the currency pages list the decimals of every currency.
Historical rates
def rate_on(date: str, base: str, quote: str) -> float:
res = requests.get(
"https://api.currencyapi.com/v3/historical",
params={"date": date, "base_currency": base, "currencies": quote},
headers={"apikey": API_KEY},
timeout=10,
)
res.raise_for_status()
return res.json()["data"][quote]["value"]
print(rate_on("2024-03-15", "USD", "EUR"))
Cache the rates
Rates do not change between two requests a second apart. Cache the latest rates for a few minutes and historical rates forever, for example with functools.lru_cache for historical dates:
from functools import lru_cache
@lru_cache(maxsize=4096)
def cached_rate_on(date, base, quote):
return rate_on(date, base, quote)
pandas: convert a column of transactions
import pandas as pd
df = pd.DataFrame({"date": ["2024-03-15", "2024-06-03"], "amount_usd": [120.0, 89.5]})
df["rate_eur"] = [cached_rate_on(d, "USD", "EUR") for d in df["date"]]
df["amount_eur"] = (df["amount_usd"] * df["rate_eur"]).round(2)
Get a free API key with 300 requests per month on the pricing page.