feat: add defeatbeta-api integration with comprehensive comparison tools
- Add defeatbeta-api as primary financial data source (replaces yfinance for analysis) - Add comprehensive Jupyter notebook tutorial (defeatbeta_tutorial.ipynb) - Add API comparison script (compare_apis.py) - Add data exploration script (explore_data.py) - Add basic test script (test_defeatbeta.py) - Add notebook runner script (run_notebook.sh) - Add org-mode mapping documentation (docs/defeatbeta_mapping.org) - Update pyproject.toml with defeatbeta-api dependency - Add defeatbeta-api as git submodule for reference DefeatBeta Advantages: - No rate limits (HuggingFace hosted) - Historical financial ratios (ROE, ROIC, WACC time series) - Earnings call transcripts access - Revenue segmentation by product/geography - Automated DCF valuation with Excel output - DuckDB-powered fast queries Note: .envrc, .jupyter_checkpoints/, __marimo__/, AAPL.xlsx, tearsheet.html and other generated files intentionally excluded
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for defeatbeta-api demonstrating practical use cases
|
||||
"""
|
||||
|
||||
import pandas as pd
|
||||
from defeatbeta_api.data.ticker import Ticker
|
||||
|
||||
def analyze_stock(ticker_symbol):
|
||||
"""Analyze a stock using defeatbeta-api"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"ANALYZING {ticker_symbol}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# Create ticker instance
|
||||
ticker = Ticker(ticker_symbol)
|
||||
|
||||
# 1. Get basic price and valuation
|
||||
print("\n1. PRICE AND VALUATION:")
|
||||
price_data = ticker.price()
|
||||
latest_price = price_data.iloc[-1]
|
||||
print(f" Latest price: ${latest_price['close']:.2f}")
|
||||
print(f" Date: {latest_price['report_date']}")
|
||||
print(f" Volume: {latest_price['volume']:,}")
|
||||
|
||||
# 2. Get TTM metrics
|
||||
ttm_eps = ticker.ttm_eps()
|
||||
if not ttm_eps.empty:
|
||||
latest_eps = ttm_eps.iloc[-1]['tailing_eps']
|
||||
print(f"\n2. TTM METRICS:")
|
||||
print(f" TTM EPS: ${latest_eps:.2f}")
|
||||
|
||||
ttm_pe = ticker.ttm_pe()
|
||||
if not ttm_pe.empty:
|
||||
latest_pe = ttm_pe.iloc[-1]['ttm_pe']
|
||||
print(f" TTM P/E: {latest_pe:.2f}")
|
||||
|
||||
# 3. Get market cap
|
||||
market_cap = ticker.market_capitalization()
|
||||
if not market_cap.empty:
|
||||
latest_mcap = market_cap.iloc[-1]['market_capitalization']
|
||||
print(f" Market Cap: ${latest_mcap:,.2f}")
|
||||
|
||||
# 4. Get financial ratios
|
||||
print(f"\n3. FINANCIAL RATIOS:")
|
||||
|
||||
roe = ticker.roe()
|
||||
if not roe.empty:
|
||||
latest_roe = roe.iloc[-1]['roe']
|
||||
print(f" ROE: {latest_roe:.2%}")
|
||||
|
||||
roic = ticker.roic()
|
||||
if not roic.empty:
|
||||
latest_roic = roic.iloc[-1]['roic']
|
||||
print(f" ROIC: {latest_roic:.2%}")
|
||||
|
||||
wacc = ticker.wacc()
|
||||
if not wacc.empty:
|
||||
latest_wacc = wacc.iloc[-1]['wacc']
|
||||
print(f" WACC: {latest_wacc:.2%}")
|
||||
|
||||
# 5. Get beta
|
||||
beta_data = ticker.beta()
|
||||
if not beta_data.empty:
|
||||
latest_beta = beta_data.iloc[-1]['beta']
|
||||
print(f" Beta (5Y): {latest_beta:.2f}")
|
||||
|
||||
# 6. Get growth metrics
|
||||
print(f"\n4. GROWTH METRICS:")
|
||||
|
||||
revenue_growth = ticker.quarterly_revenue_yoy_growth()
|
||||
if not revenue_growth.empty:
|
||||
latest_rev_growth = revenue_growth.iloc[-1]['yoy_growth']
|
||||
print(f" Quarterly Revenue YoY Growth: {latest_rev_growth:.2%}")
|
||||
|
||||
eps_growth = ticker.quarterly_eps_yoy_growth()
|
||||
if not eps_growth.empty:
|
||||
latest_eps_growth = eps_growth.iloc[-1]['yoy_growth']
|
||||
print(f" Quarterly EPS YoY Growth: {latest_eps_growth:.2%}")
|
||||
|
||||
# 7. Get margin metrics
|
||||
print(f"\n5. MARGIN METRICS:")
|
||||
|
||||
gross_margin = ticker.quarterly_gross_margin()
|
||||
if not gross_margin.empty:
|
||||
latest_gross_margin = gross_margin.iloc[-1]['gross_margin']
|
||||
print(f" Gross Margin: {latest_gross_margin:.2%}")
|
||||
|
||||
net_margin = ticker.quarterly_net_margin()
|
||||
if not net_margin.empty:
|
||||
latest_net_margin = net_margin.iloc[-1]['net_margin']
|
||||
print(f" Net Margin: {latest_net_margin:.2%}")
|
||||
|
||||
# 8. Get income statement summary
|
||||
print(f"\n6. INCOME STATEMENT SUMMARY (Latest Quarter):")
|
||||
income_stmt = ticker.quarterly_income_statement()
|
||||
try:
|
||||
income_df = income_stmt.df() # df is a method, not a property
|
||||
# Get key metrics
|
||||
key_metrics = ['Total Revenue', 'Gross Profit', 'Operating Income',
|
||||
'Net Income Common Stockholders', 'Diluted EPS']
|
||||
|
||||
for metric in key_metrics:
|
||||
if metric in income_df['Breakdown'].values:
|
||||
row = income_df[income_df['Breakdown'] == metric]
|
||||
if not row.empty:
|
||||
latest_q = row.iloc[0]['TTM'] # TTM column has latest
|
||||
print(f" {metric}: ${latest_q/1e6:,.2f}M" if 'Revenue' in metric or 'Profit' in metric or 'Income' in metric else f" {metric}: ${latest_q:.2f}")
|
||||
except Exception as e:
|
||||
print(f" Could not retrieve income statement details: {type(e).__name__}")
|
||||
|
||||
# 9. Get revenue breakdown
|
||||
print(f"\n7. REVENUE BREAKDOWN (Latest):")
|
||||
revenue_segment = ticker.revenue_by_segment()
|
||||
if not revenue_segment.empty:
|
||||
latest_rev = revenue_segment.iloc[-1]
|
||||
print(f" Total Revenue: ${latest_rev.iloc[2:].sum():,.0f}")
|
||||
for col in revenue_segment.columns[2:]: # Skip symbol and report_date
|
||||
if col in latest_rev:
|
||||
value = latest_rev[col]
|
||||
if pd.notna(value):
|
||||
print(f" {col}: ${value:,.0f}")
|
||||
|
||||
return ticker
|
||||
|
||||
def compare_stocks(tickers):
|
||||
"""Compare multiple stocks"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"COMPARING STOCKS: {', '.join(tickers)}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
comparison_data = []
|
||||
|
||||
for symbol in tickers:
|
||||
ticker = Ticker(symbol)
|
||||
|
||||
# Get key metrics
|
||||
metrics = {'Symbol': symbol}
|
||||
|
||||
# Price
|
||||
price_data = ticker.price()
|
||||
if not price_data.empty:
|
||||
metrics['Price'] = price_data.iloc[-1]['close']
|
||||
|
||||
# TTM P/E
|
||||
ttm_pe = ticker.ttm_pe()
|
||||
if not ttm_pe.empty:
|
||||
metrics['P/E'] = ttm_pe.iloc[-1]['ttm_pe']
|
||||
|
||||
# Market Cap
|
||||
market_cap = ticker.market_capitalization()
|
||||
if not market_cap.empty:
|
||||
metrics['Market Cap'] = market_cap.iloc[-1]['market_capitalization']
|
||||
|
||||
# ROE
|
||||
roe = ticker.roe()
|
||||
if not roe.empty:
|
||||
metrics['ROE'] = roe.iloc[-1]['roe']
|
||||
|
||||
# Revenue Growth
|
||||
rev_growth = ticker.quarterly_revenue_yoy_growth()
|
||||
if not rev_growth.empty:
|
||||
metrics['Rev Growth'] = rev_growth.iloc[-1]['yoy_growth']
|
||||
|
||||
comparison_data.append(metrics)
|
||||
|
||||
# Create comparison table
|
||||
df = pd.DataFrame(comparison_data)
|
||||
df.set_index('Symbol', inplace=True)
|
||||
|
||||
# Format the table
|
||||
print(f"\n{df.to_string(float_format=lambda x: f'{x:,.2f}' if isinstance(x, (int, float)) else str(x))}")
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
print("DEFEATBETA-API DEMONSTRATION")
|
||||
print("="*60)
|
||||
|
||||
# Analyze individual stocks
|
||||
stocks = ['NVDA', 'TSLA', 'AAPL']
|
||||
|
||||
for stock in stocks[:2]: # Just analyze first 2 to keep output manageable
|
||||
analyze_stock(stock)
|
||||
|
||||
# Compare all stocks
|
||||
compare_stocks(stocks)
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print("API FEATURES DEMONSTRATED:")
|
||||
print("1. Price and volume data")
|
||||
print("2. TTM EPS and P/E ratios")
|
||||
print("3. Market capitalization")
|
||||
print("4. Financial ratios (ROE, ROIC, WACC)")
|
||||
print("5. Beta calculation")
|
||||
print("6. Growth metrics (Revenue, EPS YoY)")
|
||||
print("7. Margin analysis")
|
||||
print("8. Income statement summary")
|
||||
print("9. Revenue segmentation")
|
||||
print("10. Multi-stock comparison")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user