Skip to content

Commit 58c945f

Browse files
authored
Merge pull request #855 from gaoflow/fix-currency-short-rollover
fix(formatting): roll format_currency_short up to the next unit at boundaries
2 parents 91d82fb + 058d944 commit 58c945f

3 files changed

Lines changed: 21 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- **`FormC.filer_information.ccc` no longer duplicates the CIK** — the Form C parser read the `filerCik` element into both `cik` and `ccc`; `ccc` now reads the actual `filerCcc` element (always redacted to `XXXXXXXX` in disseminated filings) and is `Optional`, returning `None` when absent.
1818
- **`FormC.filer_information.live_or_test` is no longer always `False`** — the parser looked for a `testOrLive` element under `filer`, but the schema places `liveTestFlag` under `filerInfo`; LIVE filings now correctly report `True` (older `testOrLive` documents remain supported).
1919
- **TTM Q4 derivation no longer produces wrong/negative values for discrete-quarter reporters** — when a concept is reported as discrete quarters with no cumulative 9-month YTD fact (common for BDCs and investment companies), `TTMCalculator` derives Q4 as `FY - (Q1+Q2+Q3)`. It previously selected the three input quarters by their `fiscal_period` label, but the SEC tags comparative facts in re-filings with the *filing's* fiscal period, so the same calendar quarter could appear labeled Q1, Q2 and Q3 across successive 10-Qs — producing a wrong, often negative Q4 (e.g. GAIN `InvestmentCompanyDividendDistribution`: `57.2M - 3×28.8M = -29.2M`). Quarters are now selected by distinct calendar period (dedup by `period_end`, latest periodic filing wins), and derivation is skipped when a discrete Q4 is already reported. This affects `quarterize()`, TTM calculations, and quarterly statement views. ([#848](https://github.com/dgunning/edgartools/issues/848))
20+
- **`format_currency_short` rolls up to the next unit at magnitude boundaries** — a value just under 1B (>= ~999.95M) rounded to `1,000.0` within the millions bucket and rendered as the nonsensical `$1,000.0M` instead of `$1.0B`; it now promotes to the billions unit when the millions mantissa rounds up to 1,000.
2021

2122
### Changed
2223

edgar/display/formatting.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,13 @@ def format_currency_short(value: Union[int, float, Decimal, None], currency: str
101101
if abs_val >= 1_000_000_000:
102102
return f"{sign}{currency}{abs_val / 1_000_000_000:,.1f}B"
103103
elif abs_val >= 1_000_000:
104-
return f"{sign}{currency}{abs_val / 1_000_000:,.1f}M"
104+
scaled = abs_val / 1_000_000
105+
# A value just under 1B (>= ~999.95M) rounds to "1,000.0M" at one
106+
# decimal place; promote it to "1.0B" rather than render the
107+
# nonsensical "1,000.0M".
108+
if round(scaled, 1) >= 1000:
109+
return f"{sign}{currency}{abs_val / 1_000_000_000:,.1f}B"
110+
return f"{sign}{currency}{scaled:,.1f}M"
105111
elif abs_val >= 1_000:
106112
return f"{sign}{currency}{abs_val:,.0f}"
107113
else:

tests/test_to_context.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ def test_boundary_million(self):
4646
def test_boundary_billion(self):
4747
assert format_currency_short(1_000_000_000) == "$1.0B"
4848

49+
def test_high_millions_not_promoted(self):
50+
# Comfortably under 1B: stays in millions.
51+
assert format_currency_short(999_000_000) == "$999.0M"
52+
53+
def test_just_under_billion_promotes_to_b(self):
54+
# Values that round up to "1,000.0M" must roll over to "1.0B"
55+
# instead of rendering the nonsensical "$1,000.0M".
56+
assert format_currency_short(999_950_000) == "$1.0B"
57+
assert format_currency_short(999_999_999) == "$1.0B"
58+
59+
def test_just_under_billion_promotes_negative(self):
60+
assert format_currency_short(-999_950_000) == "-$1.0B"
61+
4962

5063
class TestTenKToContext:
5164
"""Tests for TenK.to_context() using a known filing."""

0 commit comments

Comments
 (0)