diff --git a/edgar/xbrl/currency.py b/edgar/xbrl/currency.py index b8607a01..5a758285 100644 --- a/edgar/xbrl/currency.py +++ b/edgar/xbrl/currency.py @@ -24,6 +24,7 @@ usd_revenue = converter.to_usd(dkk_revenue, 2024, rate_type='average') """ +import re from collections import Counter from dataclasses import dataclass, field from datetime import date, datetime @@ -47,7 +48,26 @@ def _extract_year(value) -> Optional[int]: return value.year return None -__all__ = ['CurrencyConverter', 'ExchangeRate'] +__all__ = ['CurrencyConverter', 'ExchangeRate', 'normalize_currency_unit'] + + +def normalize_currency_unit(raw: Optional[str]) -> Optional[str]: + """Extract an ISO 4217 code from common XBRL currency unit identifiers.""" + if not raw: + return raw + + if re.fullmatch(r"[A-Z]{3}", raw): + return raw + + match = re.search(r"iso4217:([A-Z]{3})", raw, flags=re.IGNORECASE) + if match: + return match.group(1).upper() + + match = re.search(r"UNIT_STANDARD_([A-Z]{3})(?:_|$)", raw) + if match: + return match.group(1) + + return raw @dataclass diff --git a/edgar/xbrl/facts.py b/edgar/xbrl/facts.py index a344d81b..ae57627d 100644 --- a/edgar/xbrl/facts.py +++ b/edgar/xbrl/facts.py @@ -24,6 +24,7 @@ from edgar.richtools import repr_rich from edgar.xbrl.core import STANDARD_LABEL, parse_date +from edgar.xbrl.currency import normalize_currency_unit from edgar.xbrl.models import select_display_label @@ -1014,6 +1015,7 @@ def get_facts(self) -> List[Dict[str, Any]]: 'context_ref': fact.context_ref, 'value': fact.value, 'unit_ref': fact.unit_ref, + 'currency': normalize_currency_unit(fact.unit_ref), 'decimals': fact.decimals, 'numeric_value': fact.numeric_value } diff --git a/tests/xbrl/test_currency_unit_normalization.py b/tests/xbrl/test_currency_unit_normalization.py new file mode 100644 index 00000000..d7fcf0be --- /dev/null +++ b/tests/xbrl/test_currency_unit_normalization.py @@ -0,0 +1,21 @@ +from edgar.xbrl.currency import normalize_currency_unit + + +def test_normalize_currency_unit_returns_clean_iso_code(): + assert normalize_currency_unit("USD") == "USD" + + +def test_normalize_currency_unit_extracts_iso4217_measure(): + assert normalize_currency_unit("iso4217:USD") == "USD" + + +def test_normalize_currency_unit_extracts_standard_unit_identifier(): + raw = "UNIT_STANDARD_HKD_MNUSOXGRF0O9R60JINVDUQ" + + assert normalize_currency_unit(raw) == "HKD" + + +def test_normalize_currency_unit_preserves_unknown_format(): + raw = "shares" + + assert normalize_currency_unit(raw) == raw