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, BarsRequest, BarsResponse, ConditionCodesRequest,
12 ConditionCodesResponse, ExchangeCodesResponse, LatestBarsRequest, LatestBarsResponse,
13 LatestQuotesRequest, LatestQuotesResponse, LatestTradesRequest, LatestTradesResponse,
14 QuotesRequest, QuotesResponse, SnapshotsRequest, SnapshotsResponse, TradesRequest,
15 TradesResponse,
16};
17
18#[derive(Clone)]
19pub struct StocksClient {
20 inner: Arc<ClientInner>,
21}
22
23impl StocksClient {
24 pub(crate) fn new(inner: Arc<ClientInner>) -> Self {
25 Self { inner }
26 }
27
28 pub async fn bars(&self, request: BarsRequest) -> Result<BarsResponse, Error> {
29 request.validate()?;
30 self.get_json("stocks.bars", "/v2/stocks/bars", request.into_query())
31 .await
32 }
33
34 pub async fn bars_all(&self, request: BarsRequest) -> Result<BarsResponse, Error> {
35 let client = self.clone();
36 pagination::collect_all(request, move |request| {
37 let client = client.clone();
38 async move { client.bars(request).await }
39 })
40 .await
41 }
42
43 pub async fn auctions(&self, request: AuctionsRequest) -> Result<AuctionsResponse, Error> {
44 request.validate()?;
45 self.get_json(
46 "stocks.auctions",
47 "/v2/stocks/auctions",
48 request.into_query(),
49 )
50 .await
51 }
52
53 pub async fn auctions_all(&self, request: AuctionsRequest) -> Result<AuctionsResponse, Error> {
54 let client = self.clone();
55 pagination::collect_all(request, move |request| {
56 let client = client.clone();
57 async move { client.auctions(request).await }
58 })
59 .await
60 }
61
62 pub async fn quotes(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
63 request.validate()?;
64 self.get_json("stocks.quotes", "/v2/stocks/quotes", request.into_query())
65 .await
66 }
67
68 pub async fn quotes_all(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
69 let client = self.clone();
70 pagination::collect_all(request, move |request| {
71 let client = client.clone();
72 async move { client.quotes(request).await }
73 })
74 .await
75 }
76
77 pub async fn trades(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
78 request.validate()?;
79 self.get_json("stocks.trades", "/v2/stocks/trades", request.into_query())
80 .await
81 }
82
83 pub async fn trades_all(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
84 let client = self.clone();
85 pagination::collect_all(request, move |request| {
86 let client = client.clone();
87 async move { client.trades(request).await }
88 })
89 .await
90 }
91
92 pub async fn latest_bars(
93 &self,
94 request: LatestBarsRequest,
95 ) -> Result<LatestBarsResponse, Error> {
96 request.validate()?;
97 self.get_json(
98 "stocks.latest_bars",
99 "/v2/stocks/bars/latest",
100 request.into_query(),
101 )
102 .await
103 }
104
105 pub async fn latest_quotes(
106 &self,
107 request: LatestQuotesRequest,
108 ) -> Result<LatestQuotesResponse, Error> {
109 request.validate()?;
110 self.get_json(
111 "stocks.latest_quotes",
112 "/v2/stocks/quotes/latest",
113 request.into_query(),
114 )
115 .await
116 }
117
118 pub async fn latest_trades(
119 &self,
120 request: LatestTradesRequest,
121 ) -> Result<LatestTradesResponse, Error> {
122 request.validate()?;
123 self.get_json(
124 "stocks.latest_trades",
125 "/v2/stocks/trades/latest",
126 request.into_query(),
127 )
128 .await
129 }
130
131 pub async fn snapshots(&self, request: SnapshotsRequest) -> Result<SnapshotsResponse, Error> {
132 request.validate()?;
133 self.get_json(
134 "stocks.snapshots",
135 "/v2/stocks/snapshots",
136 request.into_query(),
137 )
138 .await
139 }
140
141 pub async fn condition_codes(
142 &self,
143 request: ConditionCodesRequest,
144 ) -> Result<ConditionCodesResponse, Error> {
145 let path = format!("/v2/stocks/meta/conditions/{}", request.ticktype.as_str());
146 self.get_json("stocks.condition_codes", path, request.into_query())
147 .await
148 }
149
150 pub async fn exchange_codes(&self) -> Result<ExchangeCodesResponse, Error> {
151 self.get_json(
152 "stocks.exchange_codes",
153 "/v2/stocks/meta/exchanges",
154 Vec::new(),
155 )
156 .await
157 }
158
159 #[allow(dead_code)]
160 #[must_use]
161 pub(crate) fn inner(&self) -> &Arc<ClientInner> {
162 &self.inner
163 }
164
165 async fn get_json<Response>(
166 &self,
167 operation: &'static str,
168 path: impl Into<String>,
169 query: Vec<(String, String)>,
170 ) -> Result<Response, Error>
171 where
172 Response: DeserializeOwned,
173 {
174 let request = RequestParts::new(Method::GET, path.into())
175 .with_operation(operation)
176 .with_query(query);
177
178 self.inner
179 .send_json::<Response>(request)
180 .await
181 .map(|response| response.into_body())
182 }
183}
184
185impl fmt::Debug for StocksClient {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("StocksClient").finish()
188 }
189}