Download engine/quantities.py from s-ttp/crucible: direct link, hf CLI and curl.
- Browser
- Download file 7.08 kB
-
https://huggingface.co/spaces/s-ttp/crucible/resolve/main/engine/quantities.py
- Command line
-
hf download hf://spaces/s-ttp/crucible/engine/quantities.py
-
curl -L -o quantities.py https://huggingface.co/spaces/s-ttp/crucible/resolve/main/engine/quantities.py
7.08 kB
| """Typed units and quantity types: what a number IS, not only how large it is. | |
| A rate stored as a decimal (0.0335) can be a margin LEVEL of 3.35%, a margin CHANGE of 335 basis points or a | |
| growth rate of 3.35%. The decimal is the same, the quantity is not. Every rate-like figure therefore carries: | |
| * ``unit`` — the unit it was stated in: PERCENT, PERCENTAGE_POINTS, BASIS_POINTS, DECIMAL_FRACTION, MULTIPLE, | |
| COUNT, USD, USD_MILLION, USD_BILLION, USD_PER_SHARE; | |
| * ``quantity_type`` — what it measures: LEVEL, CHANGE, GROWTH_RATE, SPREAD, MARGIN_LEVEL, MARGIN_CHANGE, YIELD, | |
| PROBABILITY. | |
| Canonical values: rates, changes and spreads as decimals (335 bps → 0.0335, 3.35 pp → 0.0335, 3.35% → 0.0335); | |
| money in USD. The canonical number may coincide; the unit and quantity type never collapse, and formatting is | |
| driven by them, never inferred from the size of the stored number. | |
| """ | |
| from __future__ import annotations | |
| # ── units ───────────────────────────────────────────────────────────────────────────── | |
| DECIMAL_FRACTION = "DECIMAL_FRACTION" | |
| PERCENT = "PERCENT" | |
| PERCENTAGE_POINTS = "PERCENTAGE_POINTS" | |
| BASIS_POINTS = "BASIS_POINTS" | |
| MULTIPLE = "MULTIPLE" | |
| COUNT = "COUNT" | |
| USD = "USD" | |
| USD_MILLION = "USD_MILLION" | |
| USD_BILLION = "USD_BILLION" | |
| USD_PER_SHARE = "USD_PER_SHARE" | |
| UNITS = (DECIMAL_FRACTION, PERCENT, PERCENTAGE_POINTS, BASIS_POINTS, MULTIPLE, COUNT, USD, USD_MILLION, USD_BILLION, | |
| USD_PER_SHARE) | |
| RATE_UNITS = (DECIMAL_FRACTION, PERCENT, PERCENTAGE_POINTS, BASIS_POINTS) | |
| MONEY_UNITS = (USD, USD_MILLION, USD_BILLION, USD_PER_SHARE) | |
| # stated value × factor = canonical value (decimal for rates, USD for money) | |
| TO_CANONICAL = {DECIMAL_FRACTION: 1.0, PERCENT: 0.01, PERCENTAGE_POINTS: 0.01, BASIS_POINTS: 0.0001, MULTIPLE: 1.0, | |
| COUNT: 1.0, USD: 1.0, USD_MILLION: 1e6, USD_BILLION: 1e9, USD_PER_SHARE: 1.0} | |
| # ── quantity types ──────────────────────────────────────────────────────────────────── | |
| LEVEL = "LEVEL" | |
| CHANGE = "CHANGE" | |
| GROWTH_RATE = "GROWTH_RATE" | |
| SPREAD = "SPREAD" | |
| MARGIN_LEVEL = "MARGIN_LEVEL" | |
| MARGIN_CHANGE = "MARGIN_CHANGE" | |
| YIELD = "YIELD" | |
| PROBABILITY = "PROBABILITY" | |
| QUANTITY_TYPES = (LEVEL, CHANGE, GROWTH_RATE, SPREAD, MARGIN_LEVEL, MARGIN_CHANGE, YIELD, PROBABILITY) | |
| CHANGE_TYPES = (CHANGE, MARGIN_CHANGE, SPREAD) | |
| # units a quantity type may be stated in | |
| ALLOWED_UNITS = { | |
| LEVEL: MONEY_UNITS + (COUNT, MULTIPLE), | |
| GROWTH_RATE: (PERCENT, DECIMAL_FRACTION), | |
| MARGIN_LEVEL: (PERCENT, DECIMAL_FRACTION), | |
| MARGIN_CHANGE: (BASIS_POINTS, PERCENTAGE_POINTS), | |
| CHANGE: (BASIS_POINTS, PERCENTAGE_POINTS) + MONEY_UNITS, | |
| SPREAD: (BASIS_POINTS, PERCENTAGE_POINTS), | |
| YIELD: (PERCENT, DECIMAL_FRACTION), | |
| PROBABILITY: (PERCENT, DECIMAL_FRACTION), | |
| } | |
| # economic concepts for guidance and claims: a change or a growth rate is never stored under a level concept | |
| CONCEPT_QUANTITY = { | |
| "REVENUE": LEVEL, "REVENUE_GROWTH": GROWTH_RATE, "ORGANIC_REVENUE_GROWTH": GROWTH_RATE, | |
| "OPERATING_MARGIN": MARGIN_LEVEL, "OPERATING_MARGIN_CHANGE": MARGIN_CHANGE, | |
| "NET_MARGIN": MARGIN_LEVEL, "GROSS_MARGIN": MARGIN_LEVEL, "GROSS_MARGIN_CHANGE": MARGIN_CHANGE, | |
| "EPS": LEVEL, "EPS_GROWTH": GROWTH_RATE, "OPERATING_INCOME": LEVEL, "OPERATING_EXPENSES": LEVEL, | |
| "INTEREST_EXPENSE": LEVEL, "AMORTIZATION": LEVEL, "TAX_RATE": MARGIN_LEVEL, "FREE_CASH_FLOW": LEVEL, | |
| "CAPEX": LEVEL, "SHARE_REPURCHASE": LEVEL, "DIVIDEND": LEVEL, "NET_INTEREST_INCOME": LEVEL, | |
| "NET_INTEREST_MARGIN": MARGIN_LEVEL, "OTHER": None, | |
| } | |
| class QuantityError(ValueError): | |
| """A unit or quantity type that does not describe the figure.""" | |
| def to_canonical(value, unit): | |
| if value is None: | |
| return None | |
| if unit not in TO_CANONICAL: | |
| raise QuantityError(f"unknown unit {unit!r}") | |
| return float(value) * TO_CANONICAL[unit] | |
| def check(unit, quantity_type): | |
| """(ok, reason): is this unit a valid way to state this quantity type?""" | |
| if unit not in UNITS: | |
| return False, f"unknown unit {unit!r}" | |
| if quantity_type not in QUANTITY_TYPES: | |
| return False, f"unknown quantity type {quantity_type!r}" | |
| if unit not in ALLOWED_UNITS[quantity_type]: | |
| return False, f"{quantity_type} cannot be stated in {unit}" | |
| return True, "" | |
| def _num(x, dec): | |
| s = f"{x:,.{dec}f}" | |
| return s.rstrip("0").rstrip(".") if dec and "." in s else s | |
| def format_value(value, unit, quantity_type=None, *, signed=False): | |
| """One canonical value, formatted from its unit and quantity type (never from its magnitude).""" | |
| if value is None: | |
| return None | |
| v = float(value) | |
| sg = "+" if (signed and v > 0) else "" | |
| if unit == BASIS_POINTS: | |
| return f"{sg}{_num(v * 10000.0, 0)} bps" | |
| if unit == PERCENTAGE_POINTS: | |
| return f"{sg}{_num(v * 100.0, 2)} percentage points" | |
| if unit in (PERCENT, DECIMAL_FRACTION): | |
| return f"{sg}{v * 100.0:,.1f}%" | |
| if unit == MULTIPLE: | |
| return f"{v:,.1f}x" | |
| if unit == COUNT: | |
| return f"{int(round(v)):,}" | |
| if unit == USD_PER_SHARE: | |
| return f"{sg}${v:,.2f}" | |
| if unit in (USD, USD_MILLION, USD_BILLION): | |
| a = abs(v) | |
| s = "-" if v < 0 else sg | |
| if a >= 1e12: | |
| return f"{s}${a / 1e12:,.2f}T" | |
| if a >= 1e9: | |
| return f"{s}${a / 1e9:,.2f}B" | |
| if a >= 1e6: | |
| return f"{s}${a / 1e6:,.0f}M" if a >= 1e8 else f"{s}${a / 1e6:,.1f}M" | |
| return f"{s}${a:,.0f}" | |
| raise QuantityError(f"cannot format unit {unit!r}") | |
| def format_range(low, high, unit, quantity_type=None): | |
| lo, hi = format_value(low, unit, quantity_type), format_value(high, unit, quantity_type) | |
| if lo is None and hi is None: | |
| return None | |
| if lo is None or hi is None or lo == hi: | |
| return lo or hi | |
| if unit == BASIS_POINTS: | |
| return f"{_num(float(low) * 10000.0, 0)}–{_num(float(high) * 10000.0, 0)} bps" | |
| if unit == PERCENTAGE_POINTS: | |
| return f"{_num(float(low) * 100.0, 2)}–{_num(float(high) * 100.0, 2)} percentage points" | |
| return f"{lo}–{hi}" | |
| MAGNITUDE_BAND = (0.2, 5.0) | |
| def magnitude_ok(value, low, high=None): | |
| """(ok, reason): is a threshold measured against a source of the same unit of the same order of magnitude? | |
| A threshold of 3.6 bps against guidance of 335–360 bps is the same number in the wrong unit, not a judgement.""" | |
| refs = [abs(float(x)) for x in (low, high) if x is not None and float(x) != 0.0] | |
| if value is None or not refs: | |
| return True, "" | |
| v = abs(float(value)) | |
| ratio = min((v / r for r in refs), key=lambda q: abs(q - 1.0) if q else float("inf")) if v else 0.0 | |
| lo, hi = MAGNITUDE_BAND | |
| if lo <= ratio <= hi: | |
| return True, "" | |
| return False, f"threshold is {ratio:.3g}× its source value (outside {lo}–{hi}×): a unit slip, not a judgement" | |