edgarkit 0.1.0

An unofficial Rust client for the SEC EDGAR system
Documentation
# EdgarKit

<div align="center">
  <img src=".assets/mascot.png" alt="EdgarKit Mascot" width="200">
</div>

[![Crates.io](https://img.shields.io/crates/v/edgarkit.svg)](https://crates.io/crates/edgarkit)
[![Documentation](https://docs.rs/edgarkit/badge.svg)](https://docs.rs/edgarkit)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

An unofficial Rust client for the SEC EDGAR (Electronic Data Gathering, Analysis, and Retrieval) system.

## Why EdgarKit

EdgarKit is built for financial apps and high-throughput, production-grade pipelines that need to ingest, search, and process SEC filings reliably and fast. It’s a great fit for:

- High-performance financial data pipelines (ETL and streaming)
- Quantitative and fundamental investment research
- Corporate event tracking and governance analytics
- Compliance monitoring and audit workflows
- Building dashboards and alerting for market-moving filings

Rust shines here: many SEC filings (especially S-1, 10-K, 10-Q) are large and complex. Parsing, validating, and extracting structure from these can be very CPU- and IO-intensive. With Rust’s zero-cost abstractions and async runtime, you can scale to millions of documents with predictable latency and minimal overhead.

Compared to Python tools like `edgartools` or `sec-edgar-downloader`, Rust typically:
- Processes heavy filings dramatically faster (no GIL, native threading)
- Uses far less memory (no large dynamic overhead)
- Offers compile-time guarantees and stronger type safety
- Integrates cleanly into modern distributed systems (containers, services)

If you’ve hit bottlenecks with scripting solutions, EdgarKit lets you keep the developer ergonomics while upgrading performance and reliability.

## Features

- **🚦 Rate-Limited HTTP Client** - Automatic compliance with SEC.gov fair access rules
- **📄 Filing Operations** - Access company filings, submissions, and documents
- **🏢 Company Information** - Retrieve company facts, tickers, and metadata
- **🔍 Search Capabilities** - Find filings with customizable search criteria
- **📡 Feed Operations** - Monitor Atom and RSS feeds for filings and news
- **📊 Index Operations** - Download and parse daily and quarterly filing indices
- **⚡ Async-First** - Built on tokio for high-performance concurrent operations
- **🎯 Type-Safe** - Strongly-typed API with comprehensive error handling
- **🔧 Flexible** - Feature flags for modular compilation

## Installation

Add EdgarKit to your `Cargo.toml`:

```toml
[dependencies]
edgarkit = "0.1.0"
tokio = { version = "1", features = ["full"] }
```

### Feature Flags

EdgarKit uses feature flags to allow you to compile only what you need:

```toml
[dependencies]
edgarkit = { version = "0.1.0", features = ["search", "filings", "company"] }
```

Available features:
- `search` - Search API functionality (requires `serde_urlencoded`, `futures`)
- `filings` - Filing operations (requires `flate2`, `chrono`)
- `company` - Company information APIs (requires `chrono`)
- `feeds` - RSS/Atom feed support (requires `quick-xml`)
- `index` - Index file operations (requires `flate2`, `chrono`, `regex`)

Default features: `["search", "filings", "company", "feeds", "index"]` (all features enabled)

## Quick Start

```rust
use edgarkit::{Edgar, FilingOperations, FilingOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize the client with a proper user agent
    // SEC.gov requires format: "AppName contact@example.com"
    let edgar = Edgar::new("MyApp contact@example.com")?;
    
    // Get recent 10-K filings for Apple (CIK: 320193)
    let options = FilingOptions::new()
        .with_form_type("10-K")
        .with_limit(5);
    
    let filings = edgar.filings("320193", Some(options)).await?;
    
    for filing in filings {
        println!("Filed: {} - {}", filing.filing_date, filing.form);
    }
    
    Ok(())
}
```

## Filing Types You’ll Use Most

Understanding common forms helps target the right data:

- 8-K: Current reports for material events. Ideal for event tracking (mergers, leadership changes, financing, bankruptcy). See the official guide: https://www.sec.gov/files/form8-k.pdf
- 10-K: Annual report with audited financials, risk factors, MD&A, business overview. Deep, comprehensive view. https://www.sec.gov/files/form10-k.pdf
- 10-Q: Quarterly report with unaudited financials and updates. More frequent pulse than 10-K. https://www.sec.gov/files/form10-q.pdf

Other frequent forms for governance and ownership:
- 3/4/5: Insider ownership changes
- Schedule 13D/13G: Beneficial ownership disclosures
- Form D: Exempt offerings
- Investment company forms like `NCEN`, `N-PORT`, `N-CSR`

## Tips & Tricks

- `DetailedFiling.items`: Quickly scan 8-K items to identify important events. The official 8-K item reference is here: https://www.sec.gov/files/form8-k.pdf. For example, items like `1.01, 2.03, 5.01` indicate significant agreements, creation of liabilities, or a change in control of registrant (5.01).
- `is_xbrl` vs `is_inline_xbrl`: Indicates whether the filing contains XBRL (machine-readable financials) or Inline XBRL (embedded in HTML). Use XBRL parsers for precise numeric extraction; Inline XBRL often improves context and presentation.
- `primary_document`: Often the main HTML/XML file to parse. If you fetch the text filing, the primary document usually appears first.
- Use feature filters and `FilingOptions` to constrain the workload (form types, limits, offsets). For S-1 workflows, consider including amendments (S-1/A) or disabling them when you need only originals.

## Companion Crates (Recommended)

- `crabrl`: High-performance XBRL parser and validator for financial statements. Parse us-gaap concepts at scale. https://crates.io/crates/crabrl
- `quick-xml`: Fast XML parsing, perfect for lightweight forms (3/4/5, Form D, NCEN, Schedule 13D/13G) and structured feeds. https://crates.io/crates/quick-xml
- `rig.rs`: For complex, narrative-heavy filings (S-1, 10-K, 10-Q), use rig.rs with strong models (DeepSeek 3.2, Claude Haiku 4.5, Qwen Plus) to extract sections, summarize, and classify. https://rig.rs/

## Why Rust (A Short Story)

I originally built a filing pipeline in TypeScript. It worked—until it needed to process heavy S-1 filings at scale. Regex-based parsing slowed to a crawl, memory usage spiked, and throughput collapsed. Rewriting the pipeline in Rust solved the core problems: faster IO, deterministic performance, safe concurrency, and efficient parsing. EdgarKit is the distilled client layer born from that migration.

## Usage Examples

Examples are provided in the `examples/` directory to keep this README concise.

### Download Filing Content

```rust
use edgarkit::{Edgar, FilingOperations};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let edgar = Edgar::new("MyApp contact@example.com")?;
    
    // Get the latest 10-K for a company
    let content = edgar.get_latest_filing_content("320193", &["10-K"]).await?;
    
    // Save to file or process the content
    println!("Downloaded {} bytes", content.len());
    
    Ok(())
}
```

### Access Index Files

```rust
use edgarkit::{Edgar, EdgarDay, IndexOperations, FilingOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let edgar = Edgar::new("MyApp contact@example.com")?;
    
    // Get all filings from a specific day
    let day = EdgarDay::new(2024, 8, 15)?;
    let options = FilingOptions::new().with_form_type("10-K");
    
    let filings = edgar.get_daily_filings(day, Some(options)).await?;
    
    for filing in filings {
        println!("{} - {}", filing.company_name, filing.form_type);
    }
    
    Ok(())
}
```

## More Examples

Check out the `examples/` directory for comprehensive examples:

- [`basic_usage.rs`]examples/basic_usage.rs - Getting started with EdgarKit
- [`search_filings.rs`]examples/search_filings.rs - Advanced search patterns
- [`download_filings.rs`]examples/download_filings.rs - Filing retrieval and processing
- [`rss_feeds.rs`]examples/rss_feeds.rs - Working with RSS/Atom feeds
- [`index_operations.rs`]examples/index_operations.rs - Index file operations

Run any example with:
```bash
cargo run --example basic_usage --all-features
```

## Mini-Projects

EdgarKit includes two standalone CLI tools in the `examples/` directory that demonstrate real-world usage:

### IPO Scanner

Scans recent EDGAR daily indices for S-1 filings (IPOs) and displays them in an interactive terminal UI (TUI).

```bash
# Run from examples/ipo-scanner
cargo run --release -- --weekly
```

### Investment Adviser

A CLI that fetches the latest 10-K/10-Q filings and uses an LLM (via OpenRouter) to generate investment recommendations.

```bash
# Run from examples/investment-adviser
export OPENROUTER_API_KEY="..."
cargo run --release -- --ticker AAPL --model deepseek/deepseek-v3.2
```

## Rate Limiting

EdgarKit automatically handles rate limiting to comply with SEC.gov's fair access policy:

- **Default**: 10 requests per second
- **Configurable**: Adjust via `EdgarConfig`
- **Automatic retry**: Exponential backoff on rate limit errors

```rust
use edgarkit::{Edgar, EdgarConfig, EdgarUrls};
use std::time::Duration;

let config = EdgarConfig {
    user_agent: "MyApp contact@example.com".to_string(),
    rate_limit: 5, // 5 requests per second
    timeout: Duration::from_secs(30),
    base_urls: EdgarUrls::default(),
};

let edgar = Edgar::with_config(config)?;
```

## SEC.gov Compliance

When using EdgarKit, please follow SEC.gov's guidelines:

1. **User Agent Required**: Always provide a descriptive user agent with contact information
2. **Rate Limiting**: Respect the 10 requests/second limit (enforced automatically)
3. **Fair Use**: Avoid excessive bulk downloading during peak hours (9 AM - 5 PM ET)
4. **Terms of Service**: Review [SEC.gov's guidelines]https://www.sec.gov/os/accessing-edgar-data

## Error Handling

EdgarKit provides comprehensive error types:

```rust
use edgarkit::{Edgar, EdgarError, FilingOperations};

match edgar.filings("invalid-cik", None).await {
    Ok(filings) => println!("Found {} filings", filings.len()),
    Err(EdgarError::NotFound) => println!("Company not found"),
    Err(EdgarError::RateLimitExceeded) => println!("Rate limit hit"),
    Err(e) => println!("Error: {}", e),
}
```

## Documentation

Full API documentation is available at [docs.rs/edgarkit](https://docs.rs/edgarkit).

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

### Development Setup

```bash
git clone https://github.com/r007/edgarkit.git
cd edgarkit
cargo build --all-features
cargo test --all-features
```

### Running Tests

```bash
# Run unit tests
cargo test --lib

# Run all tests including integration tests
cargo test --all-features

# Run integration tests separately (requires network)
cargo test --all-features -- --ignored
```

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- Inspired in part by Joey Chilson’s work-in-progress [`edgar_client`]https://github.com/joeychilson/edgar_client (Elixir/Rust). Thanks to Joey for publishing the endpoint URLs and early implementation ideas that helped shape this client; EdgarKit rewrites and extends those concepts in a Rust-first, consistent API.
- Built with [reqwest]https://github.com/seanmonstar/reqwest for HTTP requests
- Rate limiting via [governor]https://github.com/benwis/governor
- XML parsing with [quick-xml]https://github.com/tafia/quick-xml
- Powered by the [tokio]https://tokio.rs/ async runtime

## Author

Created by [Sergey Monin](https://github.com/r007)

## Disclaimer

This library is not affiliated with or endorsed by the U.S. Securities and Exchange Commission. Please ensure your use complies with SEC.gov's terms of service and applicable regulations.

---

Made with ❤️ for the Rust community