Add ISO 4217 data.
This commit is contained in:
parent
4a4ce94bc6
commit
45a1e1b0df
3 changed files with 3216 additions and 0 deletions
131
src/pricehist/isocurrencies.py
Normal file
131
src/pricehist/isocurrencies.py
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
""" ISO 4217 Currency data
|
||||||
|
|
||||||
|
Provides `ISO 4217 <https://www.iso.org/iso-4217-currency-codes.html>`_
|
||||||
|
currency data in a ready-to-use format, indexed by currency code. Historical
|
||||||
|
currencies are included and countries with no universal currency are ignored.
|
||||||
|
|
||||||
|
The data is read from vendored copies of the XML files published by the
|
||||||
|
maintainers of the standard:
|
||||||
|
|
||||||
|
* :file:`list_one.xml` (current currencies & funds)
|
||||||
|
* :file:`list_three.xml` (historical currencies & funds)
|
||||||
|
|
||||||
|
Classes:
|
||||||
|
|
||||||
|
ISOCurrency
|
||||||
|
|
||||||
|
Functions:
|
||||||
|
|
||||||
|
current_data_date() -> str
|
||||||
|
historical_data_date() -> str
|
||||||
|
bycode() -> dict[str, ISOCurrency]
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from importlib.resources import read_binary
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=False)
|
||||||
|
class ISOCurrency:
|
||||||
|
code: str = None
|
||||||
|
number: int = None
|
||||||
|
minor_units: int = None
|
||||||
|
name: str = None
|
||||||
|
is_fund: bool = False
|
||||||
|
countries: list[str] = field(default_factory=list)
|
||||||
|
historical: bool = False
|
||||||
|
withdrawal_date: str = None
|
||||||
|
|
||||||
|
|
||||||
|
def current_data_date():
|
||||||
|
if not _current_data_date:
|
||||||
|
_readall()
|
||||||
|
return _current_data_date
|
||||||
|
|
||||||
|
|
||||||
|
def historical_data_date():
|
||||||
|
if not _historical_data_date:
|
||||||
|
_readall()
|
||||||
|
return _historical_data_date
|
||||||
|
|
||||||
|
|
||||||
|
def bycode():
|
||||||
|
if not _bycode:
|
||||||
|
_readall()
|
||||||
|
return _bycode
|
||||||
|
|
||||||
|
|
||||||
|
_current_data_date = None
|
||||||
|
_historical_data_date = None
|
||||||
|
_bycode = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _readall():
|
||||||
|
one = etree.fromstring(read_binary("pricehist.resources", "list_one.xml"))
|
||||||
|
three = etree.fromstring(read_binary("pricehist.resources", "list_three.xml"))
|
||||||
|
|
||||||
|
_current_data_date = one.cssselect("ISO_4217")[0].attrib["Pblshd"]
|
||||||
|
_historical_data_date = three.cssselect("ISO_4217")[0].attrib["Pblshd"]
|
||||||
|
(_current_data_date, _historical_data_date) # No-op
|
||||||
|
|
||||||
|
for entry in three.cssselect("HstrcCcyNtry") + one.cssselect("CcyNtry"):
|
||||||
|
if currency := _parse(entry):
|
||||||
|
if existing := _bycode.get(currency.code):
|
||||||
|
existing.code = currency.code
|
||||||
|
existing.number = currency.number
|
||||||
|
existing.minor_units = currency.minor_units
|
||||||
|
existing.name = currency.name
|
||||||
|
existing.is_fund = currency.is_fund
|
||||||
|
existing.countries += currency.countries
|
||||||
|
existing.historical = currency.historical
|
||||||
|
existing.withdrawal_date = currency.withdrawal_date
|
||||||
|
else:
|
||||||
|
_bycode[currency.code] = currency
|
||||||
|
|
||||||
|
|
||||||
|
def _parse(entry):
|
||||||
|
try:
|
||||||
|
code = entry.cssselect("Ccy")[0].text
|
||||||
|
except IndexError:
|
||||||
|
return None # Ignore countries without a universal currency
|
||||||
|
|
||||||
|
try:
|
||||||
|
number = int(entry.cssselect("CcyNbr")[0].text)
|
||||||
|
except (IndexError, ValueError):
|
||||||
|
number = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
minor_units = int(entry.cssselect("CcyMnrUnts")[0].text)
|
||||||
|
except (IndexError, ValueError):
|
||||||
|
minor_units = None
|
||||||
|
|
||||||
|
name_tags = entry.cssselect("CcyNm")
|
||||||
|
if name_tags:
|
||||||
|
name = name_tags[0].text
|
||||||
|
is_fund = name_tags[0].attrib.get("IsFund", "").upper() in ["TRUE", "WAHR"]
|
||||||
|
else:
|
||||||
|
name = None
|
||||||
|
is_fund = None
|
||||||
|
|
||||||
|
countries = [t.text for t in entry.cssselect("CtryNm")]
|
||||||
|
|
||||||
|
try:
|
||||||
|
withdrawal_date = entry.cssselect("WthdrwlDt")[0].text
|
||||||
|
historical = True
|
||||||
|
except IndexError:
|
||||||
|
withdrawal_date = None
|
||||||
|
historical = False
|
||||||
|
|
||||||
|
return ISOCurrency(
|
||||||
|
code=code,
|
||||||
|
number=number,
|
||||||
|
minor_units=minor_units,
|
||||||
|
name=name,
|
||||||
|
is_fund=is_fund,
|
||||||
|
countries=countries,
|
||||||
|
historical=historical,
|
||||||
|
withdrawal_date=withdrawal_date,
|
||||||
|
)
|
1949
src/pricehist/resources/list_one.xml
Normal file
1949
src/pricehist/resources/list_one.xml
Normal file
File diff suppressed because it is too large
Load diff
1136
src/pricehist/resources/list_three.xml
Normal file
1136
src/pricehist/resources/list_three.xml
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue