docs: add API references, mapping corrections, and verification script
- Add yfinance.org and defeatbeta-api.org reference docs - Fix defeatbeta_mapping.org: deprecated yfinance property names (quarterly_financials→quarterly_income_stmt, financials→income_stmt), longName vs longBusinessSummary conceptual mismatch, cashflow note typo - Add Mapping Limitations section with live verification results (AAPL): DuckDB 1.4.3 incompatibility, format differences, coverage gaps - Add docs/test_mapping.py as runnable mapping verification script - Add offline.py, persistent_cache.py, download_data.py, warmup_cache.py for offline/cached defeatbeta usage - Add aapl_yfinance.py exploration script and quant.py scaffold - Add .envrc (uv layout) and update pyproject.toml + uv.lock Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
#+TITLE: defeatbeta-api Reference
|
||||
#+AUTHOR: Wong Ding Feng
|
||||
#+DATE: 2026-04-25
|
||||
|
||||
* How Data Retrieval Works
|
||||
|
||||
** NOT a full download
|
||||
|
||||
Uses *DuckDB + ~cache_httpfs~ extension* querying *remote Parquet files on HuggingFace*
|
||||
(~defeatbeta/yahoo-finance-data~). Every query runs SQL directly against remote files:
|
||||
|
||||
#+begin_src sql
|
||||
SELECT * FROM 'https://huggingface.co/.../stock_prices.parquet' WHERE symbol = 'AAPL'
|
||||
#+end_src
|
||||
|
||||
Parquet's columnar format + DuckDB *predicate pushdown* = only the row-groups matching
|
||||
your ticker are fetched over HTTP range requests. Not the full 3-4 GB file.
|
||||
|
||||
** On-disk cache
|
||||
|
||||
- Default 1 GB cache at ~~/.defeatbeta/cache/~
|
||||
- Stores fetched blocks so repeated queries are fast
|
||||
- On startup: checks ~spec.json~ on HuggingFace, clears stale cache if dataset was updated
|
||||
|
||||
* Getting All Available Tickers
|
||||
|
||||
#+begin_src python
|
||||
from defeatbeta_api.data.company_meta import CompanyMeta
|
||||
|
||||
meta = CompanyMeta()
|
||||
all_tickers = meta.get_all_tickers() # List[str]
|
||||
all_companies = meta.get_all_companies_info() # List[dict]: symbol, name, cik, currency
|
||||
#+end_src
|
||||
|
||||
Reads ~company_tickers.json~ from HuggingFace — a small JSON, not the big Parquet files.
|
||||
|
||||
* Single Ticker API — ~Ticker("AAPL")~
|
||||
|
||||
#+begin_src python
|
||||
from defeatbeta_api.data.ticker import Ticker
|
||||
t = Ticker("AAPL")
|
||||
#+end_src
|
||||
|
||||
** Company Info
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|----------------------------+-------------+---------------------------------------------------------|
|
||||
| ~info()~ | DataFrame | Profile: name, sector, industry, description, headcount |
|
||||
| ~officers()~ | DataFrame | Executive officers |
|
||||
| ~sec_filing()~ | DataFrame | SEC filings list |
|
||||
| ~news()~ | ~News~ object | Latest news articles |
|
||||
| ~earning_call_transcripts()~ | ~Transcripts~ | Earnings call transcripts |
|
||||
| ~calendar()~ | DataFrame | Upcoming earnings dates |
|
||||
|
||||
** Prices & Basic Finance
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|------------------------------------+-----------+------------------------------|
|
||||
| ~price()~ | DataFrame | Historical OHLCV prices |
|
||||
| ~splits()~ | DataFrame | Stock split events |
|
||||
| ~dividends()~ | DataFrame | Dividend payment history |
|
||||
| ~shares()~ | DataFrame | Shares outstanding over time |
|
||||
| ~beta(period="5y", benchmark="SPY")~ | DataFrame | Calculated beta vs benchmark |
|
||||
| ~currency(symbol)~ | DataFrame | Exchange rate history |
|
||||
| ~ttm_eps()~ | DataFrame | Trailing 12-month EPS |
|
||||
|
||||
** Financial Statements
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|------------------------------+-----------+-------------------------|
|
||||
| ~quarterly_income_statement()~ | ~Statement~ | Quarterly P&L |
|
||||
| ~annual_income_statement()~ | ~Statement~ | Annual P&L |
|
||||
| ~quarterly_balance_sheet()~ | ~Statement~ | Quarterly balance sheet |
|
||||
| ~annual_balance_sheet()~ | ~Statement~ | Annual balance sheet |
|
||||
| ~quarterly_cash_flow()~ | ~Statement~ | Quarterly cash flow |
|
||||
| ~annual_cash_flow()~ | ~Statement~ | Annual cash flow |
|
||||
|
||||
** TTM Aggregates
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|----------------------------------------+-----------+----------------------------------|
|
||||
| ~ttm_revenue()~ | DataFrame | Trailing 12-month revenue |
|
||||
| ~ttm_fcf()~ | DataFrame | Trailing 12-month free cash flow |
|
||||
| ~ttm_ebitda()~ | DataFrame | Trailing 12-month EBITDA |
|
||||
| ~ttm_net_income_common_stockholders()~ | DataFrame | Trailing 12-month net income |
|
||||
| ~ttm_pe()~ | DataFrame | Trailing P/E (price / ttm_eps) |
|
||||
|
||||
** Revenue Breakdown
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|------------------------+-----------+-----------------------------|
|
||||
| ~revenue_by_segment()~ | DataFrame | Revenue by business segment |
|
||||
| ~revenue_by_geography()~ | DataFrame | Revenue by region |
|
||||
| ~revenue_by_product()~ | DataFrame | Revenue by product line |
|
||||
|
||||
** Valuation Multiples
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|-------------------------+-----------+------------------------------|
|
||||
| ~market_capitalization()~ | DataFrame | Historical market cap |
|
||||
| ~ps_ratio()~ | DataFrame | Price/Sales ratio |
|
||||
| ~pb_ratio()~ | DataFrame | Price/Book ratio |
|
||||
| ~peg_ratio()~ | DataFrame | PEG ratio |
|
||||
| ~enterprise_value()~ | DataFrame | Enterprise value |
|
||||
| ~enterprise_to_revenue()~ | DataFrame | EV/Revenue |
|
||||
| ~enterprise_to_ebitda()~ | DataFrame | EV/EBITDA |
|
||||
| ~debt_to_equity()~ | DataFrame | D/E ratio |
|
||||
| ~net_debt_ttm()~ | DataFrame | Net debt (TTM) |
|
||||
| ~wacc()~ | DataFrame | Weighted avg cost of capital |
|
||||
|
||||
** Profitability Returns
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|---------------------+-----------+------------------------------------|
|
||||
| ~roe()~ | DataFrame | Return on equity |
|
||||
| ~roa()~ | DataFrame | Return on assets |
|
||||
| ~roic()~ | DataFrame | Return on invested capital |
|
||||
| ~roce()~ | DataFrame | Return on capital employed |
|
||||
| ~equity_multiplier()~ | DataFrame | Financial leverage (assets/equity) |
|
||||
| ~asset_turnover()~ | DataFrame | Revenue/assets efficiency |
|
||||
|
||||
** Margins
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|------------------------------+-----------+--------------------|
|
||||
| ~quarterly_gross_margin()~ | DataFrame | Gross margin % |
|
||||
| ~annual_gross_margin()~ | DataFrame | Gross margin % |
|
||||
| ~quarterly_operating_margin()~ | DataFrame | Operating margin % |
|
||||
| ~annual_operating_margin()~ | DataFrame | Operating margin % |
|
||||
| ~quarterly_net_margin()~ | DataFrame | Net margin % |
|
||||
| ~annual_net_margin()~ | DataFrame | Net margin % |
|
||||
| ~quarterly_ebitda_margin()~ | DataFrame | EBITDA margin % |
|
||||
| ~annual_ebitda_margin()~ | DataFrame | EBITDA margin % |
|
||||
| ~quarterly_fcf_margin()~ | DataFrame | FCF margin % |
|
||||
| ~annual_fcf_margin()~ | DataFrame | FCF margin % |
|
||||
|
||||
** YoY Growth
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|-----------------------------------------+-----------+---------------------|
|
||||
| ~quarterly_revenue_yoy_growth()~ | DataFrame | Revenue growth % |
|
||||
| ~annual_revenue_yoy_growth()~ | DataFrame | Revenue growth % |
|
||||
| ~quarterly_operating_income_yoy_growth()~ | DataFrame | Op. income growth % |
|
||||
| ~annual_operating_income_yoy_growth()~ | DataFrame | Op. income growth % |
|
||||
| ~quarterly_ebitda_yoy_growth()~ | DataFrame | EBITDA growth % |
|
||||
| ~annual_ebitda_yoy_growth()~ | DataFrame | EBITDA growth % |
|
||||
| ~quarterly_net_income_yoy_growth()~ | DataFrame | Net income growth % |
|
||||
| ~annual_net_income_yoy_growth()~ | DataFrame | Net income growth % |
|
||||
| ~quarterly_fcf_yoy_growth()~ | DataFrame | FCF growth % |
|
||||
| ~annual_fcf_yoy_growth()~ | DataFrame | FCF growth % |
|
||||
| ~quarterly_eps_yoy_growth()~ | DataFrame | EPS growth % |
|
||||
| ~quarterly_ttm_eps_yoy_growth()~ | DataFrame | TTM EPS growth % |
|
||||
|
||||
** Industry Comparisons
|
||||
|
||||
Uses the ticker's own industry to benchmark against peers.
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|------------------------------------+-----------+--------------------------|
|
||||
| ~industry_ttm_pe()~ | DataFrame | Avg P/E across industry |
|
||||
| ~industry_ps_ratio()~ | DataFrame | Industry P/S |
|
||||
| ~industry_pb_ratio()~ | DataFrame | Industry P/B |
|
||||
| ~industry_roe()~ | DataFrame | Industry ROE |
|
||||
| ~industry_roa()~ | DataFrame | Industry ROA |
|
||||
| ~industry_roic()~ | DataFrame | Industry ROIC |
|
||||
| ~industry_equity_multiplier()~ | DataFrame | Industry leverage |
|
||||
| ~industry_asset_turnover()~ | DataFrame | Industry efficiency |
|
||||
| ~industry_quarterly_gross_margin()~ | DataFrame | Industry gross margin % |
|
||||
| ~industry_quarterly_ebitda_margin()~ | DataFrame | Industry EBITDA margin % |
|
||||
| ~industry_quarterly_net_margin()~ | DataFrame | Industry net margin % |
|
||||
|
||||
** DCF / Advanced
|
||||
|
||||
| Method | Returns | What it gives |
|
||||
|-----------------------------+---------+----------------------------------------|
|
||||
| ~dcf_data()~ | dict | All raw inputs for a DCF model |
|
||||
| ~dcf()~ | dict | Full DCF valuation + exports ~.xlsx~ |
|
||||
| ~download_data_performance()~ | str | Timing summary of data fetch durations |
|
||||
|
||||
* Multi-Ticker API — ~Tickers(["AAPL", "NVDA"])~
|
||||
|
||||
#+begin_src python
|
||||
from defeatbeta_api.data.tickers import Tickers
|
||||
t = Tickers(["AAPL", "NVDA"])
|
||||
t = Tickers(["AAPL", "NVDA"], max_workers=2) # limit parallelism
|
||||
#+end_src
|
||||
|
||||
Wraps all ~Ticker~ methods, running them in *parallel threads*.
|
||||
|
||||
- Methods returning simple data → *combined DataFrame* (all tickers in one table)
|
||||
- Methods returning complex objects (statements, news, transcripts) → ~{symbol: result}~ dict
|
||||
|
||||
Same method names as ~Ticker~, plus industry comparison methods operate per unique
|
||||
industry represented across the list.
|
||||
|
||||
#+begin_src python
|
||||
t.info() # → DataFrame (combined)
|
||||
t.price() # → DataFrame (combined)
|
||||
t.annual_income_statement() # → {'AAPL': Statement(...), 'NVDA': Statement(...)}
|
||||
t.news() # → {'AAPL': News(...), 'NVDA': News(...)}
|
||||
t.earning_call_transcripts() # → {'AAPL': Transcripts(...), 'NVDA': Transcripts(...)}
|
||||
t.industry_roe() # → DataFrame (one row per unique industry)
|
||||
#+end_src
|
||||
+186
-128
@@ -7,20 +7,20 @@
|
||||
|
||||
# Overview
|
||||
|
||||
| Category | Yahoo Finance | DefeatBeta-API | Notes |
|
||||
|----------|--------------|----------------|-------|
|
||||
| **Data Source** | Yahoo Finance API | HuggingFace + DuckDB | No rate limits |
|
||||
| **Query Engine** | Direct API | DuckDB OLAP | Sub-second queries |
|
||||
| **Update Frequency** | Real-time (15min delayed) | Daily batch | DefeatBeta is historical only |
|
||||
| **Historical Depth** | Full history | Full history | Comparable coverage |
|
||||
| **Special Features** | Limited | Earnings transcripts, DCF, AI | DefeatBeta has unique capabilities |
|
||||
| Category | Yahoo Finance | DefeatBeta-API | Notes |
|
||||
|--------------------+---------------------------+-------------------------------+------------------------------------|
|
||||
| **Data Source** | Yahoo Finance API | HuggingFace + DuckDB | No rate limits |
|
||||
| **Query Engine** | Direct API | DuckDB OLAP | Sub-second queries |
|
||||
| **Update Frequency** | Real-time (15min delayed) | Daily batch | DefeatBeta is historical only |
|
||||
| **Historical Depth** | Full history | Full history | Comparable coverage |
|
||||
| **Special Features** | Limited | Earnings transcripts, DCF, AI | DefeatBeta has unique capabilities |
|
||||
|
||||
* Price & Volume Data
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.history(period='max')~ | ~ticker.price()~ | pandas.DataFrame | OHLCV data |
|
||||
| ~ticker.history(period='1d')~ | N/A | - | Real-time not available |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|----------------------------------------+-------------------------+------------------+--------------------------|
|
||||
| ~ticker.history(period='max')~ | ~ticker.price()~ | pandas.DataFrame | OHLCV data |
|
||||
| ~ticker.history(period='1d')~ | N/A | - | Real-time not available |
|
||||
| ~ticker.history(start='...', end='...')~ | ~ticker.price()~ (filter) | pandas.DataFrame | Date filtering available |
|
||||
|
||||
* DefeatBeta Price Data Structure
|
||||
@@ -33,14 +33,14 @@
|
||||
|
||||
* Financial Statements
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.quarterly_financials~ | ~ticker.quarterly_income_statement()~ | Statement object | Different format |
|
||||
| ~ticker.financials~ | ~ticker.annual_income_statement()~ | Statement object | Annual version |
|
||||
| ~ticker.quarterly_balance_sheet~ | ~ticker.quarterly_balance_sheet()~ | Statement object | Same structure |
|
||||
| ~ticker.balance_sheet~ | ~ticker.annual_balance_sheet()~ | Statement object | Annual version |
|
||||
| ~ticker.quarterly_cashflow~ | ~ticker.quarterly_cash_flow()~ | Statement object | Note: 'flow' vs 'flow' |
|
||||
| ~ticker.cashflow~ | ~ticker.annual_cash_flow()~ | Statement object | Annual version |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------------------------+-------------------------------------+------------------+------------------------|
|
||||
| ~ticker.quarterly_income_stmt~ | ~ticker.quarterly_income_statement()~ | Statement object | Different format |
|
||||
| ~ticker.income_stmt~ | ~ticker.annual_income_statement()~ | Statement object | Annual version |
|
||||
| ~ticker.quarterly_balance_sheet~ | ~ticker.quarterly_balance_sheet()~ | Statement object | Same structure |
|
||||
| ~ticker.balance_sheet~ | ~ticker.annual_balance_sheet()~ | Statement object | Annual version |
|
||||
| ~ticker.quarterly_cashflow~ | ~ticker.quarterly_cash_flow()~ | Statement object | 'cashflow' vs 'cash_flow' |
|
||||
| ~ticker.cashflow~ | ~ticker.annual_cash_flow()~ | Statement object | Annual version |
|
||||
|
||||
** Statement Object Methods
|
||||
#+BEGIN_SRC python
|
||||
@@ -53,16 +53,16 @@ income_stmt.print_pretty_table() # Formatted output
|
||||
|
||||
* Valuation Metrics
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.info['trailingPE']~ | ~ticker.ttm_pe()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['forwardPE']~ | N/A | - | Not available |
|
||||
| ~ticker.info['trailingEps']~ | ~ticker.ttm_eps()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['forwardEps']~ | N/A | - | Not available |
|
||||
| ~ticker.info['marketCap']~ | ~ticker.market_capitalization()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['priceToBook']~ | ~ticker.pb_ratio()~ | pandas.DataFrame | Price/Book ratio |
|
||||
| ~ticker.info['priceToSalesTrailing12Months']~ | ~ticker.ps_ratio()~ | pandas.DataFrame | Price/Sales ratio |
|
||||
| N/A | ~ticker.peg_ratio()~ | pandas.DataFrame | PEG ratio (unique) |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|---------------------------------------------+--------------------------------+------------------+---------------------------|
|
||||
| ~ticker.info['trailingPE']~ | ~ticker.ttm_pe()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['forwardPE']~ | N/A | - | Not available |
|
||||
| ~ticker.info['trailingEps']~ | ~ticker.ttm_eps()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['forwardEps']~ | N/A | - | Not available |
|
||||
| ~ticker.info['marketCap']~ | ~ticker.market_capitalization()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['priceToBook']~ | ~ticker.pb_ratio()~ | pandas.DataFrame | Price/Book ratio |
|
||||
| ~ticker.info['priceToSalesTrailing12Months']~ | ~ticker.ps_ratio()~ | pandas.DataFrame | Price/Sales ratio |
|
||||
| N/A | ~ticker.peg_ratio()~ | pandas.DataFrame | PEG ratio (unique) |
|
||||
|
||||
** Key Advantage: Historical Valuation Data
|
||||
DefeatBeta provides **full historical time series** for:
|
||||
@@ -75,13 +75,13 @@ Yahoo Finance only provides **current values** in ~.info~
|
||||
|
||||
* Financial Ratios
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.info['returnOnEquity']~ | ~ticker.roe()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['returnOnAssets']~ | ~ticker.roa()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| N/A | ~ticker.roic()~ | pandas.DataFrame | Return on Invested Capital |
|
||||
| N/A | ~ticker.wacc()~ | pandas.DataFrame | Weighted Avg Cost of Capital |
|
||||
| ~ticker.info['beta']~ | ~ticker.beta()~ | pandas.DataFrame | 5Y monthly beta |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|-------------------------------+----------------+------------------+------------------------------|
|
||||
| ~ticker.info['returnOnEquity']~ | ~ticker.roe()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['returnOnAssets']~ | ~ticker.roa()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| N/A | ~ticker.roic()~ | pandas.DataFrame | Return on Invested Capital |
|
||||
| N/A | ~ticker.wacc()~ | pandas.DataFrame | Weighted Avg Cost of Capital |
|
||||
| ~ticker.info['beta']~ | ~ticker.beta()~ | pandas.DataFrame | 5Y monthly beta |
|
||||
|
||||
** WACC Components Available in DefeatBeta
|
||||
#+BEGIN_SRC python
|
||||
@@ -93,66 +93,67 @@ wacc = ticker.wacc()
|
||||
|
||||
* Growth Metrics
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.info['revenueGrowth']~ | ~ticker.quarterly_revenue_yoy_growth()~ | pandas.DataFrame | YoY growth |
|
||||
| ~ticker.info['earningsGrowth']~ | ~ticker.quarterly_eps_yoy_growth()~ | pandas.DataFrame | EPS YoY growth |
|
||||
| N/A | ~ticker.quarterly_net_income_yoy_growth()~ | pandas.DataFrame | Net income growth |
|
||||
| N/A | ~ticker.quarterly_operating_income_yoy_growth()~ | pandas.DataFrame | Operating income growth |
|
||||
| N/A | ~ticker.quarterly_ebitda_yoy_growth()~ | pandas.DataFrame | EBITDA growth |
|
||||
| N/A | ~ticker.quarterly_fcf_yoy_growth()~ | pandas.DataFrame | Free cash flow growth |
|
||||
| N/A | ~ticker.annual_revenue_yoy_growth()~ | pandas.DataFrame | Annual revenue growth |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|-------------------------------+------------------------------------------------+------------------+-------------------------|
|
||||
| ~ticker.info['revenueGrowth']~ | ~ticker.quarterly_revenue_yoy_growth()~ | pandas.DataFrame | YoY growth |
|
||||
| ~ticker.info['earningsGrowth']~ | ~ticker.quarterly_eps_yoy_growth()~ | pandas.DataFrame | EPS YoY growth |
|
||||
| N/A | ~ticker.quarterly_net_income_yoy_growth()~ | pandas.DataFrame | Net income growth |
|
||||
| N/A | ~ticker.quarterly_operating_income_yoy_growth()~ | pandas.DataFrame | Operating income growth |
|
||||
| N/A | ~ticker.quarterly_ebitda_yoy_growth()~ | pandas.DataFrame | EBITDA growth |
|
||||
| N/A | ~ticker.quarterly_fcf_yoy_growth()~ | pandas.DataFrame | Free cash flow growth |
|
||||
| N/A | ~ticker.annual_revenue_yoy_growth()~ | pandas.DataFrame | Annual revenue growth |
|
||||
|
||||
* Margin Metrics
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.info['profitMargins']~ | ~ticker.quarterly_net_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['grossMargins']~ | ~ticker.quarterly_gross_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['operatingMargins']~ | ~ticker.quarterly_operating_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| N/A | ~ticker.quarterly_ebitda_margin()~ | pandas.DataFrame | EBITDA margin |
|
||||
| N/A | ~ticker.quarterly_fcf_margin()~ | pandas.DataFrame | Free cash flow margin |
|
||||
| N/A | ~ticker.industry_quarterly_gross_margin()~ | pandas.DataFrame | Industry comparison |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|---------------------------------+------------------------------------------+------------------+---------------------------|
|
||||
| ~ticker.info['profitMargins']~ | ~ticker.quarterly_net_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['grossMargins']~ | ~ticker.quarterly_gross_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| ~ticker.info['operatingMargins']~ | ~ticker.quarterly_operating_margin()~ | pandas.DataFrame | **Historical** time series! |
|
||||
| N/A | ~ticker.quarterly_ebitda_margin()~ | pandas.DataFrame | EBITDA margin |
|
||||
| N/A | ~ticker.quarterly_fcf_margin()~ | pandas.DataFrame | Free cash flow margin |
|
||||
| N/A | ~ticker.industry_quarterly_gross_margin()~ | pandas.DataFrame | Industry comparison |
|
||||
|
||||
* Dividends & Stock Splits
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.dividends~ | ~ticker.dividends()~ | pandas.DataFrame | Dividend history |
|
||||
| ~ticker.splits~ | ~ticker.splits()~ | pandas.DataFrame | Stock split history |
|
||||
| ~ticker.info['dividendYield']~ | N/A | - | Not in separate field |
|
||||
| ~ticker.info['trailingAnnualDividendYield']~ | N/A | - | Not available |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------------------------------------+--------------------+------------------+-----------------------|
|
||||
| ~ticker.dividends~ | ~ticker.dividends()~ | pandas.DataFrame | Dividend history |
|
||||
| ~ticker.splits~ | ~ticker.splits()~ | pandas.DataFrame | Stock split history |
|
||||
| ~ticker.info['dividendYield']~ | N/A | - | Not in separate field |
|
||||
| ~ticker.info['trailingAnnualDividendYield']~ | N/A | - | Not available |
|
||||
|
||||
* Company Info & Metadata
|
||||
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|--------------|----------------|-------------|-------|
|
||||
| ~ticker.info~ | ~ticker.info()~ | pandas.DataFrame | One row, many columns |
|
||||
| ~ticker.info['longName']~ | ~ticker.info()['long_business_summary']~ | string | Business summary |
|
||||
| ~ticker.info['sector']~ | ~ticker.info()['sector']~ | string | Sector classification |
|
||||
| ~ticker.info['industry']~ | ~ticker.info()['industry']~ | string | Industry classification |
|
||||
| ~ticker.info['website']~ | ~ticker.info()['web_site']~ | string | Company website |
|
||||
| ~ticker.info['fullTimeEmployees']~ | ~ticker.info()['full_time_employees']~ | int | Employee count |
|
||||
| N/A | ~ticker.officers()~ | pandas.DataFrame | Company officers |
|
||||
| N/A | ~ticker.calendar()~ | pandas.DataFrame | Earnings calendar |
|
||||
| Yahoo Finance | DefeatBeta-API | Return Type | Notes |
|
||||
|----------------------------------+----------------------------------------+------------------+-------------------------|
|
||||
| ~ticker.info~ | ~ticker.info()~ | pandas.DataFrame | One row, many columns |
|
||||
| ~ticker.info['longName']~ | N/A (check name/short_name column) | string | Company trading name |
|
||||
| ~ticker.info['longBusinessSummary']~ | ~ticker.info()['long_business_summary']~ | string | Business description |
|
||||
| ~ticker.info['sector']~ | ~ticker.info()['sector']~ | string | Sector classification |
|
||||
| ~ticker.info['industry']~ | ~ticker.info()['industry']~ | string | Industry classification |
|
||||
| ~ticker.info['website']~ | ~ticker.info()['web_site']~ | string | Company website |
|
||||
| ~ticker.info['fullTimeEmployees']~ | ~ticker.info()['full_time_employees']~ | int | Employee count |
|
||||
| N/A | ~ticker.officers()~ | pandas.DataFrame | Company officers |
|
||||
| N/A | ~ticker.calendar()~ | pandas.DataFrame | Earnings calendar |
|
||||
|
||||
* Unique DefeatBeta Features (Not in Yahoo Finance)
|
||||
|
||||
| Feature | Method | Description |
|
||||
|---------|--------|-------------|
|
||||
| **Earnings Transcripts** | ~ticker.earning_call_transcripts()~ | Full earnings call transcripts |
|
||||
| | ~transcripts.get_transcripts_list()~ | List all available transcripts |
|
||||
| | ~transcripts.get_transcript(year, quarter)~ | Get specific quarter's transcript |
|
||||
| | ~transcripts.summarize_key_financial_data_with_ai()~ | AI-powered summary |
|
||||
| **Revenue Breakdown** | ~ticker.revenue_by_segment()~ | Revenue by product segment |
|
||||
| | ~ticker.revenue_by_product()~ | Detailed product breakdown |
|
||||
| | ~ticker.revenue_by_geography()~ | Revenue by geographic region |
|
||||
| **Automated DCF** | ~ticker.dcf()~ | Generates Excel DCF valuation |
|
||||
| **AI Analysis** | ~transcripts.analyze_financial_metrics_change...~ | LLM analysis of quarter changes |
|
||||
| | ~transcripts.analyze_financial_metrics_forecast...~ | LLM forecast analysis |
|
||||
| **Industry Metrics** | ~ticker.industry_ttm_pe()~ | Industry P/E comparison |
|
||||
| | ~ticker.industry_roe()~ | Industry ROE comparison |
|
||||
| | ~ticker.industry_quarterly_gross_margin()~ | Industry margin comparison |
|
||||
| Feature | Method | Description |
|
||||
|------------------------+----------------------------------------------------+-----------------------------------|
|
||||
| **Earnings Transcripts** | ~ticker.earning_call_transcripts()~ | Full earnings call transcripts |
|
||||
| | ~transcripts.get_transcripts_list()~ | List all available transcripts |
|
||||
| | ~transcripts.get_transcript(year, quarter)~ | Get specific quarter's transcript |
|
||||
| | ~transcripts.summarize_key_financial_data_with_ai()~ | AI-powered summary |
|
||||
| **Revenue Breakdown** | ~ticker.revenue_by_segment()~ | Revenue by product segment |
|
||||
| | ~ticker.revenue_by_product()~ | Detailed product breakdown |
|
||||
| | ~ticker.revenue_by_geography()~ | Revenue by geographic region |
|
||||
| **Automated DCF** | ~ticker.dcf()~ | Generates Excel DCF valuation |
|
||||
| **AI Analysis** | ~transcripts.analyze_financial_metrics_change...~ | LLM analysis of quarter changes |
|
||||
| | ~transcripts.analyze_financial_metrics_forecast...~ | LLM forecast analysis |
|
||||
| **Industry Metrics** | ~ticker.industry_ttm_pe()~ | Industry P/E comparison |
|
||||
| | ~ticker.industry_roe()~ | Industry ROE comparison |
|
||||
| | ~ticker.industry_quarterly_gross_margin()~ | Industry margin comparison |
|
||||
|
||||
* Example: yfinance → DefeatBeta Migration
|
||||
|
||||
@@ -209,26 +210,26 @@ current_roe = ticker.roe().iloc[-1]['roe']
|
||||
|
||||
* Quick Reference: Common Operations
|
||||
|
||||
| Operation | Yahoo Finance | DefeatBeta-API |
|
||||
|-----------|--------------|----------------|
|
||||
| Get current price | ~ticker.info['currentPrice']~ | ~ticker.price().iloc[-1]['close']~ |
|
||||
| Get current P/E | ~ticker.info['trailingPE']~ | ~ticker.ttm_pe().iloc[-1]['ttm_pe']~ |
|
||||
| Get current EPS | ~ticker.info['trailingEps']~ | ~ticker.ttm_eps().iloc[-1]['tailing_eps']~ |
|
||||
| Get market cap | ~ticker.info['marketCap']~ | ~ticker.market_capitalization().iloc[-1]['market_capitalization']~ |
|
||||
| Get ROE | ~ticker.info['returnOnEquity']~ | ~ticker.roe().iloc[-1]['roe']~ |
|
||||
| Get revenue (TTM) | ~ticker.info['totalRevenue']~ | ~ticker.quarterly_income_statement().df().iloc[0]['TTM']~ |
|
||||
| Get 5Y beta | ~ticker.info['beta']~ | ~ticker.beta().iloc[-1]['beta']~ |
|
||||
| Operation | Yahoo Finance | DefeatBeta-API |
|
||||
|-------------------+-------------------------------+------------------------------------------------------------------|
|
||||
| Get current price | ~ticker.info['currentPrice']~ | ~ticker.price().iloc[-1]['close']~ |
|
||||
| Get current P/E | ~ticker.info['trailingPE']~ | ~ticker.ttm_pe().iloc[-1]['ttm_pe']~ |
|
||||
| Get current EPS | ~ticker.info['trailingEps']~ | ~ticker.ttm_eps().iloc[-1]['tailing_eps']~ |
|
||||
| Get market cap | ~ticker.info['marketCap']~ | ~ticker.market_capitalization().iloc[-1]['market_capitalization']~ |
|
||||
| Get ROE | ~ticker.info['returnOnEquity']~ | ~ticker.roe().iloc[-1]['roe']~ |
|
||||
| Get revenue (TTM) | ~ticker.info['totalRevenue']~ | ~ticker.quarterly_income_statement().df().iloc[0]['TTM']~ |
|
||||
| Get 5Y beta | ~ticker.info['beta']~ | ~ticker.beta().iloc[-1]['beta']~ |
|
||||
|
||||
* Data Type Differences
|
||||
|
||||
| Aspect | Yahoo Finance | DefeatBeta-API |
|
||||
|--------|--------------|----------------|
|
||||
| Dates in DataFrame | DatetimeIndex | 'report_date' column |
|
||||
| Column naming | Title case (Open, Close) | Snake case (open, close) |
|
||||
| Dividends/Splits | Separate columns in history | Separate DataFrames |
|
||||
| Quarterly data | Transposed (dates as columns) | Wide format (TTM + quarters as columns) |
|
||||
| Missing data | NaN | NaN |
|
||||
| Numeric types | float | Decimal (convert with ~float()~) |
|
||||
| Aspect | Yahoo Finance | DefeatBeta-API |
|
||||
|--------------------+-------------------------------+-----------------------------------------|
|
||||
| Dates in DataFrame | DatetimeIndex | 'report_date' column |
|
||||
| Column naming | Title case (Open, Close) | Snake case (open, close) |
|
||||
| Dividends/Splits | Separate columns in history | Separate DataFrames |
|
||||
| Quarterly data | Transposed (dates as columns) | Wide format (TTM + quarters as columns) |
|
||||
| Missing data | NaN | NaN |
|
||||
| Numeric types | float | Decimal (convert with ~float()~) |
|
||||
|
||||
* Converting Decimal to Float
|
||||
#+BEGIN_SRC python
|
||||
@@ -244,37 +245,94 @@ market_cap_billions = float(market_cap.iloc[-1]['market_capitalization']) / 1e9
|
||||
|
||||
* When to Use Each
|
||||
|
||||
| Use Case | Recommendation | Reason |
|
||||
|----------|---------------|--------|
|
||||
| Backtesting trading strategies | **DefeatBeta** | No rate limits, consistent historical data |
|
||||
| DCF Valuation modeling | **DefeatBeta** | Automated Excel output |
|
||||
| Revenue segment analysis | **DefeatBeta** | Unique revenue breakdown |
|
||||
| Earnings call research | **DefeatBeta** | Full transcripts available |
|
||||
| Real-time price alerts | **Yahoo Finance** | 15min delayed but real-time |
|
||||
| Analyst recommendations | **Yahoo Finance** | Price targets, ratings |
|
||||
| Institutional ownership | **Yahoo Finance** | Major holders data |
|
||||
| Options/derivatives data | **Yahoo Finance** | Not available in DefeatBeta |
|
||||
| Quick stock lookup | **Either** | Both work well |
|
||||
| Multi-year historical analysis | **DefeatBeta** | Faster queries, no rate limits |
|
||||
| Use Case | Recommendation | Reason |
|
||||
|--------------------------------+-----------------+--------------------------------------------|
|
||||
| Backtesting trading strategies | **DefeatBeta** | No rate limits, consistent historical data |
|
||||
| DCF Valuation modeling | **DefeatBeta** | Automated Excel output |
|
||||
| Revenue segment analysis | **DefeatBeta** | Unique revenue breakdown |
|
||||
| Earnings call research | **DefeatBeta** | Full transcripts available |
|
||||
| Real-time price alerts | **Yahoo Finance** | 15min delayed but real-time |
|
||||
| Analyst recommendations | **Yahoo Finance** | Price targets, ratings |
|
||||
| Institutional ownership | **Yahoo Finance** | Major holders data |
|
||||
| Options/derivatives data | **Yahoo Finance** | Not available in DefeatBeta |
|
||||
| Quick stock lookup | **Either** | Both work well |
|
||||
| Multi-year historical analysis | **DefeatBeta** | Faster queries, no rate limits |
|
||||
|
||||
* Environment Setup
|
||||
|
||||
| Task | Command |
|
||||
|------|---------|
|
||||
| Install DefeatBeta | ~uv add defeatbeta-api~ |
|
||||
| Install yfinance | ~uv add yfinance~ |
|
||||
| Run notebook | ~uv run jupyter notebook~ |
|
||||
| Check version | ~ticker.price()~ shows data update date |
|
||||
| Task | Command |
|
||||
|--------------------+---------------------------------------|
|
||||
| Install DefeatBeta | ~uv add defeatbeta-api~ |
|
||||
| Install yfinance | ~uv add yfinance~ |
|
||||
| Run notebook | ~uv run jupyter notebook~ |
|
||||
| Check version | ~ticker.price()~ shows data update date |
|
||||
|
||||
* Mapping Limitations & Verification Notes
|
||||
/Verified 2026-04-26 via test_mapping.py on AAPL. defeatbeta-api 0.0.45, yfinance 1.3.0, DuckDB 1.4.3./
|
||||
|
||||
** What was confirmed correct (live data matched)
|
||||
- ~dividends()~: both APIs return $0.26 for Nov-2025 and Feb-2026 payments — values match exactly
|
||||
- ~splits()~: both return the same ratios (7:1 in 2014, 4:1 in 2020)
|
||||
|
||||
** Incorrect property names for yfinance (deprecated in v1.3)
|
||||
|
||||
| Used in mapping | Correct name in yfinance 1.3+ |
|
||||
|----------------------------+-------------------------------|
|
||||
| ~ticker.quarterly_financials~ | ~ticker.quarterly_income_stmt~ |
|
||||
| ~ticker.financials~ | ~ticker.income_stmt~ |
|
||||
|
||||
The old names were removed. The mapping should use the new names.
|
||||
|
||||
** Conceptual mismatch: longName vs long_business_summary (Company Info)
|
||||
|
||||
The mapping equates ~ticker.info['longName']~ with ~ticker.info()['long_business_summary']~,
|
||||
labelling it "Business summary". This is wrong:
|
||||
|
||||
- ~longName~ = company trading name, e.g. "Apple Inc."
|
||||
- ~long_business_summary~ = multi-sentence business description paragraph
|
||||
- The yfinance equivalent of the description is ~ticker.info['longBusinessSummary']~
|
||||
|
||||
** Typo in Financial Statements note (cashflow row)
|
||||
|
||||
The "Notes" column reads ~Note: 'flow' vs 'flow'~. Should read: ~'cashflow' vs 'cash_flow'~
|
||||
|
||||
** Data format differences found in verified pairs
|
||||
|
||||
| Field | yfinance | defeatbeta |
|
||||
|---------------+--------------------------------------+-------------------------------|
|
||||
| dividends | Series, DatetimeIndex, float amount | DataFrame, report_date col |
|
||||
| split_factor | float (e.g. ~7.0~) | string ratio (e.g. ~"7:1"~) |
|
||||
|
||||
** Historical coverage gap
|
||||
|
||||
- Dividends: yfinance returns 90 records, defeatbeta returns 61 (truncated history)
|
||||
- Splits: yfinance returns 5 events, defeatbeta returns 4 (one historical split missing)
|
||||
|
||||
** DuckDB compatibility issue (defeatbeta-api 0.0.45 + DuckDB 1.4.3)
|
||||
|
||||
All Parquet-backed queries except ~dividends()~ and ~splits()~ failed during verification
|
||||
with either ~"don't know what type:"~ or ~"TProtocolException: Invalid data"~. Affected:
|
||||
~price()~, all financial statements, all valuation/ratio/margin/growth metrics, ~info()~, ~beta()~.
|
||||
|
||||
This is an incompatibility between DuckDB 1.4.3 and the httpfs extension / remote Parquet
|
||||
format used by defeatbeta-api. Downgrading DuckDB or waiting for a defeatbeta-api update
|
||||
may resolve it. The logical mapping is still valid — the API shape is correct, only the
|
||||
DuckDB query layer is broken.
|
||||
|
||||
** Data freshness
|
||||
|
||||
DefeatBeta dataset last updated 2026-04-17, 9 days behind current date. yfinance has
|
||||
15-minute delayed real-time data. This gap will always exist for defeatbeta.
|
||||
|
||||
* Common Issues & Solutions
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| ~TypeError: unsupported operand type(s) for /: 'Decimal' and 'float'~ | Wrap values in ~float()~ |
|
||||
| ~Rate limit exceeded~ | Switch to DefeatBeta |
|
||||
| ~Real-time data needed~ | Use Yahoo Finance |
|
||||
| ~Missing revenue breakdown~ | Use DefeatBeta ~revenue_by_segment()~ |
|
||||
| ~Slow queries~ | Use DefeatBeta (DuckDB engine) |
|
||||
| Issue | Solution |
|
||||
|---------------------------------------------------------------------+-------------------------------------|
|
||||
| ~TypeError: unsupported operand type(s) for /: 'Decimal' and 'float'~ | Wrap values in ~float()~ |
|
||||
| ~Rate limit exceeded~ | Switch to DefeatBeta |
|
||||
| ~Real-time data needed~ | Use Yahoo Finance |
|
||||
| ~Missing revenue breakdown~ | Use DefeatBeta ~revenue_by_segment()~ |
|
||||
| ~Slow queries~ | Use DefeatBeta (DuckDB engine) |
|
||||
|
||||
* Additional Resources
|
||||
|
||||
@@ -285,7 +343,7 @@ market_cap_billions = float(market_cap.iloc[-1]['market_capitalization']) / 1e9
|
||||
|
||||
* Footer
|
||||
#+BEGIN_COMMENT
|
||||
Last updated: 2026-04-25
|
||||
Last updated: 2026-04-26 (verified via test_mapping.py on AAPL)
|
||||
Author: Documentation
|
||||
Version: 1.0
|
||||
#+END_COMMENT
|
||||
#+END_COMMENT
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
"""
|
||||
Mapping verification: yfinance vs defeatbeta-api for AAPL.
|
||||
Prints type + 2 representative rows/values for each mapped pair.
|
||||
Methods that fail are reported inline (not crashed).
|
||||
"""
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
import yfinance as yf
|
||||
from defeatbeta_api.data.ticker import Ticker
|
||||
import pandas as pd
|
||||
|
||||
SYMBOL = "AAPL"
|
||||
|
||||
yf_t = yf.Ticker(SYMBOL)
|
||||
db_t = Ticker(SYMBOL)
|
||||
|
||||
PASS = "✓"
|
||||
FAIL = "✗"
|
||||
|
||||
|
||||
def try_db(fn, *args, **kwargs):
|
||||
"""Call a defeatbeta method, return (result, None) or (None, error_str)."""
|
||||
try:
|
||||
return fn(*args, **kwargs), None
|
||||
except Exception as e:
|
||||
return None, str(e)[:80]
|
||||
|
||||
|
||||
def show_df(label, df, n=2):
|
||||
if df is None:
|
||||
return
|
||||
if isinstance(df, pd.DataFrame):
|
||||
print(f" {label} ({df.shape[0]}r×{df.shape[1]}c), last {n} rows:")
|
||||
cols = list(df.columns)[:6]
|
||||
print(df[cols].tail(n).to_string(index=False))
|
||||
elif isinstance(df, pd.Series):
|
||||
print(f" {label} (Series len={len(df)}), last {n}:")
|
||||
print(df.tail(n).to_string())
|
||||
|
||||
|
||||
def row(label, yf_val, yf_type_label, db_result, db_err):
|
||||
ok = PASS if db_result is not None else FAIL
|
||||
print(f"\n{ok} {label}")
|
||||
if db_err:
|
||||
print(f" yfinance → {yf_type_label}: {yf_val!r}")
|
||||
print(f" defeatbeta→ ERROR: {db_err}")
|
||||
else:
|
||||
print(f" yfinance type={yf_type_label} value={yf_val!r}")
|
||||
print(f" defeatbeta type={type(db_result).__name__}", end="")
|
||||
if isinstance(db_result, pd.DataFrame):
|
||||
print(f" cols={list(db_result.columns)}")
|
||||
show_df("defeatbeta", db_result)
|
||||
else:
|
||||
print(f" value={db_result!r}")
|
||||
|
||||
|
||||
def section(title):
|
||||
print(f"\n{'='*68}\n {title}\n{'='*68}")
|
||||
|
||||
|
||||
# ── 1. PRICE DATA ─────────────────────────────────────────────────────────────
|
||||
section("1. PRICE DATA — ticker.history() vs ticker.price()")
|
||||
|
||||
yf_price = yf_t.history(period="5d")[["Open", "Close", "High", "Low", "Volume"]]
|
||||
db_price, db_price_err = try_db(db_t.price)
|
||||
|
||||
print(f"\n{PASS if not db_price_err else FAIL} ticker.history() vs ticker.price()")
|
||||
print(f" yfinance type=DataFrame cols={list(yf_price.columns)}")
|
||||
print(yf_price.tail(2).to_string())
|
||||
if db_price_err:
|
||||
print(f" defeatbeta→ ERROR: {db_price_err}")
|
||||
else:
|
||||
print(f" defeatbeta type=DataFrame cols={list(db_price.columns)}")
|
||||
print(db_price.tail(2).to_string(index=False))
|
||||
|
||||
# ── 2. FINANCIAL STATEMENTS ───────────────────────────────────────────────────
|
||||
section("2. FINANCIAL STATEMENTS")
|
||||
|
||||
# yfinance uses .quarterly_income_stmt (v1.3) — old .quarterly_financials is deprecated
|
||||
yf_inc_q = yf_t.quarterly_income_stmt
|
||||
db_inc_q, db_inc_q_err = try_db(db_t.quarterly_income_statement)
|
||||
db_inc_q_df = db_inc_q.df() if db_inc_q else None
|
||||
|
||||
print(f"\n{PASS if not db_inc_q_err else FAIL} quarterly_income_stmt vs quarterly_income_statement()")
|
||||
print(f" yfinance type={type(yf_inc_q).__name__} shape={yf_inc_q.shape} (rows=line items, cols=quarters)")
|
||||
print(yf_inc_q.iloc[:2, :2].to_string())
|
||||
if db_inc_q_err:
|
||||
print(f" defeatbeta→ ERROR: {db_inc_q_err}")
|
||||
else:
|
||||
print(f" defeatbeta type={type(db_inc_q).__name__} → .df() shape={db_inc_q_df.shape}")
|
||||
print(db_inc_q_df.iloc[:2, :5].to_string(index=False))
|
||||
|
||||
yf_bs = yf_t.balance_sheet
|
||||
db_bs, db_bs_err = try_db(db_t.annual_balance_sheet)
|
||||
db_bs_df = db_bs.df() if db_bs else None
|
||||
|
||||
print(f"\n{PASS if not db_bs_err else FAIL} balance_sheet vs annual_balance_sheet()")
|
||||
print(f" yfinance type={type(yf_bs).__name__} shape={yf_bs.shape}")
|
||||
print(yf_bs.iloc[:2, :2].to_string())
|
||||
if db_bs_err:
|
||||
print(f" defeatbeta→ ERROR: {db_bs_err}")
|
||||
else:
|
||||
print(f" defeatbeta type={type(db_bs).__name__} → .df() shape={db_bs_df.shape}")
|
||||
print(db_bs_df.iloc[:2, :5].to_string(index=False))
|
||||
|
||||
yf_cf = yf_t.cashflow
|
||||
db_cf, db_cf_err = try_db(db_t.annual_cash_flow)
|
||||
db_cf_df = db_cf.df() if db_cf else None
|
||||
|
||||
print(f"\n{PASS if not db_cf_err else FAIL} cashflow vs annual_cash_flow()")
|
||||
print(f" yfinance type={type(yf_cf).__name__} shape={yf_cf.shape}")
|
||||
print(yf_cf.iloc[:2, :2].to_string())
|
||||
if db_cf_err:
|
||||
print(f" defeatbeta→ ERROR: {db_cf_err}")
|
||||
else:
|
||||
print(f" defeatbeta → .df() shape={db_cf_df.shape}")
|
||||
print(db_cf_df.iloc[:2, :5].to_string(index=False))
|
||||
|
||||
# ── 3. VALUATION METRICS ──────────────────────────────────────────────────────
|
||||
section("3. VALUATION METRICS")
|
||||
|
||||
db_pe, db_pe_err = try_db(db_t.ttm_pe)
|
||||
db_eps, db_eps_err = try_db(db_t.ttm_eps)
|
||||
db_mc, db_mc_err = try_db(db_t.market_capitalization)
|
||||
db_pb, db_pb_err = try_db(db_t.pb_ratio)
|
||||
db_ps, db_ps_err = try_db(db_t.ps_ratio)
|
||||
|
||||
row("trailingPE → ttm_pe()", yf_t.info.get("trailingPE"), "float", db_pe, db_pe_err)
|
||||
row("trailingEps → ttm_eps()", yf_t.info.get("trailingEps"), "float", db_eps, db_eps_err)
|
||||
row("marketCap → market_cap()", yf_t.info.get("marketCap"), "int", db_mc, db_mc_err)
|
||||
row("priceToBook → pb_ratio()", yf_t.info.get("priceToBook"), "float", db_pb, db_pb_err)
|
||||
row("priceToSales → ps_ratio()", yf_t.info.get("priceToSalesTrailing12Months"), "float", db_ps, db_ps_err)
|
||||
|
||||
# ── 4. FINANCIAL RATIOS ───────────────────────────────────────────────────────
|
||||
section("4. FINANCIAL RATIOS")
|
||||
|
||||
db_roe, db_roe_err = try_db(db_t.roe)
|
||||
db_roa, db_roa_err = try_db(db_t.roa)
|
||||
db_beta, db_beta_err = try_db(db_t.beta)
|
||||
db_wacc, db_wacc_err = try_db(db_t.wacc)
|
||||
|
||||
row("returnOnEquity → roe()", yf_t.info.get("returnOnEquity"), "float", db_roe, db_roe_err)
|
||||
row("returnOnAssets → roa()", yf_t.info.get("returnOnAssets"), "float", db_roa, db_roa_err)
|
||||
row("beta → beta()", yf_t.info.get("beta"), "float", db_beta, db_beta_err)
|
||||
row("N/A → wacc()", None, "N/A", db_wacc, db_wacc_err)
|
||||
|
||||
# ── 5. GROWTH METRICS ─────────────────────────────────────────────────────────
|
||||
section("5. GROWTH METRICS")
|
||||
|
||||
db_rg, db_rg_err = try_db(db_t.quarterly_revenue_yoy_growth)
|
||||
db_eg, db_eg_err = try_db(db_t.quarterly_eps_yoy_growth)
|
||||
db_nig, db_nig_err = try_db(db_t.quarterly_net_income_yoy_growth)
|
||||
|
||||
row("revenueGrowth → quarterly_revenue_yoy_growth()", yf_t.info.get("revenueGrowth"), "float", db_rg, db_rg_err)
|
||||
row("earningsGrowth → quarterly_eps_yoy_growth()", yf_t.info.get("earningsGrowth"), "float", db_eg, db_eg_err)
|
||||
row("N/A → quarterly_net_income_yoy_growth()", None, "N/A", db_nig, db_nig_err)
|
||||
|
||||
# ── 6. MARGIN METRICS ─────────────────────────────────────────────────────────
|
||||
section("6. MARGIN METRICS")
|
||||
|
||||
db_nm, db_nm_err = try_db(db_t.quarterly_net_margin)
|
||||
db_gm, db_gm_err = try_db(db_t.quarterly_gross_margin)
|
||||
db_om, db_om_err = try_db(db_t.quarterly_operating_margin)
|
||||
|
||||
row("profitMargins → quarterly_net_margin()", yf_t.info.get("profitMargins"), "float", db_nm, db_nm_err)
|
||||
row("grossMargins → quarterly_gross_margin()", yf_t.info.get("grossMargins"), "float", db_gm, db_gm_err)
|
||||
row("operatingMargins → quarterly_op_margin()", yf_t.info.get("operatingMargins"), "float", db_om, db_om_err)
|
||||
|
||||
# ── 7. DIVIDENDS & SPLITS ─────────────────────────────────────────────────────
|
||||
section("7. DIVIDENDS & SPLITS")
|
||||
|
||||
yf_div = yf_t.dividends
|
||||
db_div, db_div_err = try_db(db_t.dividends)
|
||||
|
||||
print(f"\n{PASS if not db_div_err else FAIL} .dividends vs .dividends()")
|
||||
print(f" yfinance type={type(yf_div).__name__} len={len(yf_div)}")
|
||||
print(yf_div.tail(2).to_string())
|
||||
if db_div_err:
|
||||
print(f" defeatbeta→ ERROR: {db_div_err}")
|
||||
else:
|
||||
print(f" defeatbeta type={type(db_div).__name__} shape={db_div.shape}")
|
||||
print(db_div.tail(2).to_string(index=False))
|
||||
|
||||
yf_sp = yf_t.splits
|
||||
db_sp, db_sp_err = try_db(db_t.splits)
|
||||
|
||||
print(f"\n{PASS if not db_sp_err else FAIL} .splits vs .splits()")
|
||||
print(f" yfinance type={type(yf_sp).__name__} len={len(yf_sp)}")
|
||||
print(yf_sp.tail(2).to_string())
|
||||
if db_sp_err:
|
||||
print(f" defeatbeta→ ERROR: {db_sp_err}")
|
||||
else:
|
||||
print(f" defeatbeta type={type(db_sp).__name__} shape={db_sp.shape}")
|
||||
print(db_sp.tail(2).to_string(index=False))
|
||||
|
||||
# ── 8. COMPANY INFO ───────────────────────────────────────────────────────────
|
||||
section("8. COMPANY INFO — .info vs .info()")
|
||||
|
||||
yf_info = yf_t.info
|
||||
db_info, db_info_err = try_db(db_t.info)
|
||||
|
||||
if db_info_err:
|
||||
print(f" defeatbeta→ ERROR: {db_info_err}")
|
||||
else:
|
||||
fields = [
|
||||
("sector", "sector", yf_info.get("sector")),
|
||||
("industry", "industry", yf_info.get("industry")),
|
||||
("employees", "full_time_employees", yf_info.get("fullTimeEmployees")),
|
||||
("website", "web_site", yf_info.get("website")),
|
||||
# Note: yf longName = company name; longBusinessSummary = description
|
||||
("longName", None, yf_info.get("longName")),
|
||||
("longBusinessSummary", "long_business_summary", yf_info.get("longBusinessSummary", "")[:60]),
|
||||
]
|
||||
print(f"\n {'Field':<30} {'yfinance':<35} {'defeatbeta'}")
|
||||
print(f" {'-'*30} {'-'*35} {'-'*30}")
|
||||
for label, db_col, yf_val in fields:
|
||||
db_val = db_info[db_col].iloc[0] if db_col and db_col in db_info.columns else "—"
|
||||
if isinstance(db_val, str) and len(db_val) > 40:
|
||||
db_val = db_val[:40] + "…"
|
||||
if isinstance(yf_val, str) and len(yf_val) > 34:
|
||||
yf_val = yf_val[:34] + "…"
|
||||
print(f" {label:<30} {str(yf_val):<35} {str(db_val)}")
|
||||
|
||||
# ── SUMMARY ───────────────────────────────────────────────────────────────────
|
||||
print(f"\n{'='*68}")
|
||||
print(" ALL CHECKS COMPLETE")
|
||||
print(f"{'='*68}\n")
|
||||
@@ -0,0 +1,302 @@
|
||||
#+title: yfinance API Reference
|
||||
#+subtitle: Version 1.3.0
|
||||
#+author: Ran Aroussi
|
||||
#+date: 2026-04-25
|
||||
|
||||
* Overview
|
||||
|
||||
yfinance offers a Pythonic way to fetch financial & market data from Yahoo! Finance.
|
||||
|
||||
** Installation
|
||||
#+begin_src sh
|
||||
pip install yfinance
|
||||
#+end_src
|
||||
|
||||
** Quick Start
|
||||
#+begin_src python
|
||||
import yfinance as yf
|
||||
|
||||
# Single ticker
|
||||
dat = yf.Ticker("MSFT")
|
||||
dat.info
|
||||
dat.history(period='1mo')
|
||||
dat.option_chain(dat.options[0]).calls
|
||||
|
||||
# Multiple tickers
|
||||
tickers = yf.Tickers('MSFT AAPL GOOG')
|
||||
tickers.tickers['MSFT'].info
|
||||
yf.download(['MSFT', 'AAPL', 'GOOG'], period='1mo')
|
||||
|
||||
# Funds
|
||||
spy = yf.Ticker('SPY').funds_data
|
||||
spy.description
|
||||
spy.top_holdings
|
||||
#+end_src
|
||||
|
||||
* Top-Level Functions
|
||||
|
||||
| Function | Description |
|
||||
|--------------------------------+-------------------------------------------|
|
||||
| ~yf.download(tickers, ...)~ | Download market data for multiple tickers |
|
||||
| ~yf.enable_debug_mode()~ | Enable verbose debug logging |
|
||||
| ~yf.set_tz_cache_location(path)~ | Set timezone cache directory |
|
||||
| ~yf.screen(query)~ | Run equity/fund/ETF screener queries |
|
||||
|
||||
* Config
|
||||
|
||||
| Setting | Description |
|
||||
|---------------------------------+----------------------|
|
||||
| ~yf.config.debug.logging = True~ | Enable debug logging |
|
||||
| ~yf.config.user_agent = 'custom'~ | Custom user agent |
|
||||
|
||||
* Ticker(symbol)
|
||||
|
||||
** Price History
|
||||
|
||||
| Property/Method | Returns |
|
||||
|---------------------------------------------+--------------------------------------|
|
||||
| ~.history(period, start, end, interval, ...)~ | OHLCV DataFrame |
|
||||
| ~.get_history_metadata()~ | Dict with currency, exchange, etc. |
|
||||
| ~.get_dividends()~ | Dividend history (Series) |
|
||||
| ~.dividends~ | Cached dividend history |
|
||||
| ~.get_splits()~ | Stock split history (Series) |
|
||||
| ~.splits~ | Cached split history |
|
||||
| ~.get_actions()~ | Dividends + splits combined (Series) |
|
||||
| ~.actions~ | Cached actions history |
|
||||
| ~.get_capital_gains()~ | Capital gains distributions (Series) |
|
||||
| ~.capital_gains~ | Cached capital gains |
|
||||
| ~.get_shares_full()~ | Full shares outstanding history |
|
||||
|
||||
** Info & News
|
||||
|
||||
| Property/Method | Returns |
|
||||
|-------------------------------+----------------------------------|
|
||||
| ~.get_info()~ / ~.info~ | Full company info dict |
|
||||
| ~.get_fast_info()~ / ~.fast_info~ | Quick-access key metrics |
|
||||
| ~.get_news()~ / ~.news~ | Recent news articles (DataFrame) |
|
||||
| ~.isin~ | ISIN identifier |
|
||||
| ~.get_isin()~ | ISIN as string |
|
||||
|
||||
** Financial Statements
|
||||
|
||||
| Property/Method | Returns |
|
||||
|------------------------+-----------------------------------------|
|
||||
| ~.income_stmt~ | Annual income statement |
|
||||
| ~.quarterly_income_stmt~ | Quarterly income statement |
|
||||
| ~.ttm_income_stmt~ | Trailing-twelve-months income statement |
|
||||
| ~.balance_sheet~ | Annual balance sheet |
|
||||
| ~.cashflow~ | Annual cash flow statement |
|
||||
| ~.quarterly_cashflow~ | Quarterly cash flow |
|
||||
| ~.ttm_cashflow~ | TTM cash flow |
|
||||
| ~.get_income_stmt()~ | Alias for income_stmt |
|
||||
| ~.get_balance_sheet()~ | Alias for balance_sheet |
|
||||
| ~.get_cashflow()~ | Alias for cashflow |
|
||||
|
||||
** Earnings & Calendar
|
||||
|
||||
| Property/Method | Returns |
|
||||
|-----------------------+--------------------------------------|
|
||||
| ~.earnings~ | Annual earnings summary |
|
||||
| ~.calendar~ | Upcoming earnings/dividends dates |
|
||||
| ~.get_earnings_dates()~ | Historical & upcoming earnings dates |
|
||||
| ~.earnings_dates~ | Cached earnings dates |
|
||||
| ~.get_sec_filings()~ | SEC filing history |
|
||||
| ~.sec_filings~ | Cached SEC filings |
|
||||
|
||||
** Analysis & Estimates
|
||||
|
||||
| Property/Method | Returns |
|
||||
|--------------------------------+------------------------------------|
|
||||
| ~.get_recommendations()~ | Historical analyst recommendations |
|
||||
| ~.recommendations~ | Cached recommendations |
|
||||
| ~.get_recommendations_summary()~ | Summary of buy/hold/sell |
|
||||
| ~.recommendations_summary~ | Cached summary |
|
||||
| ~.get_upgrades_downgrades()~ | Analyst upgrades/downgrades |
|
||||
| ~.upgrades_downgrades~ | Cached upgrades/downgrades |
|
||||
| ~.get_sustainability()~ | ESG scores |
|
||||
| ~.sustainability~ | Cached ESG |
|
||||
| ~.get_analyst_price_targets()~ | Price target estimates |
|
||||
| ~.analyst_price_targets~ | Cached price targets |
|
||||
| ~.get_earnings_estimate()~ | Earnings estimates |
|
||||
| ~.earnings_estimate~ | Cached earnings estimates |
|
||||
| ~.get_revenue_estimate()~ | Revenue estimates |
|
||||
| ~.revenue_estimate~ | Cached revenue estimates |
|
||||
| ~.get_earnings_history()~ | Earnings surprise history |
|
||||
| ~.earnings_history~ | Cached earnings history |
|
||||
| ~.get_eps_trend()~ | EPS trend revisions |
|
||||
| ~.eps_trend~ | Cached EPS trend |
|
||||
| ~.get_eps_revisions()~ | EPS revision counts |
|
||||
| ~.eps_revisions~ | Cached EPS revisions |
|
||||
| ~.get_growth_estimates()~ | Growth rate estimates |
|
||||
| ~.growth_estimates~ | Cached growth estimates |
|
||||
|
||||
** Holdings & Insider Activity
|
||||
|
||||
| Property/Method | Returns |
|
||||
|---------------------------------------------------------+-----------------------------------|
|
||||
| ~.get_funds_data()~ / ~.funds_data~ | Fund info (for ETFs/mutual funds) |
|
||||
| ~.get_insider_purchases()~ / ~.insider_purchases~ | Insider purchase records |
|
||||
| ~.get_insider_transactions()~ / ~.insider_transactions~ | Insider trade history |
|
||||
| ~.get_insider_roster_holders()~ / ~.insider_roster_holders~ | Insider roster |
|
||||
| ~.get_major_holders()~ / ~.major_holders~ | Ownership breakdown |
|
||||
| ~.get_institutional_holders()~ / ~.institutional_holders~ | Institutional holders |
|
||||
| ~.get_mutualfund_holders()~ / ~.mutualfund_holders~ | Mutual fund holders |
|
||||
|
||||
** Options
|
||||
|
||||
| Method | Returns |
|
||||
|---------------------+-------------------------------------|
|
||||
| ~.options~ | Tuple of available expiration dates |
|
||||
| ~.option_chain(date)~ | Calls & puts DataFrame for a date |
|
||||
| | |
|
||||
|
||||
* Tickers('SYM1 SYM2 ...')
|
||||
|
||||
Multiple tickers class.
|
||||
|
||||
| Property | Returns |
|
||||
|---------------------------+----------------------------------|
|
||||
| ~.tickers['SYM'].info~ | Access individual Ticker objects |
|
||||
| ~.tickers['SYM'].history()~ | Get history per ticker |
|
||||
|
||||
* Market(market_code)
|
||||
|
||||
Market summary class.
|
||||
|
||||
| Method/Property | Returns |
|
||||
|-----------------+---------------------------|
|
||||
| ~.status~ | Market open/closed status |
|
||||
| ~.summary()~ | Market summary data |
|
||||
|
||||
* Calendars
|
||||
|
||||
Calendar events class.
|
||||
|
||||
| Method | Returns |
|
||||
|--------------+-------------------|
|
||||
| ~.earnings()~ | Earnings calendar |
|
||||
| ~.dividends()~ | Dividend calendar |
|
||||
| ~.splits()~ | Splits calendar |
|
||||
| ~.ipo()~ | IPO calendar |
|
||||
|
||||
* Search(query)
|
||||
|
||||
Search class for quotes and news.
|
||||
|
||||
| Property/Method | Returns |
|
||||
|-----------------+----------------------|
|
||||
| ~.quotes~ | Search result quotes |
|
||||
| ~.news~ | Search result news |
|
||||
| ~.lists~ | Watchlists/lists |
|
||||
| ~.nav~ | Navigation results |
|
||||
| ~.research~ | Research reports |
|
||||
| ~.get_quotes()~ | Fetch quotes |
|
||||
| ~.get_news()~ | Fetch news |
|
||||
|
||||
* Lookup(query)
|
||||
|
||||
Ticker lookup class.
|
||||
|
||||
| Method | Returns |
|
||||
|---------------+------------------------|
|
||||
| ~.get_quotes()~ | Lookup matching quotes |
|
||||
|
||||
* WebSocket(symbols, ...)
|
||||
|
||||
Live streaming data (synchronous).
|
||||
|
||||
| Method | Description |
|
||||
|-----------------------+---------------------------|
|
||||
| ~.connect()~ | Open WebSocket connection |
|
||||
| ~.subscribe(symbols)~ | Subscribe to symbols |
|
||||
| ~.unsubscribe(symbols)~ | Unsubscribe from symbols |
|
||||
| ~.close()~ | Close connection |
|
||||
|
||||
* AsyncWebSocket(symbols, ...)
|
||||
|
||||
Live streaming data (asynchronous).
|
||||
|
||||
Same methods as ~WebSocket~, but async.
|
||||
|
||||
* Sector(sector_key)
|
||||
|
||||
Sector information class.
|
||||
|
||||
| Property/Method | Returns |
|
||||
|-----------------+--------------------------|
|
||||
| ~.key~ | Sector identifier |
|
||||
| ~.name~ | Sector name |
|
||||
| ~.symbol~ | Associated ETF symbol |
|
||||
| ~.top_etfs~ | Top ETFs in sector |
|
||||
| ~.top_companies~ | Top companies in sector |
|
||||
| ~.industries~ | Industries within sector |
|
||||
|
||||
* Industry(industry_key)
|
||||
|
||||
Industry information class.
|
||||
|
||||
| Property/Method | Returns |
|
||||
|-----------------+---------------------------|
|
||||
| ~.key~ | Industry identifier |
|
||||
| ~.name~ | Industry name |
|
||||
| ~.sector_key~ | Parent sector |
|
||||
| ~.top_companies~ | Top companies in industry |
|
||||
|
||||
* Query Builders (Screener)
|
||||
|
||||
| Class | Description |
|
||||
|------------------+------------------------------------|
|
||||
| ~EquityQuery~ | Build equity filter queries |
|
||||
| ~FundQuery~ | Build mutual fund filter queries |
|
||||
| ~ETFQuery~ | Build ETF filter queries |
|
||||
| ~yf.screen(query)~ | Execute a query and return results |
|
||||
|
||||
* download() Parameters
|
||||
|
||||
#+begin_src python
|
||||
yf.download(
|
||||
tickers, # str or list of tickers
|
||||
period="1mo", # 1d, 5d, 1mo, 3mo, 6mo, 1y, 2y, 5y, 10y, ytd, max
|
||||
start=None, # datetime or str "YYYY-MM-DD"
|
||||
end=None,
|
||||
interval="1d", # 1m, 2m, 5m, 15m, 30m, 60m, 90m, 1h, 1d, 5d, 1wk, 1mo, 3mo
|
||||
group_by="column", # "column" or "ticker"
|
||||
auto_adjust=False,
|
||||
back_adjust=False,
|
||||
repair=False, # Enable price repair
|
||||
keepna=False,
|
||||
proxy=None,
|
||||
timeout=10,
|
||||
threads=True,
|
||||
progress=True,
|
||||
)
|
||||
#+end_src
|
||||
|
||||
* Advanced Features
|
||||
|
||||
** Logging
|
||||
Enable debug logging:
|
||||
#+begin_src python
|
||||
yf.config.debug.logging = True
|
||||
#+end_src
|
||||
|
||||
** Caching
|
||||
- Persistent cache is enabled by default
|
||||
- Set custom cache location: ~yf.set_tz_cache_location(path)~
|
||||
|
||||
** Price Repair
|
||||
- Enable with ~repair=True~ in ~download()~ or ~history()~
|
||||
- Fixes NaN values, bad splits, and dividend adjustments
|
||||
- Dividend repair also available
|
||||
|
||||
** Multi-Level Column Index
|
||||
- When downloading multiple tickers, columns are MultiIndex
|
||||
- ~group_by="column"~ or ~group_by="ticker"~
|
||||
|
||||
* Legal Disclaimer
|
||||
|
||||
Yahoo!, Y!Finance, and Yahoo! finance are registered trademarks of Yahoo, Inc.
|
||||
|
||||
yfinance is /not/ affiliated, endorsed, or vetted by Yahoo, Inc. It's an open-source tool that uses Yahoo's publicly available APIs, and is intended for research and educational purposes.
|
||||
|
||||
You should refer to Yahoo!'s terms of use for details on your rights to use the actual data downloaded. The Yahoo! finance API is intended for personal use only.
|
||||
Reference in New Issue
Block a user