borsa_core/
connector.rs

1use async_trait::async_trait;
2
3use crate::BorsaError;
4use paft::domain::{AssetKind, Instrument, Isin};
5use paft::fundamentals::analysis::{
6    Earnings, PriceTarget, RecommendationRow, RecommendationSummary, UpgradeDowngradeRow,
7};
8use paft::fundamentals::esg::EsgScores;
9use paft::fundamentals::holders::{
10    InsiderRosterHolder, InsiderTransaction, InstitutionalHolder, MajorHolder,
11    NetSharePurchaseActivity,
12};
13use paft::fundamentals::profile::Profile;
14use paft::fundamentals::statements::{BalanceSheetRow, Calendar, CashflowRow, IncomeStatementRow};
15use paft::market::news::NewsArticle;
16use paft::market::options::OptionChain;
17use paft::market::quote::{Quote, QuoteUpdate};
18use paft::market::requests::history::{HistoryRequest, Interval};
19use paft::market::requests::news::NewsRequest;
20use paft::market::requests::search::SearchRequest;
21use paft::market::responses::history::HistoryResponse;
22use paft::market::responses::search::SearchResponse;
23
24/// Typed key for identifying connectors in priority configuration.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub struct ConnectorKey(pub &'static str);
27
28impl ConnectorKey {
29    /// Construct a new typed connector key from a static name.
30    ///
31    /// This is useful when configuring per-kind or per-symbol priorities.
32    #[must_use]
33    pub const fn new(name: &'static str) -> Self {
34        Self(name)
35    }
36
37    /// Returns the inner static string.
38    #[must_use]
39    pub const fn as_str(self) -> &'static str {
40        self.0
41    }
42}
43
44impl From<ConnectorKey> for &'static str {
45    fn from(k: ConnectorKey) -> Self {
46        k.0
47    }
48}
49
50/// Focused role trait for connectors that provide OHLCV history.
51#[async_trait]
52pub trait HistoryProvider: Send + Sync {
53    /// Fetch OHLCV history and actions for the given instrument and request.
54    async fn history(
55        &self,
56        instrument: &Instrument,
57        req: HistoryRequest,
58    ) -> Result<HistoryResponse, BorsaError>;
59
60    /// REQUIRED: exact intervals this connector can natively serve for history.
61    ///
62    /// Parameters:
63    /// - `kind`: asset kind to consider (some providers vary by kind).
64    ///
65    /// Returns the static slice of supported `Interval`s.
66    fn supported_history_intervals(&self, kind: AssetKind) -> &'static [Interval];
67}
68
69/// Focused role trait for connectors that provide quotes.
70#[async_trait]
71pub trait QuoteProvider: Send + Sync {
72    /// Fetch a point-in-time quote for the given instrument.
73    async fn quote(&self, instrument: &Instrument) -> Result<Quote, BorsaError>;
74}
75
76// Granular role traits
77/// Focused role trait for connectors that provide earnings fundamentals.
78#[async_trait]
79pub trait EarningsProvider: Send + Sync {
80    /// Fetch earnings for the given instrument.
81    async fn earnings(&self, instrument: &Instrument) -> Result<Earnings, BorsaError>;
82}
83
84/// Focused role trait for connectors that provide income statements.
85#[async_trait]
86pub trait IncomeStatementProvider: Send + Sync {
87    /// Fetch income statement rows for the given instrument.
88    async fn income_statement(
89        &self,
90        instrument: &Instrument,
91        quarterly: bool,
92    ) -> Result<Vec<IncomeStatementRow>, BorsaError>;
93}
94
95/// Focused role trait for connectors that provide balance sheets.
96#[async_trait]
97pub trait BalanceSheetProvider: Send + Sync {
98    /// Fetch balance sheet rows for the given instrument.
99    async fn balance_sheet(
100        &self,
101        instrument: &Instrument,
102        quarterly: bool,
103    ) -> Result<Vec<BalanceSheetRow>, BorsaError>;
104}
105
106/// Focused role trait for connectors that provide cashflow statements.
107#[async_trait]
108pub trait CashflowProvider: Send + Sync {
109    /// Fetch cashflow rows for the given instrument.
110    async fn cashflow(
111        &self,
112        instrument: &Instrument,
113        quarterly: bool,
114    ) -> Result<Vec<CashflowRow>, BorsaError>;
115}
116
117/// Focused role trait for connectors that provide corporate event calendars.
118#[async_trait]
119pub trait CalendarProvider: Send + Sync {
120    /// Fetch the fundamentals calendar for the given instrument.
121    async fn calendar(&self, instrument: &Instrument) -> Result<Calendar, BorsaError>;
122}
123
124/// Focused role trait for connectors that provide analyst recommendations.
125#[async_trait]
126pub trait RecommendationsProvider: Send + Sync {
127    /// Fetch recommendation rows for the given instrument.
128    async fn recommendations(
129        &self,
130        instrument: &Instrument,
131    ) -> Result<Vec<RecommendationRow>, BorsaError>;
132}
133
134/// Focused role trait for connectors that provide an aggregate recommendations summary.
135#[async_trait]
136pub trait RecommendationsSummaryProvider: Send + Sync {
137    /// Fetch a recommendations summary for the given instrument.
138    async fn recommendations_summary(
139        &self,
140        instrument: &Instrument,
141    ) -> Result<RecommendationSummary, BorsaError>;
142}
143
144/// Focused role trait for connectors that provide upgrades/downgrades history.
145#[async_trait]
146pub trait UpgradesDowngradesProvider: Send + Sync {
147    /// Fetch upgrade/downgrade rows for the given instrument.
148    async fn upgrades_downgrades(
149        &self,
150        instrument: &Instrument,
151    ) -> Result<Vec<UpgradeDowngradeRow>, BorsaError>;
152}
153
154/// Focused role trait for connectors that provide analyst price targets.
155#[async_trait]
156pub trait AnalystPriceTargetProvider: Send + Sync {
157    /// Fetch the current analyst price target for the given instrument.
158    async fn analyst_price_target(
159        &self,
160        instrument: &Instrument,
161    ) -> Result<PriceTarget, BorsaError>;
162}
163
164/// Focused role trait for connectors that provide major holder breakdowns.
165#[async_trait]
166pub trait MajorHoldersProvider: Send + Sync {
167    /// Fetch major holder rows for the given instrument.
168    async fn major_holders(&self, instrument: &Instrument) -> Result<Vec<MajorHolder>, BorsaError>;
169}
170
171/// Focused role trait for connectors that provide institutional holders.
172#[async_trait]
173pub trait InstitutionalHoldersProvider: Send + Sync {
174    /// Fetch institutional holder rows for the given instrument.
175    async fn institutional_holders(
176        &self,
177        instrument: &Instrument,
178    ) -> Result<Vec<InstitutionalHolder>, BorsaError>;
179}
180
181/// Focused role trait for connectors that provide mutual fund holders.
182#[async_trait]
183pub trait MutualFundHoldersProvider: Send + Sync {
184    /// Fetch mutual fund holder rows for the given instrument.
185    async fn mutual_fund_holders(
186        &self,
187        instrument: &Instrument,
188    ) -> Result<Vec<InstitutionalHolder>, BorsaError>;
189}
190
191/// Focused role trait for connectors that provide insider transaction events.
192#[async_trait]
193pub trait InsiderTransactionsProvider: Send + Sync {
194    /// Fetch insider transactions for the given instrument.
195    async fn insider_transactions(
196        &self,
197        instrument: &Instrument,
198    ) -> Result<Vec<InsiderTransaction>, BorsaError>;
199}
200
201/// Focused role trait for connectors that provide insider roster holders.
202#[async_trait]
203pub trait InsiderRosterHoldersProvider: Send + Sync {
204    /// Fetch insider roster holders for the given instrument.
205    async fn insider_roster_holders(
206        &self,
207        instrument: &Instrument,
208    ) -> Result<Vec<InsiderRosterHolder>, BorsaError>;
209}
210
211/// Focused role trait for connectors that provide net share purchase activity.
212#[async_trait]
213pub trait NetSharePurchaseActivityProvider: Send + Sync {
214    /// Fetch net share purchase activity for the given instrument, if any.
215    async fn net_share_purchase_activity(
216        &self,
217        instrument: &Instrument,
218    ) -> Result<Option<NetSharePurchaseActivity>, BorsaError>;
219}
220
221/// Focused role trait for connectors that provide company profile data.
222#[async_trait]
223pub trait ProfileProvider: Send + Sync {
224    /// Fetch a profile for the given instrument.
225    async fn profile(&self, instrument: &Instrument) -> Result<Profile, BorsaError>;
226}
227
228/// Focused role trait for connectors that provide ISIN lookup.
229#[async_trait]
230pub trait IsinProvider: Send + Sync {
231    /// Fetch an ISIN string for the given instrument, if available.
232    async fn isin(&self, instrument: &Instrument) -> Result<Option<Isin>, BorsaError>;
233}
234
235/// Focused role trait for connectors that can search instruments.
236#[async_trait]
237pub trait SearchProvider: Send + Sync {
238    /// Perform a symbol search according to the provided request.
239    async fn search(&self, req: SearchRequest) -> Result<SearchResponse, BorsaError>;
240}
241
242/// Focused role trait for connectors that provide ESG scores.
243#[async_trait]
244pub trait EsgProvider: Send + Sync {
245    /// Fetch ESG scores for the given instrument.
246    async fn sustainability(&self, instrument: &Instrument) -> Result<EsgScores, BorsaError>;
247}
248
249/// Focused role trait for connectors that provide news articles.
250#[async_trait]
251pub trait NewsProvider: Send + Sync {
252    /// Fetch news articles for the given instrument.
253    async fn news(
254        &self,
255        instrument: &Instrument,
256        req: NewsRequest,
257    ) -> Result<Vec<NewsArticle>, BorsaError>;
258}
259
260/// Focused role trait for connectors that provide streaming quote updates.
261#[async_trait]
262pub trait StreamProvider: Send + Sync {
263    /// Start a streaming session for the given instruments.
264    async fn stream_quotes(
265        &self,
266        instruments: &[Instrument],
267    ) -> Result<
268        (
269            crate::stream::StreamHandle,
270            tokio::sync::mpsc::Receiver<QuoteUpdate>,
271        ),
272        BorsaError,
273    >;
274}
275
276/// Focused role trait for connectors that provide options expirations.
277#[async_trait]
278pub trait OptionsExpirationsProvider: Send + Sync {
279    /// Fetch a list of option expiration timestamps for the given instrument.
280    async fn options_expirations(&self, instrument: &Instrument) -> Result<Vec<i64>, BorsaError>;
281}
282
283/// Focused role trait for connectors that provide option chains.
284#[async_trait]
285pub trait OptionChainProvider: Send + Sync {
286    /// Fetch an option chain for the given instrument and optional expiration date.
287    async fn option_chain(
288        &self,
289        instrument: &Instrument,
290        date: Option<i64>,
291    ) -> Result<OptionChain, BorsaError>;
292}
293
294/// Main connector trait implemented by provider crates. Exposes capability discovery.
295#[async_trait]
296pub trait BorsaConnector: Send + Sync {
297    /// A stable identifier for priority lists (e.g., "borsa-yfinance", "borsa-coinmarketcap").
298    fn name(&self) -> &'static str;
299
300    /// Human-friendly vendor string.
301    fn vendor(&self) -> &'static str {
302        "unknown"
303    }
304
305    /// Whether this connector *claims* to support a given asset kind.
306    ///
307    /// Default: returns `false` for all kinds. Connectors must explicitly override
308    /// this method to declare which asset kinds they support.
309    fn supports_kind(&self, kind: AssetKind) -> bool {
310        let _ = kind;
311        false
312    }
313
314    /// Advertise history capability by returning a usable trait object reference when supported.
315    fn as_history_provider(&self) -> Option<&dyn HistoryProvider> {
316        None
317    }
318
319    /// Advertise quote capability by returning a usable trait object reference when supported.
320    fn as_quote_provider(&self) -> Option<&dyn QuoteProvider> {
321        None
322    }
323
324    /// If implemented, returns a trait object for earnings fundamentals.
325    fn as_earnings_provider(&self) -> Option<&dyn EarningsProvider> {
326        None
327    }
328    /// If implemented, returns a trait object for income statements.
329    fn as_income_statement_provider(&self) -> Option<&dyn IncomeStatementProvider> {
330        None
331    }
332    /// If implemented, returns a trait object for balance sheets.
333    fn as_balance_sheet_provider(&self) -> Option<&dyn BalanceSheetProvider> {
334        None
335    }
336    /// If implemented, returns a trait object for cashflow statements.
337    fn as_cashflow_provider(&self) -> Option<&dyn CashflowProvider> {
338        None
339    }
340    /// If implemented, returns a trait object for the fundamentals calendar.
341    fn as_calendar_provider(&self) -> Option<&dyn CalendarProvider> {
342        None
343    }
344
345    /// If implemented, returns a trait object for analyst recommendations.
346    fn as_recommendations_provider(&self) -> Option<&dyn RecommendationsProvider> {
347        None
348    }
349    /// If implemented, returns a trait object for recommendations summary.
350    fn as_recommendations_summary_provider(&self) -> Option<&dyn RecommendationsSummaryProvider> {
351        None
352    }
353    /// If implemented, returns a trait object for upgrades/downgrades.
354    fn as_upgrades_downgrades_provider(&self) -> Option<&dyn UpgradesDowngradesProvider> {
355        None
356    }
357    /// If implemented, returns a trait object for analyst price targets.
358    fn as_analyst_price_target_provider(&self) -> Option<&dyn AnalystPriceTargetProvider> {
359        None
360    }
361
362    /// If implemented, returns a trait object for major holders.
363    fn as_major_holders_provider(&self) -> Option<&dyn MajorHoldersProvider> {
364        None
365    }
366    /// If implemented, returns a trait object for institutional holders.
367    fn as_institutional_holders_provider(&self) -> Option<&dyn InstitutionalHoldersProvider> {
368        None
369    }
370    /// If implemented, returns a trait object for mutual fund holders.
371    fn as_mutual_fund_holders_provider(&self) -> Option<&dyn MutualFundHoldersProvider> {
372        None
373    }
374    /// If implemented, returns a trait object for insider transactions.
375    fn as_insider_transactions_provider(&self) -> Option<&dyn InsiderTransactionsProvider> {
376        None
377    }
378    /// If implemented, returns a trait object for insider roster holders.
379    fn as_insider_roster_holders_provider(&self) -> Option<&dyn InsiderRosterHoldersProvider> {
380        None
381    }
382    /// If implemented, returns a trait object for net share purchase activity.
383    fn as_net_share_purchase_activity_provider(
384        &self,
385    ) -> Option<&dyn NetSharePurchaseActivityProvider> {
386        None
387    }
388
389    /// If implemented, returns a trait object for company profiles.
390    fn as_profile_provider(&self) -> Option<&dyn ProfileProvider> {
391        None
392    }
393    /// If implemented, returns a trait object for ISIN lookup.
394    fn as_isin_provider(&self) -> Option<&dyn IsinProvider> {
395        None
396    }
397    /// If implemented, returns a trait object for instrument search.
398    fn as_search_provider(&self) -> Option<&dyn SearchProvider> {
399        None
400    }
401    /// If implemented, returns a trait object for ESG scores.
402    fn as_esg_provider(&self) -> Option<&dyn EsgProvider> {
403        None
404    }
405    /// If implemented, returns a trait object for news articles.
406    fn as_news_provider(&self) -> Option<&dyn NewsProvider> {
407        None
408    }
409
410    /// If implemented, returns a trait object for options expirations.
411    fn as_options_expirations_provider(&self) -> Option<&dyn OptionsExpirationsProvider> {
412        None
413    }
414    /// If implemented, returns a trait object for option chains.
415    fn as_option_chain_provider(&self) -> Option<&dyn OptionChainProvider> {
416        None
417    }
418
419    /// If implemented, returns a trait object for quote streaming.
420    fn as_stream_provider(&self) -> Option<&dyn StreamProvider> {
421        None
422    }
423}