b5bf689e72
- 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>
350 lines
21 KiB
Org Mode
350 lines
21 KiB
Org Mode
# DEFEATBETA-API vs YFINANCE MAPPING
|
|
# A comprehensive guide for migrating from Yahoo Finance to DefeatBeta-API
|
|
|
|
* DEFEATBETA-API vs YFINANCE MAPPING :noexport:
|
|
This document provides a mapping between Yahoo Finance (yfinance)
|
|
and DefeatBeta-API methods and attributes.
|
|
|
|
# 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 |
|
|
|
|
* 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 |
|
|
| ~ticker.history(start='...', end='...')~ | ~ticker.price()~ (filter) | pandas.DataFrame | Date filtering available |
|
|
|
|
* DefeatBeta Price Data Structure
|
|
#+BEGIN_SRC python
|
|
# Columns: ['symbol', 'report_date', 'open', 'close', 'high', 'low', 'volume']
|
|
# Example:
|
|
symbol report_date open close high low volume
|
|
0 AAPL 2026-04-17 266.96 270.23 272.30 266.72 61314800
|
|
#+END_SRC
|
|
|
|
* Financial Statements
|
|
|
|
| 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
|
|
# DefeatBeta Statement objects have these methods:
|
|
income_stmt = ticker.quarterly_income_statement()
|
|
income_stmt.df() # Returns pandas.DataFrame
|
|
income_stmt.data() # Alternative access
|
|
income_stmt.print_pretty_table() # Formatted output
|
|
#+END_SRC
|
|
|
|
* 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) |
|
|
|
|
** Key Advantage: Historical Valuation Data
|
|
DefeatBeta provides **full historical time series** for:
|
|
- TTM P/E ratios (all daily closes)
|
|
- TTM EPS history
|
|
- Market cap history
|
|
- Price/Book, Price/Sales ratios
|
|
|
|
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 |
|
|
|
|
** WACC Components Available in DefeatBeta
|
|
#+BEGIN_SRC python
|
|
# Full breakdown of WACC calculation:
|
|
wacc = ticker.wacc()
|
|
# Columns: market_capitalization, beta_5y, sp500_10y_cagr, treasure_10y_yield,
|
|
# weight_of_debt, weight_of_equity, cost_of_debt, cost_of_equity, wacc
|
|
#+END_SRC
|
|
|
|
* 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 |
|
|
|
|
* 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 |
|
|
|
|
* 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 |
|
|
|
|
* Company Info & Metadata
|
|
|
|
| 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 |
|
|
|
|
* Example: yfinance → DefeatBeta Migration
|
|
|
|
** Yahoo Finance Style
|
|
#+BEGIN_SRC python
|
|
import yfinance as yf
|
|
|
|
ticker = yf.Ticker('AAPL')
|
|
|
|
# Current valuation
|
|
pe = ticker.info['trailingPE']
|
|
eps = ticker.info['trailingEps']
|
|
market_cap = ticker.info['marketCap']
|
|
|
|
# Financial statements
|
|
quarterly_financials = ticker.quarterly_financials
|
|
quarterly_balance = ticker.quarterly_balance_sheet
|
|
|
|
# Growth
|
|
revenue_growth = ticker.info['revenueGrowth']
|
|
#+END_SRC
|
|
|
|
** DefeatBeta Equivalent
|
|
#+BEGIN_SRC python
|
|
from defeatbeta_api.data.ticker import Ticker
|
|
|
|
ticker = Ticker('AAPL')
|
|
|
|
# Historical valuation time series
|
|
ttm_pe = ticker.ttm_pe() # Full daily P/E history
|
|
ttm_eps = ticker.ttm_eps() # Full EPS history
|
|
market_cap = ticker.market_capitalization() # Daily market cap
|
|
|
|
# Financial statements
|
|
quarterly_income = ticker.quarterly_income_statement()
|
|
quarterly_balance = ticker.quarterly_balance_sheet()
|
|
|
|
# Convert to DataFrame
|
|
income_df = quarterly_income.df()
|
|
|
|
# Growth metrics (time series!)
|
|
revenue_growth = ticker.quarterly_revenue_yoy_growth()
|
|
eps_growth = ticker.quarterly_eps_yoy_growth()
|
|
#+END_SRC
|
|
|
|
** Getting Current Values from DefeatBeta
|
|
#+BEGIN_SRC python
|
|
# DefeatBeta provides time series, but getting current value is easy:
|
|
current_pe = ticker.ttm_pe().iloc[-1]['ttm_pe']
|
|
current_eps = ticker.ttm_eps().iloc[-1]['tailing_eps']
|
|
current_mcap = ticker.market_capitalization().iloc[-1]['market_capitalization']
|
|
current_roe = ticker.roe().iloc[-1]['roe']
|
|
#+END_SRC
|
|
|
|
* 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']~ |
|
|
|
|
* 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()~) |
|
|
|
|
* Converting Decimal to Float
|
|
#+BEGIN_SRC python
|
|
# DefeatBeta returns Decimal types for financial data
|
|
# Always convert before arithmetic operations
|
|
|
|
value = ticker.ttm_eps().iloc[-1]['tailing_eps']
|
|
value_float = float(value) # Convert Decimal → float
|
|
|
|
# Use in calculations
|
|
market_cap_billions = float(market_cap.iloc[-1]['market_capitalization']) / 1e9
|
|
#+END_SRC
|
|
|
|
* 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 |
|
|
|
|
* 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 |
|
|
|
|
* 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) |
|
|
|
|
* Additional Resources
|
|
|
|
- DefeatBeta-API: https://github.com/defeat-beta/defeatbeta-api
|
|
- Documentation: https://github.com/defeat-beta/defeatbeta-api/tree/main/doc
|
|
- DCF Examples: https://github.com/defeat-beta/defeatbeta-api/tree/main/doc/api/DCF_Examples.md
|
|
- Value Examples: https://github.com/defeat-beta/defeatbeta-api/tree/main/doc/api/Value_Examples.md
|
|
|
|
* Footer
|
|
#+BEGIN_COMMENT
|
|
Last updated: 2026-04-26 (verified via test_mapping.py on AAPL)
|
|
Author: Documentation
|
|
Version: 1.0
|
|
#+END_COMMENT
|