webull_rs/endpoints/
market_data.rs

1use crate::auth::AuthManager;
2use crate::endpoints::base::BaseEndpoint;
3use crate::error::WebullResult;
4use crate::models::market::{
5    Bar, BarQueryParams, CorpActionEventType, CorpActionParams, EodBarsParams, Instrument,
6    InstrumentParams, NewsArticle, NewsQueryParams, OptionChain, OptionChainQueryParams, Quote,
7    SnapshotParams, TimeFrame,
8};
9use reqwest::Client;
10use serde::Serialize;
11use std::sync::Arc;
12
13/// Endpoints for market data operations.
14pub struct MarketDataEndpoints {
15    /// Base endpoint
16    base: BaseEndpoint,
17}
18
19impl MarketDataEndpoints {
20    /// Create new market data endpoints.
21    pub fn new(client: Client, base_url: String, auth_manager: Arc<AuthManager>) -> Self {
22        Self {
23            base: BaseEndpoint::new(client, base_url, auth_manager),
24        }
25    }
26
27    /// Get a real-time quote for a symbol.
28    pub async fn get_quote(&self, symbol: &str) -> WebullResult<Quote> {
29        let path = format!("/api/quote/tickerRealTimes/{}", symbol);
30        self.base.get(&path).await
31    }
32
33    /// Get real-time quotes for multiple symbols.
34    pub async fn get_quotes(&self, symbols: &[&str]) -> WebullResult<Vec<Quote>> {
35        #[derive(Serialize)]
36        struct SymbolsRequest<'a> {
37            symbols: Vec<&'a str>,
38        }
39
40        let request = SymbolsRequest {
41            symbols: symbols.to_vec(),
42        };
43
44        self.base.post("/api/quote/tickerRealTimes", &request).await
45    }
46
47    /// Get snapshot data for symbols.
48    pub async fn get_snapshot(&self, params: &SnapshotParams) -> WebullResult<Vec<Quote>> {
49        self.base.post("/api/quote/snapshot", params).await
50    }
51
52    /// Helper method to get snapshot for a single stock symbol.
53    pub async fn get_stock_snapshot(&self, symbol: &str) -> WebullResult<Vec<Quote>> {
54        let params = SnapshotParams::new_stock(symbol);
55        self.get_snapshot(&params).await
56    }
57
58    /// Helper method to get snapshot for multiple stock symbols.
59    pub async fn get_stock_snapshots(&self, symbols: &[&str]) -> WebullResult<Vec<Quote>> {
60        let params = SnapshotParams::new_stocks(symbols);
61        self.get_snapshot(&params).await
62    }
63
64    /// Get historical bar data for a symbol.
65    pub async fn get_history_bar(&self, params: &BarQueryParams) -> WebullResult<Vec<Bar>> {
66        self.base.post("/api/quote/history/bars", params).await
67    }
68
69    /// Get option chain for a symbol.
70    pub async fn get_option_chain(
71        &self,
72        params: &OptionChainQueryParams,
73    ) -> WebullResult<OptionChain> {
74        self.base.post("/api/options/list", params).await
75    }
76
77    /// Get market news.
78    pub async fn get_news(&self, params: &NewsQueryParams) -> WebullResult<Vec<NewsArticle>> {
79        self.base.post("/api/securities/news/list", params).await
80    }
81
82    /// Get market calendar.
83    pub async fn get_market_calendar(&self) -> WebullResult<Vec<String>> {
84        self.base.get("/api/securities/financial/calendar").await
85    }
86
87    /// Get instrument information.
88    pub async fn get_instrument(&self, params: &InstrumentParams) -> WebullResult<Vec<Instrument>> {
89        self.base.post("/api/quote/instruments", params).await
90    }
91
92    /// Helper method to get instrument information for a single stock symbol.
93    pub async fn get_stock_instrument(&self, symbol: &str) -> WebullResult<Vec<Instrument>> {
94        let params = InstrumentParams::new_stock(symbol);
95        self.get_instrument(&params).await
96    }
97
98    /// Helper method to get instrument information for multiple stock symbols.
99    pub async fn get_stock_instruments(&self, symbols: &[&str]) -> WebullResult<Vec<Instrument>> {
100        let params = InstrumentParams::new_stocks(symbols);
101        self.get_instrument(&params).await
102    }
103
104    /// Get end-of-day bars for instruments.
105    /// Only available for Webull JP.
106    pub async fn get_eod_bar(&self, params: &EodBarsParams) -> WebullResult<Vec<Bar>> {
107        self.base.post("/api/quote/eod/bars", params).await
108    }
109
110    /// Helper method to get end-of-day bars for an instrument.
111    pub async fn get_instrument_eod_bars(
112        &self,
113        instrument_id: &str,
114        count: u32,
115    ) -> WebullResult<Vec<Bar>> {
116        let params = EodBarsParams::new(instrument_id, count);
117        self.get_eod_bar(&params).await
118    }
119
120    /// Helper method to get end-of-day bars for an instrument with a specific date.
121    pub async fn get_instrument_eod_bars_with_date(
122        &self,
123        instrument_id: &str,
124        date: &str,
125        count: u32,
126    ) -> WebullResult<Vec<Bar>> {
127        let params = EodBarsParams::new(instrument_id, count).date(date);
128        self.get_eod_bar(&params).await
129    }
130
131    /// Get corporate actions for instruments.
132    /// Only available for Webull JP.
133    pub async fn get_corp_action(
134        &self,
135        params: &CorpActionParams,
136    ) -> WebullResult<Vec<Instrument>> {
137        self.base.post("/api/quote/corp/action", params).await
138    }
139
140    /// Helper method to get stock split corporate actions for an instrument.
141    pub async fn get_stock_splits(&self, instrument_id: &str) -> WebullResult<Vec<Instrument>> {
142        let params = CorpActionParams::new(instrument_id, vec![CorpActionEventType::Split]);
143        self.get_corp_action(&params).await
144    }
145
146    /// Helper method to get reverse stock split corporate actions for an instrument.
147    pub async fn get_reverse_stock_splits(
148        &self,
149        instrument_id: &str,
150    ) -> WebullResult<Vec<Instrument>> {
151        let params = CorpActionParams::new(instrument_id, vec![CorpActionEventType::ReverseSplit]);
152        self.get_corp_action(&params).await
153    }
154
155    /// Helper method to get all corporate actions for an instrument.
156    pub async fn get_all_corp_actions(&self, instrument_id: &str) -> WebullResult<Vec<Instrument>> {
157        let params = CorpActionParams::new(
158            instrument_id,
159            vec![
160                CorpActionEventType::Split,
161                CorpActionEventType::ReverseSplit,
162            ],
163        );
164        self.get_corp_action(&params).await
165    }
166
167    /// Helper method to get daily bars for a symbol.
168    pub async fn get_daily_bars(&self, symbol: &str, count: Option<u32>) -> WebullResult<Vec<Bar>> {
169        let params = if let Some(count) = count {
170            BarQueryParams::new(symbol, "STK", TimeFrame::Day1, count)
171        } else {
172            BarQueryParams::new_stock(symbol, TimeFrame::Day1)
173        };
174
175        self.get_history_bar(&params).await
176    }
177
178    /// Helper method to get intraday bars for a symbol.
179    pub async fn get_intraday_bars(
180        &self,
181        symbol: &str,
182        time_frame: TimeFrame,
183        count: Option<u32>,
184    ) -> WebullResult<Vec<Bar>> {
185        let params = if let Some(count) = count {
186            BarQueryParams::new(symbol, "STK", time_frame, count)
187        } else {
188            BarQueryParams::new_stock(symbol, time_frame)
189        };
190
191        self.get_history_bar(&params).await
192    }
193}