Skip to main content
ℹ️ Informational only. This series shows how to automate SEC EDGAR data retrieval. Nothing here is investment or legal advice. Always consult a qualified professional before making investment decisions.
📚 PART 4 OF 5

10-K Deep Dive — Automate Annual Report Intelligence

Annual Report Monitoring · Risk Factor Change Detection · NLP Diff Analysis

What is a 10-K?

The 10-K is the comprehensive annual report. Filed within 60–90 days of fiscal year end depending on company size. Key sections:

  • Item 1: Business description — what the company does
  • Item 1A: Risk factors — most important for change detection
  • Item 7: MD&A — management discussion & analysis
  • Item 8: Financial statements — full GAAP audited financials
  • Item 9A: Internal controls — management's assessment of controls

The Killer Feature: Risk Factor Diff

Item 1A risk factors change year-over-year. New risk factors often signal things management is worried about before they show up in financials: new litigation, regulatory scrutiny, supply chain issues, competitive threats. OpenClaw can diff this year's risk factors against last year's and flag new language with semantic NLP, not just string matching.

Risk Factor Diff Configuration

name: tenk_risk_diff
schedule: "0 9 * * 1"
steps:
  - fetch_10k:
      ciks: "{{ watchlist_ciks }}"
      since: "{{ 90_days_ago }}"
  - extract_section:
      section: "Item 1A"
      method: text_extraction
  - compare:
      to: prior_year_10k
      method: semantic_diff
      threshold: 0.15
  - llm:
      prompt: |
        Compare these two versions of Item 1A Risk Factors.
        Identify: new risks added, risks removed, material language changes.
        Be specific about what changed and why it might matter.
        Prior year: {{ prior_risk_factors }}
        Current year: {{ current_risk_factors }}
  - notify:
      subject: "📚 10-K Risk Factor Changes: {{ ticker }} {{ fiscal_year }}"

Segment Revenue Extraction

Extract segment-level revenue data from XBRL to track business mix changes:

def get_segment_revenue(cik: str):
    """Extract segment revenue from XBRL company facts."""
    padded = cik.zfill(10)
    url = f"https://data.sec.gov/api/xbrl/companyfacts/CIK{padded}.json"
    headers = {"User-Agent": "YourName your@email.com"}
    r = httpx.get(url, headers=headers)
    facts = r.json()
    # RevenueFromContractWithCustomerExcludingAssessedTax
    # or Revenues — try both
    us_gaap = facts["facts"].get("us-gaap", {})
    for tag in ["RevenueFromContractWithCustomerExcludingAssessedTax", "Revenues"]:
        if tag in us_gaap:
            annual = [v for v in us_gaap[tag]["units"].get("USD", [])
                      if v.get("form") == "10-K"]
            return sorted(annual, key=lambda x: x["end"], reverse=True)
    return []

Debt Maturity Schedule Extraction

10-K note disclosures include future debt maturities. Extract and alert on large maturities within 18 months with questionable refinancing capacity:

Debt maturity cliff detection: Companies with large debt maturities in the near term + declining free cash flow + rising interest rates = refinancing risk. This is findable in the debt schedule notes.

Annual vs Quarterly Comparison

Aspect 10-K (Annual) 10-Q (Quarterly)
Filing frequency Once per year 3 times per year (Q1, Q2, Q3)
Audit status Fully audited by external auditor Reviewed (not audited)
Risk factors section Detailed Item 1A Updates only (Item 1A.Risk Factors)
Internal controls assessment Full Item 9A with auditor opinion Management assessment only
Use case Comprehensive annual review, risk monitoring Timely operational updates, trend tracking

FAQ

Q: How long are 10-Ks?

A: Large accelerated filers often file 100–300 page 10-Ks. You don't read them — OpenClaw extracts and summarizes what changed from last year.

Q: Can I compare across companies?

A: XBRL makes cross-company comparison possible for standardized metrics. Segment data is less standardized because reporting structures vary.

Q: How do I handle fiscal years that don't end in December?

A: Filter by the `period` field in the EDGAR API response, not calendar year. Walmart's fiscal year ends January 31, for example.