finance-query 3.0.0

A Rust library for querying financial data
Documentation
//! Capability traits over a single equity symbol.

use super::super::Operation;
use crate::error::Result;
use crate::models::quote::QuoteSummaryResponse;

use super::ProviderCore;

/// [`crate::Capability::QUOTE`] — single and batch equity quotes.
#[async_trait::async_trait]
pub trait QuoteProvider: ProviderCore {
    /// Fetch every quote module this provider serves for one symbol.
    async fn fetch_quote(&self, symbol: &str) -> Result<QuoteSummaryResponse>;

    /// Fetch quotes for multiple symbols in a single request.
    /// Returns `(symbol, QuoteSummaryResponse)` pairs — only partially populated
    /// (price module only) since batch endpoints don't return full quoteSummary data.
    async fn fetch_quotes_batch(&self, _: &[&str]) -> Result<Vec<(String, QuoteSummaryResponse)>> {
        Err(self.not_supported(Operation::QuotesBatch))
    }

    /// Fetch a snapshot for symbols spanning several asset classes in one
    /// request. Rows the provider could not resolve are returned with
    /// `error` set rather than dropped.
    ///
    /// NOTE: Polygon is the only cross-asset snapshot among the providers
    /// integrated here. The keyless sources are each single-asset-class, so
    /// reproducing this means fanning out per class and inventing a merge.
    async fn fetch_unified_snapshot(
        &self,
        _symbols: &[&str],
    ) -> Result<Vec<crate::models::quote::snapshot::MarketSnapshot>> {
        Err(self.not_supported(Operation::UnifiedSnapshot))
    }
}

/// [`crate::Capability::CHART`] — historical OHLCV candles and sparklines.
#[async_trait::async_trait]
pub trait ChartProvider: ProviderCore {
    /// Fetch OHLCV candles at one interval over one range.
    async fn fetch_chart(
        &self,
        symbol: &str,
        interval: crate::Interval,
        range: crate::TimeRange,
    ) -> Result<crate::models::chart::Chart>;

    /// Fetch OHLCV candles between two Unix timestamps.
    async fn fetch_chart_range(
        &self,
        _symbol: &str,
        _interval: crate::Interval,
        _start: i64,
        _end: i64,
    ) -> Result<crate::models::chart::Chart> {
        Err(self.not_supported(Operation::ChartRange))
    }

    /// Fetch lightweight sparkline data for multiple symbols in a single request.
    /// Returns successfully-parsed `(symbol, Spark)` pairs; callers fill in
    /// missing-symbol errors for any symbol absent from the result.
    async fn fetch_spark(
        &self,
        _symbols: &[&str],
        _interval: crate::Interval,
        _range: crate::TimeRange,
    ) -> Result<Vec<(String, crate::models::chart::spark::Spark)>> {
        Err(self.not_supported(Operation::Spark))
    }

    /// Fetch grouped daily OHLCV bars for every stock ticker on `date`
    /// (`YYYY-MM-DD`) in a single request — market-wide rather than
    /// symbol-scoped. Returns `(symbol, candle)` pairs.
    ///
    /// NOTE: no keyless provider in this crate publishes a market-wide bulk
    /// EOD file for stocks; this stays a Polygon-only capability.
    async fn fetch_grouped_daily(
        &self,
        _date: &str,
    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
        Err(self.not_supported(Operation::GroupedDaily))
    }

    /// Fetch grouped daily OHLCV bars for every crypto ticker on `date`
    /// (`YYYY-MM-DD`) in a single request. Returns `(symbol, candle)` pairs.
    ///
    /// NOTE: Binance's 24hr ticker endpoint covers every symbol in one call
    /// but only as a rolling now-minus-24h window, not an arbitrary
    /// historical `date` — the wrong shape for this operation, so it stays
    /// Polygon-only.
    async fn fetch_crypto_grouped_daily(
        &self,
        _date: &str,
    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
        Err(self.not_supported(Operation::CryptoGroupedDaily))
    }

    /// Fetch grouped daily OHLCV bars for every forex ticker on `date`
    /// (`YYYY-MM-DD`) in a single request. Returns `(symbol, candle)` pairs.
    ///
    /// NOTE: Frankfurter serves every ECB reference rate for a historical
    /// `date` in one call, but only a single daily fixing rate, not OHLCV
    /// candles — the wrong shape for this operation, so it stays
    /// Polygon-only.
    async fn fetch_forex_grouped_daily(
        &self,
        _date: &str,
    ) -> Result<Vec<(String, crate::models::chart::Candle)>> {
        Err(self.not_supported(Operation::ForexGroupedDaily))
    }
}

/// [`crate::Capability::FUNDAMENTALS`] — financial statements and share-supply data.
#[async_trait::async_trait]
pub trait FundamentalsProvider: ProviderCore {
    /// Fetch one financial statement at one reporting frequency.
    async fn fetch_financials(
        &self,
        symbol: &str,
        stmt_type: crate::StatementType,
        frequency: crate::Frequency,
    ) -> Result<crate::models::fundamentals::FinancialStatement>;

    /// Fetch bi-monthly short-interest settlement reports.
    async fn fetch_short_interest(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::fundamentals::ShortInterest>> {
        Err(self.not_supported(Operation::ShortInterest))
    }

    /// Fetch daily short-volume data.
    async fn fetch_short_volume(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::fundamentals::ShortVolume>> {
        Err(self.not_supported(Operation::ShortVolume))
    }

    /// Fetch share float and shares outstanding.
    async fn fetch_share_float(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::ShareFloat> {
        Err(self.not_supported(Operation::ShareFloat))
    }

    /// Fetch the company's identity/classification profile.
    async fn fetch_company_profile(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::CompanyProfile> {
        Err(self.not_supported(Operation::CompanyProfile))
    }

    /// Fetch the aggregated analyst price-target consensus.
    async fn fetch_price_target_consensus(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::PriceTargetConsensus> {
        Err(self.not_supported(Operation::PriceTargetConsensus))
    }

    /// Fetch price-target publication activity over trailing windows.
    ///
    /// NOTE: analyst price targets aren't SEC-filed data — no keyless
    /// provider in this crate publishes trailing-window target-publication
    /// counts, so this stays FMP-only.
    async fn fetch_price_target_summary(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::PriceTargetSummary> {
        Err(self.not_supported(Operation::PriceTargetSummary))
    }

    /// Fetch the aggregated analyst rating consensus.
    async fn fetch_rating_consensus(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::RatingConsensus> {
        Err(self.not_supported(Operation::RatingConsensus))
    }

    /// Fetch the trailing-twelve-month key-metrics snapshot.
    async fn fetch_key_metrics_ttm(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::KeyMetricsTtm> {
        Err(self.not_supported(Operation::KeyMetricsTtm))
    }

    /// Fetch the trailing-twelve-month ratios snapshot.
    async fn fetch_ratios_ttm(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::FinancialRatiosTtm> {
        Err(self.not_supported(Operation::RatiosTtm))
    }

    /// Fetch an ETF's profile and portfolio holdings.
    async fn fetch_etf_profile(
        &self,
        _symbol: &str,
    ) -> Result<crate::models::fundamentals::EtfProfile> {
        Err(self.not_supported(Operation::EtfProfile))
    }

    /// Fetch earnings-surprise history, newest first.
    async fn fetch_earnings_surprises(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::fundamentals::EarningsSurprise>> {
        Err(self.not_supported(Operation::EarningsSurprises))
    }

    /// Fetch the raw per-analyst grade-action history behind
    /// [`fetch_rating_consensus`](Self::fetch_rating_consensus)'s rollup.
    async fn fetch_grading_history(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::fundamentals::GradingAction>> {
        Err(self.not_supported(Operation::GradingHistory))
    }
}

/// [`crate::Capability::CORPORATE`] — news, corporate events, similar-symbol
/// recommendations.
#[async_trait::async_trait]
pub trait CorporateProvider: ProviderCore {
    /// Fetch recent news articles mentioning one symbol.
    async fn fetch_news(&self, symbol: &str) -> Result<Vec<crate::models::corporate::news::News>>;

    /// Fetch dividends, splits, and capital gains for one symbol.
    async fn fetch_events(&self, symbol: &str)
    -> Result<crate::models::chart::events::ChartEvents>;

    /// Symbols this provider considers comparable to `symbol`.
    async fn fetch_similar_symbols(
        &self,
        _symbol: &str,
        _limit: u32,
    ) -> Result<Vec<crate::models::corporate::recommendation::SimilarSymbol>> {
        Err(self.not_supported(Operation::Recommendations))
    }

    /// Fetch the company's own press releases.
    async fn fetch_press_releases(
        &self,
        _symbol: &str,
        _limit: u32,
    ) -> Result<Vec<crate::models::corporate::press_release::PressRelease>> {
        Err(self.not_supported(Operation::PressReleases))
    }

    /// Fetch an earnings call transcript, provider-neutral shape. `quarter`
    /// and `year` narrow to a specific call; a provider with no "latest"
    /// shortcut requires both.
    async fn fetch_earnings_transcript(
        &self,
        _symbol: &str,
        _quarter: Option<&str>,
        _year: Option<i32>,
    ) -> Result<crate::models::corporate::earnings_transcript::EarningsTranscript> {
        Err(self.not_supported(Operation::EarningsTranscript))
    }

    /// Fetch reported executive compensation, most recent fiscal year first.
    async fn fetch_executive_compensation(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::corporate::governance::ExecutiveCompensation>> {
        Err(self.not_supported(Operation::ExecutiveCompensation))
    }

    /// Fetch reported employee headcount history, most recent period first.
    async fn fetch_employee_count(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::corporate::governance::EmployeeCount>> {
        Err(self.not_supported(Operation::EmployeeCount))
    }
}

/// [`crate::Capability::OPTIONS`] — options chains.
#[async_trait::async_trait]
pub trait OptionsProvider: ProviderCore {
    /// Fetch the options chain for one symbol.
    async fn fetch_options(
        &self,
        symbol: &str,
        date: Option<i64>,
    ) -> Result<crate::models::options::Options>;
}

/// [`crate::Capability::FILINGS`] — SEC filing data.
#[async_trait::async_trait]
pub trait FilingsProvider: ProviderCore {
    /// Fetch regulatory filings for one symbol.
    async fn fetch_filings(&self, symbol: &str) -> Result<crate::models::filings::ProviderFilings>;

    /// Fetch the sectioned text of one filing by accession number.
    async fn fetch_filing_sections(
        &self,
        _accession_number: &str,
        _form: crate::models::filings::FilingSectionForm,
    ) -> Result<Vec<crate::models::filings::FilingSection>> {
        Err(self.not_supported(Operation::FilingSections))
    }

    /// Fetch risk factors extracted from a symbol's SEC filings.
    async fn fetch_risk_factors(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::filings::RiskFactor>> {
        Err(self.not_supported(Operation::RiskFactors))
    }

    /// Search filing *text* rather than looking filings up by filer.
    ///
    /// `symbol` scopes the search to one filer; the provider resolves it to
    /// whatever identifier its own index is keyed by (a CIK, for EDGAR).
    /// `None` searches every filer.
    async fn fetch_filing_search(
        &self,
        _symbol: Option<&str>,
        _query: &str,
        _filters: &crate::models::filings::FilingSearchFilters,
    ) -> Result<Vec<crate::models::filings::FilingSearchHit>> {
        Err(self.not_supported(Operation::FilingSearch))
    }

    /// Fetch insider transactions reported on Forms 3/4/5, newest filing first.
    async fn fetch_insider_trades(
        &self,
        _symbol: &str,
        _limit: u32,
    ) -> Result<Vec<crate::models::filings::InsiderTrade>> {
        Err(self.not_supported(Operation::InsiderTrades))
    }

    /// Fetch the latest reported 13F institutional holdings for a filer.
    async fn fetch_institutional_holdings(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::filings::InstitutionalHolding>> {
        Err(self.not_supported(Operation::InstitutionalHoldings))
    }

    /// Fetch congressional (senate) stock-trade disclosures for a symbol.
    async fn fetch_congressional_trades(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::filings::CongressionalTrade>> {
        Err(self.not_supported(Operation::CongressionalTrades))
    }

    /// Fetch SEC fails-to-deliver data for a symbol.
    async fn fetch_fails_to_deliver(
        &self,
        _symbol: &str,
    ) -> Result<Vec<crate::models::filings::FailToDeliver>> {
        Err(self.not_supported(Operation::FailsToDeliver))
    }
}