From 810b4cc48dc4d3343a4e3e96defbbe26d76fb535 Mon Sep 17 00:00:00 2001 From: Yijia-Xiao Date: Thu, 1 Oct 2026 01:49:03 +0000 Subject: [PATCH] fix(yahoo): print each fundamentals money figure with the currency it is in (#1456) - price levels carry the quote currency (GBp for London), market cap and per-share figures its main unit (GBP), and income figures the reporting currency (TWD for TSMC's ADR) --- tests/test_fundamentals_units.py | 40 +++++++++++++++++ .../dataflows/vendors/yahoo/fundamentals.py | 43 +++++++++++++------ 2 files changed, 70 insertions(+), 13 deletions(-) diff --git a/tests/test_fundamentals_units.py b/tests/test_fundamentals_units.py index f960ad6c6..febebe4bd 100644 --- a/tests/test_fundamentals_units.py +++ b/tests/test_fundamentals_units.py @@ -37,3 +37,43 @@ def test_an_absent_percent_field_is_left_out(): out = _fundamentals({"longName": "JPMorgan Chase & Co.", "profitMargins": 0.35}) assert "Dividend Yield" not in out and "Debt to Equity" not in out + + +@pytest.mark.unit +def test_each_money_figure_carries_the_currency_it_is_in(): + """Yahoo quotes London in pence but states EPS and market cap in pounds, and + the income figures in the reporting currency (#1456).""" + out = _fundamentals({"longName": "Shell plc", "currency": "GBp", "financialCurrency": "USD", + "marketCap": 203440193536, "trailingEps": 3.42, "bookValue": 29.1, + "fiftyTwoWeekHigh": 3800.0, "fiftyDayAverage": 3500.5, + "totalRevenue": 296600993792, "netIncomeToCommon": 25970999296}) + + assert "Market Cap: 203440193536 GBP" in out + assert "EPS (TTM): 3.42 GBP" in out and "Book Value: 29.1 GBP" in out + assert "52 Week High: 3800.0 GBp" in out and "50 Day Average: 3500.5 GBp" in out + assert "Revenue (TTM): 296600993792 USD" in out and "Net Income: 25970999296 USD" in out + + +@pytest.mark.unit +def test_an_adr_quotes_in_dollars_and_reports_in_its_home_currency(): + out = _fundamentals({"longName": "TSMC", "currency": "USD", "financialCurrency": "TWD", + "marketCap": 2365000000000, "trailingEps": 13.21, "totalRevenue": 4440492343296}) + + assert "Market Cap: 2365000000000 USD" in out and "EPS (TTM): 13.21 USD" in out + assert "Revenue (TTM): 4440492343296 TWD" in out + + +@pytest.mark.unit +def test_a_figure_with_no_stated_currency_is_printed_bare(): + out = _fundamentals({"longName": "X", "marketCap": 1000, "totalRevenue": 50}) + + assert "Market Cap: 1000\n" in out + "\n" and "Revenue (TTM): 50" in out and "None" not in out + + +@pytest.mark.unit +def test_income_figures_without_a_stated_reporting_currency_are_printed_bare(): + """The quote currency is not evidence of the reporting currency (an ADR quotes + in USD and reports in TWD), so an unknown one is not guessed.""" + out = _fundamentals({"longName": "X", "currency": "USD", "marketCap": 1000, "totalRevenue": 50}) + + assert "Market Cap: 1000 USD" in out and "Revenue (TTM): 50\n" in out + "\n" diff --git a/tradingagents/dataflows/vendors/yahoo/fundamentals.py b/tradingagents/dataflows/vendors/yahoo/fundamentals.py index 37000728b..00698cda0 100644 --- a/tradingagents/dataflows/vendors/yahoo/fundamentals.py +++ b/tradingagents/dataflows/vendors/yahoo/fundamentals.py @@ -16,6 +16,9 @@ from tradingagents.dataflows.vendors.yahoo.common import ( yf_retry, ) +# Quote currencies Yahoo gives in a minor unit, and the main unit of each. +_MAIN_UNIT = {"GBp": "GBP", "GBX": "GBP", "ZAc": "ZAR", "ILA": "ILS"} + def get_fundamentals( ticker: Annotated[str, "ticker symbol of the company"], @@ -43,27 +46,41 @@ def get_fundamentals( # 78.4 is 78.4%, a ratio of 0.78) but the margins and returns as fractions, # so each carries its unit. dividend_yield, debt_to_equity = info.get("dividendYield"), info.get("debtToEquity") + # Money figures come in three currencies (#1456): price levels in the quote + # currency, which can be a minor unit (London in pence, GBp); market cap and + # per-share figures in that currency's main unit (GBP), as Yahoo's own P/E + # and P/B are computed against them; income figures in the currency the + # company reports in (an ADR quotes in USD, reports in TWD), or bare when + # Yahoo does not say which. + quote = info.get("currency") + main = _MAIN_UNIT.get(quote, quote) + reported = info.get("financialCurrency") + + def money(key, currency): + value = info.get(key) + return None if value is None else f"{value} {currency}" if currency else value + fields = [ ("Name", info.get("longName")), ("Sector", info.get("sector")), ("Industry", info.get("industry")), - ("Market Cap", info.get("marketCap")), + ("Market Cap", money("marketCap", main)), ("PE Ratio (TTM)", info.get("trailingPE")), ("Forward PE", info.get("forwardPE")), ("PEG Ratio", info.get("pegRatio")), ("Price to Book", info.get("priceToBook")), - ("EPS (TTM)", info.get("trailingEps")), - ("Forward EPS", info.get("forwardEps")), + ("EPS (TTM)", money("trailingEps", main)), + ("Forward EPS", money("forwardEps", main)), ("Dividend Yield", None if dividend_yield is None else f"{dividend_yield}%"), ("Beta", info.get("beta")), - ("52 Week High", info.get("fiftyTwoWeekHigh")), - ("52 Week Low", info.get("fiftyTwoWeekLow")), - ("50 Day Average", info.get("fiftyDayAverage")), - ("200 Day Average", info.get("twoHundredDayAverage")), - ("Revenue (TTM)", info.get("totalRevenue")), - ("Gross Profit", info.get("grossProfits")), - ("EBITDA", info.get("ebitda")), - ("Net Income", info.get("netIncomeToCommon")), + ("52 Week High", money("fiftyTwoWeekHigh", quote)), + ("52 Week Low", money("fiftyTwoWeekLow", quote)), + ("50 Day Average", money("fiftyDayAverage", quote)), + ("200 Day Average", money("twoHundredDayAverage", quote)), + ("Revenue (TTM)", money("totalRevenue", reported)), + ("Gross Profit", money("grossProfits", reported)), + ("EBITDA", money("ebitda", reported)), + ("Net Income", money("netIncomeToCommon", reported)), ("Profit Margin", info.get("profitMargins")), ("Operating Margin", info.get("operatingMargins")), ("Return on Equity", info.get("returnOnEquity")), @@ -71,8 +88,8 @@ def get_fundamentals( ("Debt to Equity", None if debt_to_equity is None else f"{debt_to_equity}% ({debt_to_equity / 100:.2f}x)"), ("Current Ratio", info.get("currentRatio")), - ("Book Value", info.get("bookValue")), - ("Free Cash Flow", info.get("freeCashflow")), + ("Book Value", money("bookValue", main)), + ("Free Cash Flow", money("freeCashflow", reported)), ] lines = [f"{label}: {v}" for label, v in fields if v is not None]