Skip to main content

alpaca_data/crypto/
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    BarsRequest, BarsResponse, LatestBarsRequest, LatestBarsResponse, LatestOrderbooksRequest,
12    LatestOrderbooksResponse, LatestQuotesRequest, LatestQuotesResponse, LatestTradesRequest,
13    LatestTradesResponse, QuotesRequest, QuotesResponse, SnapshotsRequest, SnapshotsResponse,
14    TradesRequest, TradesResponse,
15};
16
17#[derive(Clone)]
18pub struct CryptoClient {
19    inner: Arc<ClientInner>,
20}
21
22impl CryptoClient {
23    pub(crate) fn new(inner: Arc<ClientInner>) -> Self {
24        Self { inner }
25    }
26
27    pub async fn bars(&self, request: BarsRequest) -> Result<BarsResponse, Error> {
28        request.validate()?;
29        let path = format!("/v1beta3/crypto/{}/bars", request.location);
30        self.get_json("crypto.bars", path, 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 quotes(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
44        request.validate()?;
45        let path = format!("/v1beta3/crypto/{}/quotes", request.location);
46        self.get_json("crypto.quotes", path, request.into_query())
47            .await
48    }
49
50    pub async fn quotes_all(&self, request: QuotesRequest) -> Result<QuotesResponse, Error> {
51        let client = self.clone();
52        pagination::collect_all(request, move |request| {
53            let client = client.clone();
54            async move { client.quotes(request).await }
55        })
56        .await
57    }
58
59    pub async fn trades(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
60        request.validate()?;
61        let path = format!("/v1beta3/crypto/{}/trades", request.location);
62        self.get_json("crypto.trades", path, request.into_query())
63            .await
64    }
65
66    pub async fn trades_all(&self, request: TradesRequest) -> Result<TradesResponse, Error> {
67        let client = self.clone();
68        pagination::collect_all(request, move |request| {
69            let client = client.clone();
70            async move { client.trades(request).await }
71        })
72        .await
73    }
74
75    pub async fn latest_bars(
76        &self,
77        request: LatestBarsRequest,
78    ) -> Result<LatestBarsResponse, Error> {
79        request.validate()?;
80        let path = format!("/v1beta3/crypto/{}/latest/bars", request.location);
81        self.get_json("crypto.latest_bars", path, request.into_query())
82            .await
83    }
84
85    pub async fn latest_quotes(
86        &self,
87        request: LatestQuotesRequest,
88    ) -> Result<LatestQuotesResponse, Error> {
89        request.validate()?;
90        let path = format!("/v1beta3/crypto/{}/latest/quotes", request.location);
91        self.get_json("crypto.latest_quotes", path, request.into_query())
92            .await
93    }
94
95    pub async fn latest_trades(
96        &self,
97        request: LatestTradesRequest,
98    ) -> Result<LatestTradesResponse, Error> {
99        request.validate()?;
100        let path = format!("/v1beta3/crypto/{}/latest/trades", request.location);
101        self.get_json("crypto.latest_trades", path, request.into_query())
102            .await
103    }
104
105    pub async fn latest_orderbooks(
106        &self,
107        request: LatestOrderbooksRequest,
108    ) -> Result<LatestOrderbooksResponse, Error> {
109        request.validate()?;
110        let path = format!("/v1beta3/crypto/{}/latest/orderbooks", request.location);
111        self.get_json("crypto.latest_orderbooks", path, request.into_query())
112            .await
113    }
114
115    pub async fn snapshots(&self, request: SnapshotsRequest) -> Result<SnapshotsResponse, Error> {
116        request.validate()?;
117        let path = format!("/v1beta3/crypto/{}/snapshots", request.location);
118        self.get_json("crypto.snapshots", path, request.into_query())
119            .await
120    }
121
122    #[allow(dead_code)]
123    #[must_use]
124    pub(crate) fn inner(&self) -> &Arc<ClientInner> {
125        &self.inner
126    }
127
128    async fn get_json<Response>(
129        &self,
130        operation: &'static str,
131        path: impl Into<String>,
132        query: Vec<(String, String)>,
133    ) -> Result<Response, Error>
134    where
135        Response: DeserializeOwned,
136    {
137        let request = RequestParts::new(Method::GET, path.into())
138            .with_operation(operation)
139            .with_query(query);
140
141        self.inner
142            .send_json::<Response>(request)
143            .await
144            .map(|response| response.into_body())
145    }
146}
147
148impl fmt::Debug for CryptoClient {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        f.debug_struct("CryptoClient").finish()
151    }
152}