Skip to main content

alpaca_data/stocks/
client.rs

1use std::fmt;
2use std::sync::Arc;
3
4use alpaca_http::RequestParts;
5use reqwest::Method;
6use serde::de::DeserializeOwned;
7
8use crate::{Error, client::ClientInner, pagination};
9
10use super::{
11    AuctionsRequest, AuctionsResponse, AuctionsSingleRequest, AuctionsSingleResponse, BarsRequest,
12    BarsResponse, BarsSingleRequest, BarsSingleResponse, ConditionCodesRequest,
13    ConditionCodesResponse, ExchangeCodesResponse, LatestBarRequest, LatestBarResponse,
14    LatestBarsRequest, LatestBarsResponse, LatestQuoteRequest, LatestQuoteResponse,
15    LatestQuotesRequest, LatestQuotesResponse, LatestTradeRequest, LatestTradeResponse,
16    LatestTradesRequest, LatestTradesResponse, QuotesRequest, QuotesResponse, QuotesSingleRequest,
17    QuotesSingleResponse, SnapshotRequest, SnapshotResponse, SnapshotsRequest, SnapshotsResponse,
18    TradesRequest, TradesResponse, TradesSingleRequest, TradesSingleResponse,
19};
20
21#[derive(Clone)]
22pub struct StocksClient {
23    inner: Arc<ClientInner>,
24}
25
26impl StocksClient {
27    pub(crate) fn new(inner: Arc<ClientInner>) -> Self {
28        Self { inner }
29    }
30
31    pub async fn bars(&self, request: BarsRequest) -> Result<BarsResponse, Error> {
32        request.validate()?;
33        self.get_json("stocks.bars", "/v2/stocks/bars", request.into_query())
34            .await
35    }
36
37    pub async fn bars_all(&self, request: BarsRequest) -> Result<BarsResponse, Error> {
38        let client = self.clone();
39        pagination::collect_all(request, move |request| {
40            let client = client.clone();
41            async move { client.bars(request).await }
42        })
43        .await
44    }
45
46    pub async fn bars_single(
47        &self,
48        request: BarsSingleRequest,
49    ) -> Result<BarsSingleResponse, Error> {
50        request.validate()?;
51        let path = format!("/v2/stocks/{}/bars", request.symbol);
52        self.get_json("stocks.bars_single", path, request.into_query())
53            .await
54    }
55
56    pub async fn bars_single_all(
57        &self,
58        request: BarsSingleRequest,
59    ) -> Result<BarsSingleResponse, Error> {
60        let client = self.clone();
61        pagination::collect_all(request, move |request| {
62            let client = client.clone();
63            async move { client.bars_single(request).await }
64        })
65        .await
66    }
67
68    pub async fn auctions(&self, request: AuctionsRequest) -> Result<AuctionsResponse, Error> {
69        request.validate()?;
70        self.get_json(
71            "stocks.auctions",
72            "/v2/stocks/auctions",
73            request.into_query(),
74        )
75        .await
76    }
77
78    pub async fn auctions_all(&self, request: AuctionsRequest) -> Result<AuctionsResponse, Error> {
79        let client = self.clone();
80        pagination::collect_all(request, move |request| {
81            let client = client.clone();
82            async move { client.auctions(request).await }
83        })
84        .await
85    }
86
87    pub async fn auctions_single(
88        &self,
89        request: AuctionsSingleRequest,
90    ) -> Result<AuctionsSingleResponse, Error> {
91        request.validate()?;
92        let path = format!("/v2/stocks/{}/auctions", request.symbol);
93        self.get_json("stocks.auctions_single", path, request.into_query())
94            .await
95    }
96
97    pub async fn auctions_single_all(
98        &self,
99        request: AuctionsSingleRequest,
100    ) -> Result<AuctionsSingleResponse, Error> {
101        let client = self.clone();
102        pagination::collect_all(request, move |request| {
103            let client = client.clone();
104            async move { client.auctions_single(request).await }
105        })
106        .await
107    }
108
109    pub async fn quotes(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
110        request.validate()?;
111        self.get_json("stocks.quotes", "/v2/stocks/quotes", request.into_query())
112            .await
113    }
114
115    pub async fn quotes_all(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
116        let client = self.clone();
117        pagination::collect_all(request, move |request| {
118            let client = client.clone();
119            async move { client.quotes(request).await }
120        })
121        .await
122    }
123
124    pub async fn quotes_single(
125        &self,
126        request: QuotesSingleRequest,
127    ) -> Result<QuotesSingleResponse, Error> {
128        request.validate()?;
129        let path = format!("/v2/stocks/{}/quotes", request.symbol);
130        self.get_json("stocks.quotes_single", path, request.into_query())
131            .await
132    }
133
134    pub async fn quotes_single_all(
135        &self,
136        request: QuotesSingleRequest,
137    ) -> Result<QuotesSingleResponse, Error> {
138        let client = self.clone();
139        pagination::collect_all(request, move |request| {
140            let client = client.clone();
141            async move { client.quotes_single(request).await }
142        })
143        .await
144    }
145
146    pub async fn trades(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
147        request.validate()?;
148        self.get_json("stocks.trades", "/v2/stocks/trades", request.into_query())
149            .await
150    }
151
152    pub async fn trades_all(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
153        let client = self.clone();
154        pagination::collect_all(request, move |request| {
155            let client = client.clone();
156            async move { client.trades(request).await }
157        })
158        .await
159    }
160
161    pub async fn trades_single(
162        &self,
163        request: TradesSingleRequest,
164    ) -> Result<TradesSingleResponse, Error> {
165        request.validate()?;
166        let path = format!("/v2/stocks/{}/trades", request.symbol);
167        self.get_json("stocks.trades_single", path, request.into_query())
168            .await
169    }
170
171    pub async fn trades_single_all(
172        &self,
173        request: TradesSingleRequest,
174    ) -> Result<TradesSingleResponse, Error> {
175        let client = self.clone();
176        pagination::collect_all(request, move |request| {
177            let client = client.clone();
178            async move { client.trades_single(request).await }
179        })
180        .await
181    }
182
183    pub async fn latest_bars(
184        &self,
185        request: LatestBarsRequest,
186    ) -> Result<LatestBarsResponse, Error> {
187        request.validate()?;
188        self.get_json(
189            "stocks.latest_bars",
190            "/v2/stocks/bars/latest",
191            request.into_query(),
192        )
193        .await
194    }
195
196    pub async fn latest_bar(&self, request: LatestBarRequest) -> Result<LatestBarResponse, Error> {
197        request.validate()?;
198        let path = format!("/v2/stocks/{}/bars/latest", request.symbol);
199        self.get_json("stocks.latest_bar", path, request.into_query())
200            .await
201    }
202
203    pub async fn latest_quotes(
204        &self,
205        request: LatestQuotesRequest,
206    ) -> Result<LatestQuotesResponse, Error> {
207        request.validate()?;
208        self.get_json(
209            "stocks.latest_quotes",
210            "/v2/stocks/quotes/latest",
211            request.into_query(),
212        )
213        .await
214    }
215
216    pub async fn latest_quote(
217        &self,
218        request: LatestQuoteRequest,
219    ) -> Result<LatestQuoteResponse, Error> {
220        request.validate()?;
221        let path = format!("/v2/stocks/{}/quotes/latest", request.symbol);
222        self.get_json("stocks.latest_quote", path, request.into_query())
223            .await
224    }
225
226    pub async fn latest_trades(
227        &self,
228        request: LatestTradesRequest,
229    ) -> Result<LatestTradesResponse, Error> {
230        request.validate()?;
231        self.get_json(
232            "stocks.latest_trades",
233            "/v2/stocks/trades/latest",
234            request.into_query(),
235        )
236        .await
237    }
238
239    pub async fn latest_trade(
240        &self,
241        request: LatestTradeRequest,
242    ) -> Result<LatestTradeResponse, Error> {
243        request.validate()?;
244        let path = format!("/v2/stocks/{}/trades/latest", request.symbol);
245        self.get_json("stocks.latest_trade", path, request.into_query())
246            .await
247    }
248
249    pub async fn snapshots(&self, request: SnapshotsRequest) -> Result<SnapshotsResponse, Error> {
250        request.validate()?;
251        self.get_json(
252            "stocks.snapshots",
253            "/v2/stocks/snapshots",
254            request.into_query(),
255        )
256        .await
257    }
258
259    pub async fn snapshot(&self, request: SnapshotRequest) -> Result<SnapshotResponse, Error> {
260        request.validate()?;
261        let path = format!("/v2/stocks/{}/snapshot", request.symbol);
262        self.get_json("stocks.snapshot", path, request.into_query())
263            .await
264    }
265
266    pub async fn condition_codes(
267        &self,
268        request: ConditionCodesRequest,
269    ) -> Result<ConditionCodesResponse, Error> {
270        let path = format!("/v2/stocks/meta/conditions/{}", request.ticktype.as_str());
271        self.get_json("stocks.condition_codes", path, request.into_query())
272            .await
273    }
274
275    pub async fn exchange_codes(&self) -> Result<ExchangeCodesResponse, Error> {
276        self.get_json(
277            "stocks.exchange_codes",
278            "/v2/stocks/meta/exchanges",
279            Vec::new(),
280        )
281        .await
282    }
283
284    #[allow(dead_code)]
285    #[must_use]
286    pub(crate) fn inner(&self) -> &Arc<ClientInner> {
287        &self.inner
288    }
289
290    async fn get_json<Response>(
291        &self,
292        operation: &'static str,
293        path: impl Into<String>,
294        query: Vec<(String, String)>,
295    ) -> Result<Response, Error>
296    where
297        Response: DeserializeOwned,
298    {
299        let request = RequestParts::new(Method::GET, path.into())
300            .with_operation(operation)
301            .with_query(query);
302
303        self.inner
304            .send_json::<Response>(request)
305            .await
306            .map(|response| response.into_body())
307    }
308}
309
310impl fmt::Debug for StocksClient {
311    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312        f.debug_struct("StocksClient")
313            .field("base_url", self.inner.base_url())
314            .finish()
315    }
316}