Skip to content

Multi-Provider Architecture

Finance Query v2.6 introduces a provider abstraction layer that lets you route each data capability (quotes, charts, fundamentals, etc.) to a different provider through a single builder API. The system automatically falls back to the next provider in the list on failure.

Why Multiple Providers?

  • Redundancy — if one provider fails or rate-limits you, the next one takes over
  • Capability coverage — route each data type to the provider with the best coverage for it
  • Flexibility — pick providers based on rate limits, data quality, and budget

Available Providers

Yahoo Finance is always available with no configuration. All others are opt-in via feature flags:

Provider Feature flag Free tier Env var
Yahoo Finance (always available) Keyless
Polygon.io polygon 5 req/sec POLYGON_API_KEY
FMP fmp 250 req/day FMP_API_KEY
Alpha Vantage alphavantage 25 req/day ALPHAVANTAGE_API_KEY
CoinGecko crypto 30 req/min (keyless)
FRED fred 120 req/min FRED_API_KEY
SEC EDGAR (always available) Keyless (email via edgar::init)
[dependencies]
finance-query = { version = "2.6", features = ["polygon", "fmp"] }

Provider Initialization

API keys are read from environment variables automatically during build(). No manual init calls are needed:

export POLYGON_API_KEY="your-polygon-key"
export FMP_API_KEY="your-fmp-key"
export ALPHAVANTAGE_API_KEY="your-av-key"
export FRED_API_KEY="your-fred-key"

EDGAR requires a one-time init

The SEC EDGAR module requires edgar::init("user@example.com")? once per process (SEC policy requires contact info for rate limiting). See EDGAR.

Capability Routing

Use .route(Capability, &[Provider]) on Providers::builder() to assign providers to specific data capabilities, then create handles via providers.ticker(). Providers are tried in order — the first success wins.

use finance_query::{Capability, Fetch, Provider, Providers};

let providers = Providers::builder()
    // Route quotes to Polygon first, Yahoo as fallback
    .route(Capability::QUOTE, &[Provider::Polygon, Provider::Yahoo])
    // Route fundamentals to FMP first, Yahoo as fallback
    .route(Capability::FUNDAMENTALS, &[Provider::Fmp, Provider::Yahoo])
    // Route corporate (news, recommendations) to Polygon only
    .route(Capability::CORPORATE, &[Provider::Polygon])
    .fetch(Fetch::Sequential)
    .build()
    .await?;
let ticker = providers.ticker("AAPL").build().await?;

If no .route() is set for a capability, Yahoo Finance is used by default. EDGAR is auto-injected for FILINGS when no other provider is configured.

Available Capabilities

Capability Constant Description
Quote Capability::QUOTE Price, volume, market cap
Chart Capability::CHART Historical OHLCV data
Fundamentals Capability::FUNDAMENTALS Financial statements
Corporate Capability::CORPORATE News, recommendations, SEC metadata
Options Capability::OPTIONS Options chains
Crypto Capability::CRYPTO Cryptocurrency quotes
Economic Capability::ECONOMIC Macro series (GDP, CPI, etc.)
Forex Capability::FOREX FX currency pair rates
Indices Capability::INDICES Market index quotes
Futures Capability::FUTURES Futures contract quotes
Commodities Capability::COMMODITIES Commodity price quotes
Filings Capability::FILINGS SEC EDGAR filing data

Fetch Strategies

Fetch controls how the provider list is queried:

Strategy Behavior Best for
Fetch::Sequential Try in priority order; first success wins (default) Respecting rate limits, minimizing API calls
Fetch::Parallel Fire all concurrently; first success wins Lowest latency for real-time data
use finance_query::{Capability, Fetch, Provider, Providers};

// Sequential: try Polygon, then Yahoo if Polygon fails
let providers = Providers::builder()
    .route(Capability::QUOTE, &[Provider::Polygon, Provider::Yahoo])
    .fetch(Fetch::Sequential)
    .build()
    .await?;
let ticker = providers.ticker("AAPL").build().await?;

// Parallel: race Polygon against Yahoo, use whichever responds first
let providers = Providers::builder()
    .route(Capability::QUOTE, &[Provider::Polygon, Provider::Yahoo])
    .fetch(Fetch::Parallel)
    .build()
    .await?;
let ticker = providers.ticker("AAPL").build().await?;

Provider Capabilities Matrix

Capabilities supported by each provider. Providers that don't support a given capability are automatically skipped during dispatch.

Capability Yahoo Polygon FMP Alpha Vantage CoinGecko FRED EDGAR
Quote
Chart
Fundamentals
Corporate
Options
Crypto
Economic
Forex
Indices
Futures
Commodities
Filings
Sentiment

Providers Factory (Shared Connections)

For non-equity asset classes, use the Providers factory to create domain handles that share the same provider connections and configuration:

use finance_query::{Providers, Provider, Capability, Fetch};

let providers = Providers::builder()
    .route(Capability::FOREX, &[Provider::AlphaVantage])
    .route(Capability::ECONOMIC, &[Provider::Fred])
    .fetch(Fetch::Sequential)
    .build()
    .await?;

// All handles share the same provider connections
let aapl  = providers.ticker("AAPL").logo().build().await?;   // → Ticker
let pair  = providers.forex("USD", "EUR");                    // → ForexPair
let btc   = providers.crypto("bitcoin");                      // → CryptoCoin
let gdp   = providers.economic("REAL_GDP");                   // → EconomicIndicator
let spy   = providers.index("SPY");                           // → Index
let cl    = providers.futures("CL=F");                        // → FuturesContract
let wheat = providers.commodity("WHEAT");                     // → Commodity
let sec   = providers.filings("AAPL");                        // → Filings

Domain Handle Methods

Handle Method Returns
ForexPair .quote() ForexQuote
CryptoCoin .quote(vs_currency) CryptoQuote
EconomicIndicator .series() EconomicSeries
Index .quote() IndexQuote
FuturesContract .quote() FuturesQuote
Commodity .quote() CommodityQuote
Filings .get() ProviderFilings

Tickers and Providers

Tickers supports the same multi-provider configuration as Ticker. Routing is configured through Providers::builder() and passed to Tickers via providers.tickers():

use finance_query::{Capability, Fetch, Provider, Providers};

let providers = Providers::builder()
    .route(Capability::QUOTE, &[Provider::Polygon, Provider::Yahoo])
    .fetch(Fetch::Sequential)
    .build()
    .await?;
let tickers = providers.tickers(["AAPL", "NVDA"]).build().await?;

Spark is Yahoo-only

spark() uses a Yahoo-specific batch endpoint with no equivalent in other providers. It always uses the Yahoo client regardless of provider configuration.

Provider Pages

Provider Documentation
Polygon.io Polygon.io
FMP Financial Modeling Prep
Alpha Vantage Alpha Vantage
CoinGecko Crypto (CoinGecko)
FRED FRED & Treasury
SEC EDGAR EDGAR SEC Filings