An unofficial Rust client for the SEC EDGAR (Electronic Data Gathering, Analysis, and Retrieval) system.
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.
- 🚦 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
Add EdgarKit to your Cargo.toml:
[dependencies]
edgarkit = "0.1.0"
tokio = { version = "1", features = ["full"] }EdgarKit uses feature flags to allow you to compile only what you need:
[dependencies]
edgarkit = { version = "0.1.0", features = ["search", "filings", "company"] }Available features:
search- Search API functionality (requiresserde_urlencoded,futures)filings- Filing operations (requiresflate2,chrono)company- Company information APIs (requireschrono)feeds- RSS/Atom feed support (requiresquick-xml)index- Index file operations (requiresflate2,chrono,regex)
Default features: ["search", "filings", "company", "feeds", "index"] (all features enabled)
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(())
}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
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 like1.01, 2.03, 5.01indicate significant agreements, creation of liabilities, or a change in control of registrant (5.01).is_xbrlvsis_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
FilingOptionsto 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.
crabrl: High-performance XBRL parser and validator for financial statements. Parse us-gaap concepts at scale. https://crates.io/crates/crabrlquick-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-xmlrig.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/
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.
Examples are provided in the examples/ directory to keep this README concise.
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(())
}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(())
}Check out the examples/ directory for comprehensive examples:
basic_usage.rs- Getting started with EdgarKitsearch_filings.rs- Advanced search patternsdownload_filings.rs- Filing retrieval and processingrss_feeds.rs- Working with RSS/Atom feedsindex_operations.rs- Index file operations
Run any example with:
cargo run --example basic_usage --all-featuresEdgarKit includes two standalone CLI tools in the examples/ directory that demonstrate real-world usage:
Scans recent EDGAR daily indices for S-1 filings (IPOs) and displays them in an interactive terminal UI (TUI).
# Run from examples/ipo-scanner
cargo run --release -- --weeklyA CLI that fetches the latest 10-K/10-Q filings and uses an LLM (via OpenRouter) to generate investment recommendations.
# Run from examples/investment-adviser
export OPENROUTER_API_KEY="..."
cargo run --release -- --ticker AAPL --model deepseek/deepseek-v3.2EdgarKit 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
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)?;When using EdgarKit, please follow SEC.gov's guidelines:
- User Agent Required: Always provide a descriptive user agent with contact information
- Rate Limiting: Respect the 10 requests/second limit (enforced automatically)
- Fair Use: Avoid excessive bulk downloading during peak hours (9 AM - 5 PM ET)
- Terms of Service: Review SEC.gov's guidelines
EdgarKit provides comprehensive error types:
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),
}Full API documentation is available at docs.rs/edgarkit.
Contributions are welcome! Please feel free to submit a Pull Request.
git clone https://github.com/r007/edgarkit.git
cd edgarkit
cargo build --all-features
cargo test --all-features# 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 -- --ignoredThis project is licensed under the MIT License - see the LICENSE file for details.
- Inspired in part by Joey Chilson’s work-in-progress
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 for HTTP requests
- Rate limiting via governor
- XML parsing with quick-xml
- Powered by the tokio async runtime
Created by Sergey Monin
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
