1use serde::{Deserialize, Serialize};
4
5use crate::client::Client;
6use crate::error::Error;
7use crate::models::{
8 AccountId, CandleSpecification, CandlestickGranularity, DateTime, DecimalNumber,
9 InstrumentCandles, InstrumentName, OrderBook, PositionBook, PricingComponent, WeeklyAlignment,
10};
11
12impl Client {
13 pub fn candles(&self, instrument: impl Into<InstrumentName>) -> CandlesRequest {
35 CandlesRequest::new(self.clone(), None, instrument.into())
36 }
37
38 pub fn account_candles(
45 &self,
46 account_id: impl Into<AccountId>,
47 instrument: impl Into<InstrumentName>,
48 ) -> CandlesRequest {
49 CandlesRequest::new(self.clone(), Some(account_id.into()), instrument.into())
50 }
51
52 pub fn latest_candles(
77 &self,
78 account_id: impl Into<AccountId>,
79 specifications: impl IntoIterator<Item = CandleSpecification>,
80 ) -> LatestCandlesRequest {
81 LatestCandlesRequest {
82 client: self.clone(),
83 account_id: account_id.into(),
84 specifications: specifications.into_iter().collect(),
85 params: Vec::new(),
86 }
87 }
88
89 pub fn instrument_order_book(&self, instrument: impl Into<InstrumentName>) -> OrderBookRequest {
93 OrderBookRequest {
94 client: self.clone(),
95 instrument: instrument.into(),
96 time: None,
97 }
98 }
99
100 pub fn instrument_position_book(
104 &self,
105 instrument: impl Into<InstrumentName>,
106 ) -> PositionBookRequest {
107 PositionBookRequest {
108 client: self.clone(),
109 instrument: instrument.into(),
110 time: None,
111 }
112 }
113}
114
115#[derive(Debug)]
117pub struct CandlesRequest {
118 client: Client,
119 account_id: Option<AccountId>,
120 instrument: InstrumentName,
121 params: Vec<(&'static str, String)>,
122}
123
124impl CandlesRequest {
125 fn new(client: Client, account_id: Option<AccountId>, instrument: InstrumentName) -> Self {
126 CandlesRequest {
127 client,
128 account_id,
129 instrument,
130 params: Vec::new(),
131 }
132 }
133
134 pub fn price(mut self, price: PricingComponent) -> Self {
136 self.params.push(("price", price.to_string()));
137 self
138 }
139
140 pub fn granularity(mut self, granularity: CandlestickGranularity) -> Self {
142 self.params.push(("granularity", granularity.to_string()));
143 self
144 }
145
146 pub fn count(mut self, count: u32) -> Self {
149 self.params.push(("count", count.to_string()));
150 self
151 }
152
153 pub fn from(mut self, from: impl Into<DateTime>) -> Self {
155 self.params.push(("from", from.into().0));
156 self
157 }
158
159 pub fn to(mut self, to: impl Into<DateTime>) -> Self {
161 self.params.push(("to", to.into().0));
162 self
163 }
164
165 pub fn smooth(mut self, smooth: bool) -> Self {
168 self.params.push(("smooth", smooth.to_string()));
169 self
170 }
171
172 pub fn include_first(mut self, include_first: bool) -> Self {
175 self.params
176 .push(("includeFirst", include_first.to_string()));
177 self
178 }
179
180 pub fn daily_alignment(mut self, hour: u8) -> Self {
183 self.params.push(("dailyAlignment", hour.to_string()));
184 self
185 }
186
187 pub fn alignment_timezone(mut self, timezone: impl Into<String>) -> Self {
190 self.params.push(("alignmentTimezone", timezone.into()));
191 self
192 }
193
194 pub fn weekly_alignment(mut self, alignment: WeeklyAlignment) -> Self {
197 self.params.push(("weeklyAlignment", alignment.to_string()));
198 self
199 }
200
201 pub fn units(mut self, units: impl Into<DecimalNumber>) -> Self {
205 self.params.push(("units", units.into().to_string()));
206 self
207 }
208
209 pub async fn send(self) -> Result<InstrumentCandles, Error> {
211 let request = match &self.account_id {
212 Some(account_id) => self.client.get(&[
213 "accounts",
214 account_id.as_str(),
215 "instruments",
216 self.instrument.as_str(),
217 "candles",
218 ]),
219 None => self
220 .client
221 .get(&["instruments", self.instrument.as_str(), "candles"]),
222 };
223 self.client.execute(request.query(&self.params)).await
224 }
225}
226
227#[derive(Debug)]
229pub struct LatestCandlesRequest {
230 client: Client,
231 account_id: AccountId,
232 specifications: Vec<CandleSpecification>,
233 params: Vec<(&'static str, String)>,
234}
235
236impl LatestCandlesRequest {
237 pub fn units(mut self, units: impl Into<DecimalNumber>) -> Self {
240 self.params.push(("units", units.into().to_string()));
241 self
242 }
243
244 pub fn smooth(mut self, smooth: bool) -> Self {
246 self.params.push(("smooth", smooth.to_string()));
247 self
248 }
249
250 pub fn daily_alignment(mut self, hour: u8) -> Self {
253 self.params.push(("dailyAlignment", hour.to_string()));
254 self
255 }
256
257 pub fn alignment_timezone(mut self, timezone: impl Into<String>) -> Self {
260 self.params.push(("alignmentTimezone", timezone.into()));
261 self
262 }
263
264 pub fn weekly_alignment(mut self, alignment: WeeklyAlignment) -> Self {
267 self.params.push(("weeklyAlignment", alignment.to_string()));
268 self
269 }
270
271 pub async fn send(self) -> Result<LatestCandlesResponse, Error> {
273 let specs = self
274 .specifications
275 .iter()
276 .map(ToString::to_string)
277 .collect::<Vec<_>>()
278 .join(",");
279 let request = self
280 .client
281 .get(&["accounts", self.account_id.as_str(), "candles", "latest"])
282 .query(&[("candleSpecifications", specs)])
283 .query(&self.params);
284 self.client.execute(request).await
285 }
286}
287
288#[derive(Debug, Clone, Serialize, Deserialize)]
290#[non_exhaustive]
291pub struct LatestCandlesResponse {
292 #[serde(
294 rename = "latestCandles",
295 default,
296 skip_serializing_if = "Vec::is_empty"
297 )]
298 pub latest_candles: Vec<InstrumentCandles>,
299}
300
301#[derive(Debug)]
303pub struct OrderBookRequest {
304 client: Client,
305 instrument: InstrumentName,
306 time: Option<DateTime>,
307}
308
309impl OrderBookRequest {
310 pub fn time(mut self, time: impl Into<DateTime>) -> Self {
313 self.time = Some(time.into());
314 self
315 }
316
317 pub async fn send(self) -> Result<OrderBookResponse, Error> {
319 let mut request = self
320 .client
321 .get(&["instruments", self.instrument.as_str(), "orderBook"]);
322 if let Some(time) = &self.time {
323 request = request.query(&[("time", time.as_str())]);
324 }
325 let (mut response, headers): (OrderBookResponse, _) =
326 self.client.execute_with_headers(request).await?;
327 response.link = crate::transport::header_str(&headers, "Link").map(str::to_owned);
328 Ok(response)
329 }
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize)]
334#[non_exhaustive]
335pub struct OrderBookResponse {
336 #[serde(rename = "orderBook")]
338 pub order_book: OrderBook,
339 #[serde(skip)]
342 pub link: Option<String>,
343}
344
345#[derive(Debug)]
347pub struct PositionBookRequest {
348 client: Client,
349 instrument: InstrumentName,
350 time: Option<DateTime>,
351}
352
353impl PositionBookRequest {
354 pub fn time(mut self, time: impl Into<DateTime>) -> Self {
357 self.time = Some(time.into());
358 self
359 }
360
361 pub async fn send(self) -> Result<PositionBookResponse, Error> {
363 let mut request =
364 self.client
365 .get(&["instruments", self.instrument.as_str(), "positionBook"]);
366 if let Some(time) = &self.time {
367 request = request.query(&[("time", time.as_str())]);
368 }
369 let (mut response, headers): (PositionBookResponse, _) =
370 self.client.execute_with_headers(request).await?;
371 response.link = crate::transport::header_str(&headers, "Link").map(str::to_owned);
372 Ok(response)
373 }
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
378#[non_exhaustive]
379pub struct PositionBookResponse {
380 #[serde(rename = "positionBook")]
382 pub position_book: PositionBook,
383 #[serde(skip)]
386 pub link: Option<String>,
387}