# Fundamental Analysis with edgarfundamentals

## Overview

`edgarfundamentals` provides a simple, ticker-based interface for retrieving fundamental financial ratios directly from SEC EDGAR 10-K filings. No API key or paid subscription is required. All data comes from the SEC’s official XBRL API at `data.sec.gov`, which is free, stable, and government-maintained.

The package provides four functions:

- `get_cik()` – translates a ticker to its SEC Central Index Key
- `get_fundamentals()` – retrieves ratios for a single stock
- `get_fundamentals_batch()` – retrieves ratios for a portfolio of stocks
- `get_filing_history()` – retrieves recent SEC filing history for a stock

## Setup

Before making any API calls, set your User-Agent string. The SEC requests that automated tools identify themselves so they can contact you if your scripts cause issues with their servers.

    library(edgarfundamentals)

    options(edgarfundamentals.user_agent = "Jane Smith jane@example.com")

Replace the name and email with your own. You only need to do this once per R session.

## Looking Up a CIK

Every EDGAR API call requires a CIK number. `get_cik()` handles this translation automatically inside the other functions, but you can call it directly if you need the CIK for other purposes.

    get_cik("LLY")   # Eli Lilly
    get_cik("LMT")   # Lockheed Martin

## Fundamentals for a Single Stock

`get_fundamentals()` returns a named vector of key financial ratios derived from the most recent 10-K filing on or before `to_date`.

    get_fundamentals("LLY", to_date = "2024-12-31")

The returned vector contains:

Name | Description
--- | ---
`CIK` | SEC Central Index Key
`EPS` | Diluted Earnings Per Share (USD)
`NetIncome` | Net Income (USD)
`Revenue` | Total Revenue (USD)
`ROE` | Return on Equity (%)
`ROA` | Return on Assets (%)
`DE` | Debt-to-Equity ratio
`CurrentRatio` | Current Assets / Current Liabilities
`GrossMargin` | Gross Profit as a percentage of Revenue (%)
`OperatingMargin` | Operating Income as a percentage of Revenue (%)
`NetMargin` | Net Income as a percentage of Revenue (%)
`PE` | Price-to-Earnings ratio
`PB` | Price-to-Book ratio
`DIV` | Dividend Yield (%)

Because ratios come from annual 10-K filings, they reflect the most recently completed fiscal year – not real-time values. The PE ratio is the only computed value that uses a live market price (via Yahoo Finance), so it will change daily even when the underlying 10-K data does not.

## Fundamentals for a Portfolio

`get_fundamentals_batch()` accepts a vector of tickers and returns a tidy data frame with one row per stock. If retrieval fails for any ticker, that row contains `NA` values and a message is printed – the batch continues rather than stopping.

    healthcare <- c("UNH", "PFE", "MRK", "ABT", "LLY", "CVS", "AMGN")
    defense    <- c("LMT", "RTX", "NOC", "GD",  "HII", "LHX", "LDOS")

    healthcare.fund <- get_fundamentals_batch(healthcare, to_date = "2024-12-31")
    defense.fund    <- get_fundamentals_batch(defense,    to_date = "2024-12-31")

    healthcare.fund
    defense.fund

Expect retrieval to take approximately 20–30 seconds for 14 stocks. A 0.5 second pause is inserted after each API call to respect the SEC rate limit.

## Screening by Fundamental Criteria

Once you have the data frame, standard `dplyr` operations apply directly.

    library(dplyr)

    # Growth screen: high EPS stocks relative to peers signal strong earnings
    healthcare.fund |> arrange(desc(EPS))

    # Value screen: low PE and low PB suggest the market is pricing the stock cheaply
    # High dividend yield is also characteristic of value stocks
    defense.fund |> filter(PE < 20 & PB < 3) |> select(symbol, PE, PB, DIV, ROE)

    # GARP screen (Growth at a Reasonable Price): PE below EPS
    # Stocks where the market is not overcharging for growth
    healthcare.fund |> filter(EPS > 0 & PE < EPS) |> select(symbol, PE, EPS)

    # Profitability screen: strong margins signal pricing power and operational efficiency
    bind_rows(healthcare.fund, defense.fund) |>
      filter(GrossMargin > 40 & OperatingMargin > 15) |>
      arrange(desc(NetMargin)) |>
      select(symbol, GrossMargin, OperatingMargin, NetMargin, ROA)

    # Liquidity screen: current ratio above 1.5 and low leverage
    bind_rows(healthcare.fund, defense.fund) |>
      filter(CurrentRatio > 1.5 & DE < 1) |>
      arrange(desc(CurrentRatio)) |>
      select(symbol, CurrentRatio, DE, ROE)

## Checking Filing History

`get_filing_history()` retrieves recent EDGAR filings for a company, which is useful for verifying data availability or for finding the accession numbers needed to access the full text of specific reports.

    # Five most recent annual reports for Lockheed Martin
    get_filing_history("LMT", form_type = "10-K", n = 5)

    # Four most recent quarterly reports for Eli Lilly
    get_filing_history("LLY", form_type = "10-Q", n = 4)

## A Note on Data Limitations

EDGAR XBRL data is only as good as what companies report. A small number of companies use non-standard XBRL tag names for common concepts. The package automatically tries fallback tags when the primary tag returns no data, but in rare cases a ratio may still be `NA`. When this occurs, verifying the company’s most recent 10-K directly on `edgar.sec.gov` will confirm whether the data exists under a different tag name.

Additionally, EDGAR does not provide market-based ratios directly. Price-to-Book and Dividend Yield both require a current share price, which comes from Yahoo Finance via `tidyquant`. This means PE, PB, and DIV all reflect today’s price against the most recent annual filing data, which is standard practice for trailing ratios.