deribit_http/endpoints/public.rs
1//! REST API endpoints implementation
2//!
3//! This module implements all Deribit REST API endpoints including
4//! market data, trading, account management, and system endpoints.
5
6use crate::DeribitHttpClient;
7use crate::constants::endpoints::*;
8use crate::error::HttpError;
9use crate::model::LastTradesResponse;
10use crate::model::book::{BookSummary, OrderBook};
11use crate::model::currency::CurrencyStruct;
12use crate::model::funding::{FundingChartData, FundingRateData};
13use crate::model::index::{IndexChartDataPoint, IndexData, IndexPriceData};
14use crate::model::instrument::{Instrument, OptionType};
15use crate::model::order::OrderSide;
16use crate::model::other::{OptionInstrument, OptionInstrumentPair};
17use crate::model::response::api_response::ApiResponse;
18use crate::model::response::other::{
19 AprHistoryResponse, ContractSizeResponse, DeliveryPricesResponse, ExpirationsResponse,
20 IndexNameInfo, MarkPriceHistoryPoint, SettlementsResponse, StatusResponse, TestResponse,
21 TradeVolume, VolatilityIndexData,
22};
23use crate::model::ticker::TickerData;
24use crate::model::trade::{Liquidity, Trade};
25use crate::model::tradingview::TradingViewChartData;
26use std::collections::HashMap;
27
28/// Market data endpoints
29impl DeribitHttpClient {
30 /// Get all supported currencies
31 ///
32 /// Retrieves all cryptocurrencies supported by the API.
33 /// This is a public endpoint that doesn't require authentication.
34 ///
35 /// # Examples
36 ///
37 /// ```rust
38 /// # use deribit_http::DeribitHttpClient;
39 /// # #[tokio::main]
40 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
41 /// let client = DeribitHttpClient::new(); // testnet
42 /// let currencies = client.get_currencies().await?;
43 /// for currency in currencies {
44 /// println!("Currency: {} ({})", currency.currency, currency.currency_long);
45 /// }
46 /// # Ok(())
47 /// # }
48 /// ```
49 pub async fn get_currencies(&self) -> Result<Vec<CurrencyStruct>, HttpError> {
50 self.public_get(GET_CURRENCIES, "").await
51 }
52
53 /// Get current index price for a currency
54 ///
55 /// Retrieves the current index price for the instruments, for the selected currency.
56 /// This is a public endpoint that doesn't require authentication.
57 ///
58 /// # Arguments
59 ///
60 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
61 ///
62 pub async fn get_index(&self, currency: &str) -> Result<IndexData, HttpError> {
63 let query = format!("?currency={}", currency);
64 self.public_get(GET_INDEX, &query).await
65 }
66
67 /// Get index price by name
68 ///
69 /// Retrieves the current index price value for given index name.
70 /// This is a public endpoint that doesn't require authentication.
71 ///
72 /// # Arguments
73 ///
74 /// * `index_name` - The index identifier (e.g., "btc_usd", "eth_usd")
75 ///
76 /// # Examples
77 ///
78 /// ```rust
79 /// # use deribit_http::DeribitHttpClient;
80 /// # #[tokio::main]
81 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
82 /// let client = DeribitHttpClient::new(); // testnet
83 /// let index_price = client.get_index_price("btc_usd").await?;
84 /// println!("Index price: {}", index_price.index_price);
85 /// # Ok(())
86 /// # }
87 /// ```
88 pub async fn get_index_price(&self, index_name: &str) -> Result<IndexPriceData, HttpError> {
89 let query = format!("?index_name={}", index_name);
90 self.public_get(GET_INDEX_PRICE, &query).await
91 }
92
93 /// Get all supported index price names
94 ///
95 /// Retrieves the identifiers of all supported Price Indexes.
96 /// This is a public endpoint that doesn't require authentication.
97 ///
98 /// # Examples
99 ///
100 /// ```rust
101 /// # use deribit_http::DeribitHttpClient;
102 /// # #[tokio::main]
103 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
104 /// let client = DeribitHttpClient::new(); // testnet
105 /// let index_names = client.get_index_price_names().await?;
106 /// for name in index_names {
107 /// println!("Index: {}", name);
108 /// }
109 /// # Ok(())
110 /// # }
111 /// ```
112 pub async fn get_index_price_names(&self) -> Result<Vec<String>, HttpError> {
113 self.public_get(GET_INDEX_PRICE_NAMES, "").await
114 }
115
116 /// Get index chart data
117 ///
118 /// Returns historical price index chart data for the specified index name and time range.
119 /// The data is formatted for use in charting applications and shows price index values over time.
120 /// This is a public endpoint that doesn't require authentication.
121 ///
122 /// # Arguments
123 ///
124 /// * `index_name` - Index identifier (e.g., "btc_usd", "eth_usd", "sol_usdc")
125 /// * `range` - Time range for the data: "1h", "1d", "2d", "1m", "1y", or "all"
126 ///
127 /// # Examples
128 ///
129 /// ```rust
130 /// # use deribit_http::DeribitHttpClient;
131 /// # #[tokio::main]
132 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
133 /// let client = DeribitHttpClient::new(); // testnet
134 /// let chart_data = client.get_index_chart_data("btc_usd", "1d").await?;
135 /// for point in chart_data {
136 /// println!("Time: {}, Price: {}", point.timestamp, point.price);
137 /// }
138 /// # Ok(())
139 /// # }
140 /// ```
141 pub async fn get_index_chart_data(
142 &self,
143 index_name: &str,
144 range: &str,
145 ) -> Result<Vec<IndexChartDataPoint>, HttpError> {
146 let query = format!(
147 "?index_name={}&range={}",
148 urlencoding::encode(index_name),
149 urlencoding::encode(range)
150 );
151 self.public_get(GET_INDEX_CHART_DATA, &query).await
152 }
153
154 /// Get book summary by currency
155 ///
156 /// Retrieves the summary information such as open interest, 24h volume, etc.
157 /// for all instruments for the currency (optionally filtered by kind).
158 /// This is a public endpoint that doesn't require authentication.
159 ///
160 /// # Arguments
161 ///
162 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
163 /// * `kind` - Optional instrument kind filter (future, option, spot, future_combo, option_combo)
164 ///
165 /// # Examples
166 ///
167 /// ```rust
168 /// # use deribit_http::DeribitHttpClient;
169 /// # #[tokio::main]
170 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
171 /// let client = DeribitHttpClient::new(); // testnet
172 /// let summaries = client.get_book_summary_by_currency("BTC", Some("future")).await?;
173 /// for summary in summaries {
174 /// println!("Instrument: {} - Volume: {}", summary.instrument_name, summary.volume);
175 /// }
176 /// # Ok(())
177 /// # }
178 /// ```
179 pub async fn get_book_summary_by_currency(
180 &self,
181 currency: &str,
182 kind: Option<&str>,
183 ) -> Result<Vec<BookSummary>, HttpError> {
184 let mut query = format!("?currency={}", currency);
185 if let Some(kind) = kind {
186 query.push_str(&format!("&kind={}", kind));
187 }
188 self.public_get(GET_BOOK_SUMMARY_BY_CURRENCY, &query).await
189 }
190
191 /// Get single instrument information
192 ///
193 /// Retrieves detailed information about a specific instrument.
194 /// This is a public endpoint that doesn't require authentication.
195 ///
196 /// # Arguments
197 ///
198 /// * `instrument_name` - The instrument identifier (e.g., "BTC-PERPETUAL")
199 ///
200 /// # Examples
201 ///
202 /// ```rust
203 /// # use deribit_http::DeribitHttpClient;
204 /// # #[tokio::main]
205 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
206 /// let client = DeribitHttpClient::new(); // testnet
207 /// let instrument = client.get_instrument("BTC-PERPETUAL").await?;
208 /// println!("Contract size: {:?}", instrument.contract_size);
209 /// # Ok(())
210 /// # }
211 /// ```
212 pub async fn get_instrument(&self, instrument_name: &str) -> Result<Instrument, HttpError> {
213 let query = format!("?instrument_name={}", instrument_name);
214 self.public_get(GET_INSTRUMENT, &query).await
215 }
216
217 /// Get book summary by instrument
218 ///
219 /// Retrieves the summary information such as open interest, 24h volume, etc.
220 /// for a specific instrument.
221 /// This is a public endpoint that doesn't require authentication.
222 ///
223 /// # Arguments
224 ///
225 /// * `instrument_name` - The instrument identifier (e.g., "BTC-PERPETUAL")
226 ///
227 pub async fn get_book_summary_by_instrument(
228 &self,
229 instrument_name: &str,
230 ) -> Result<BookSummary, HttpError> {
231 let query = format!("?instrument_name={}", instrument_name);
232 // The API returns an array with one element, so we parse as Vec and extract first
233 let book_summaries: Vec<BookSummary> = self
234 .public_get(GET_BOOK_SUMMARY_BY_INSTRUMENT, &query)
235 .await?;
236 book_summaries.into_iter().next().ok_or_else(|| {
237 HttpError::InvalidResponse("Empty book summary array in response".to_string())
238 })
239 }
240
241 /// Get contract size for an instrument
242 ///
243 /// Retrieves contract size for specified instrument.
244 /// This is a public endpoint that doesn't require authentication.
245 ///
246 /// # Arguments
247 ///
248 /// * `instrument_name` - The instrument identifier (e.g., "BTC-PERPETUAL")
249 ///
250 /// # Examples
251 ///
252 /// ```rust
253 /// # use deribit_http::DeribitHttpClient;
254 /// # #[tokio::main]
255 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
256 /// let client = DeribitHttpClient::new(); // testnet
257 /// let contract_size = client.get_contract_size("BTC-PERPETUAL").await?;
258 /// println!("Contract size: {}", contract_size);
259 /// # Ok(())
260 /// # }
261 /// ```
262 pub async fn get_contract_size(&self, instrument_name: &str) -> Result<f64, HttpError> {
263 let query = format!("?instrument_name={}", instrument_name);
264 let response: ContractSizeResponse = self.public_get(GET_CONTRACT_SIZE, &query).await?;
265 Ok(response.contract_size)
266 }
267
268 /// Get server time
269 ///
270 /// Returns the current server time in milliseconds since Unix epoch.
271 /// This is a public endpoint that doesn't require authentication.
272 ///
273 /// # Examples
274 ///
275 /// ```rust
276 /// # use deribit_http::DeribitHttpClient;
277 /// # #[tokio::main]
278 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
279 /// let client = DeribitHttpClient::new(); // testnet
280 /// let server_time = client.get_server_time().await?;
281 /// println!("Server time: {}", server_time);
282 /// # Ok(())
283 /// # }
284 /// ```
285 pub async fn get_server_time(&self) -> Result<u64, HttpError> {
286 self.public_get(GET_SERVER_TIME, "").await
287 }
288
289 /// Test connectivity to the API
290 ///
291 /// Returns the API version to test connectivity.
292 /// This is a public endpoint that doesn't require authentication.
293 pub async fn test_connection(&self) -> Result<String, HttpError> {
294 let response: TestResponse = self.public_get(TEST_CONNECTION, "").await?;
295 Ok(response.version)
296 }
297
298 /// Get platform status and locked currency indices
299 ///
300 /// Returns information about the platform status and any locked currency indices.
301 /// This is a public endpoint that doesn't require authentication.
302 ///
303 pub async fn get_status(&self) -> Result<StatusResponse, HttpError> {
304 let url = format!("{}{}", self.base_url(), GET_STATUS);
305
306 let response = self
307 .http_client()
308 .get(&url)
309 .send()
310 .await
311 .map_err(|e| HttpError::NetworkError(e.to_string()))?;
312
313 if !response.status().is_success() {
314 let error_text = response
315 .text()
316 .await
317 .unwrap_or_else(|_| "Unknown error".to_string());
318 return Err(HttpError::RequestFailed(format!(
319 "Get status failed: {}",
320 error_text
321 )));
322 }
323
324 // Try direct deserialization first (non-JSON-RPC response)
325 match response.json::<StatusResponse>().await {
326 Ok(status) => Ok(status),
327 Err(_) => {
328 // Fallback to JSON-RPC wrapper format
329 let response = self
330 .http_client()
331 .get(&url)
332 .send()
333 .await
334 .map_err(|e| HttpError::NetworkError(e.to_string()))?;
335
336 let api_response: ApiResponse<StatusResponse> = response
337 .json()
338 .await
339 .map_err(|e| HttpError::InvalidResponse(e.to_string()))?;
340
341 if let Some(error) = api_response.error {
342 return Err(HttpError::RequestFailed(format!(
343 "API error: {} - {}",
344 error.code, error.message
345 )));
346 }
347
348 api_response.result.ok_or_else(|| {
349 HttpError::InvalidResponse("No status data in response".to_string())
350 })
351 }
352 }
353 }
354
355 /// Get APR history for yield tokens
356 ///
357 /// Retrieves historical APR data for specified currency. Only applicable to yield-generating tokens (USDE, STETH).
358 /// This is a public endpoint that doesn't require authentication.
359 ///
360 /// # Arguments
361 ///
362 /// * `currency` - Currency for which to retrieve APR history (usde or steth)
363 /// * `limit` - Optional number of days to retrieve (default 365, maximum 365)
364 /// * `before` - Optional parameter to receive APR history before given epoch day
365 ///
366 pub async fn get_apr_history(
367 &self,
368 currency: &str,
369 limit: Option<u32>,
370 before: Option<i32>,
371 ) -> Result<AprHistoryResponse, HttpError> {
372 let mut query = format!("?currency={}", currency);
373 if let Some(limit) = limit {
374 query.push_str(&format!("&limit={}", limit));
375 }
376 if let Some(before) = before {
377 query.push_str(&format!("&before={}", before));
378 }
379 self.public_get(GET_APR_HISTORY, &query).await
380 }
381
382 /// Get ticker information for an instrument
383 ///
384 /// Returns ticker data including last price, bid/ask, volume, etc.
385 ///
386 /// # Arguments
387 ///
388 /// * `instrument_name` - The instrument identifier (e.g., "BTC-PERPETUAL")
389 ///
390 /// # Examples
391 ///
392 /// ```rust
393 /// # use deribit_http::DeribitHttpClient;
394 /// # #[tokio::main]
395 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
396 /// let client = DeribitHttpClient::new();
397 /// let ticker = client.get_ticker("BTC-PERPETUAL").await?;
398 /// println!("Last price: {:?}", ticker.last_price);
399 /// # Ok(())
400 /// # }
401 /// ```
402 pub async fn get_ticker(&self, instrument_name: &str) -> Result<TickerData, HttpError> {
403 let query = format!("?instrument_name={}", instrument_name);
404 self.public_get(GET_TICKER, &query).await
405 }
406
407 /// Get order book for an instrument
408 ///
409 /// Returns the current order book with bids and asks.
410 ///
411 /// # Arguments
412 ///
413 /// * `instrument_name` - The instrument identifier
414 /// * `depth` - Optional depth of the order book (default: 5)
415 pub async fn get_order_book(
416 &self,
417 instrument_name: &str,
418 depth: Option<u32>,
419 ) -> Result<OrderBook, HttpError> {
420 let mut query = format!("?instrument_name={}", instrument_name);
421 if let Some(d) = depth {
422 query.push_str(&format!("&depth={}", d));
423 }
424 self.public_get(GET_ORDER_BOOK, &query).await
425 }
426
427 /// Retrieves a list of option instruments for a given currency and expiry date.
428 ///
429 /// This asynchronous function fetches option instruments for the specified `currency`
430 /// and `expiry` date and returns a filtered list of options along with their associated
431 /// ticker information.
432 ///
433 /// # Arguments
434 ///
435 /// * `currency` - A string slice that represents the name of the currency (e.g., "BTC", "ETH").
436 /// * `expiry` - A string slice representing the expiry date for the options (e.g., "20231027").
437 ///
438 /// # Returns
439 ///
440 /// Returns a `Result` containing a vector of `OptionInstrument` on success,
441 /// or an `HttpError` on failure.
442 ///
443 /// - On success, it returns a `Vec<OptionInstrument>`, where each option contains
444 /// the instrument details and ticker information.
445 /// - On failure, it returns an `HttpError`, such as in cases where the instrument
446 /// data could not be retrieved or tickers are inaccessible.
447 ///
448 /// # Errors
449 ///
450 /// This function may return an `HttpError` in the following scenarios:
451 ///
452 /// * If fetching the instrument data fails.
453 /// * If retrieving ticker information for an instrument fails.
454 ///
455 /// # Implementation Details
456 ///
457 /// 1. Fetches instruments for the specified `currency` filtered by type `option`.
458 /// 2. Filters the instruments to ensure they match the `currency`-`expiry` base name.
459 /// 3. Constructs an `OptionInstrument` for each filtered instrument, including
460 /// the instrument details and ticker information.
461 ///
462 pub async fn get_options(
463 &self,
464 currency: &str,
465 expiry: &str,
466 ) -> Result<Vec<OptionInstrument>, HttpError> {
467 let mut instruments = self
468 .get_instruments(currency, Some("option"), Some(false))
469 .await
470 .map_err(|e| HttpError::RequestFailed(e.to_string()))?;
471
472 let base_name = format!("{}-{}", currency, expiry).to_uppercase();
473 // filter instruments by base name in instrument_name
474 instruments.retain(|i| i.instrument_name.starts_with(&base_name));
475
476 let mut options: Vec<OptionInstrument> = Vec::with_capacity(instruments.len());
477 for instrument in instruments {
478 let option = OptionInstrument {
479 instrument: instrument.clone(),
480 ticker: self.get_ticker(instrument.instrument_name.as_str()).await?,
481 };
482 options.push(option)
483 }
484 Ok(options)
485 }
486
487 /// Fetches option instruments for a given currency and expiry date, grouped by strike price.
488 ///
489 /// This method retrieves all option instruments for the specified currency and expiry,
490 /// then groups them into pairs (call and put) by strike price. Each strike price
491 /// maps to an `OptionInstrumentPair` containing the call and put options if available.
492 ///
493 /// # Arguments
494 ///
495 /// * `currency` - The currency symbol (e.g., "BTC", "ETH")
496 /// * `expiry` - The expiry date in format "DDMMMYY" (e.g., "10SEP25")
497 ///
498 /// # Returns
499 ///
500 /// Returns a `HashMap` where:
501 /// - Key: Strike price as `u64`
502 /// - Value: `OptionInstrumentPair` containing call and put options for that strike
503 ///
504 /// # Errors
505 ///
506 /// Returns `HttpError` if:
507 /// - The API request fails
508 /// - An option instrument has no option type
509 /// - Network or authentication errors occur
510 ///
511 /// # Example
512 ///
513 /// ```no_run
514 /// # use deribit_http::DeribitHttpClient;
515 /// # #[tokio::main]
516 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
517 /// let client = DeribitHttpClient::new();
518 /// let pairs = client.get_options_pair("BTC", "10SEP25").await?;
519 ///
520 /// for (strike, pair) in pairs {
521 /// println!("Strike {}: Call={:?}, Put={:?}",
522 /// strike, pair.call.is_some(), pair.put.is_some());
523 /// }
524 /// # Ok(())
525 /// # }
526 /// ```
527 pub async fn get_options_pair(
528 &self,
529 currency: &str,
530 expiry: &str,
531 ) -> Result<HashMap<u64, OptionInstrumentPair>, HttpError> {
532 let option_instruments = self.get_options(currency, expiry).await?;
533
534 let mut strikes_map: HashMap<u64, OptionInstrumentPair> =
535 HashMap::with_capacity(option_instruments.len() / 2);
536 for instrument in option_instruments {
537 let strike_price = instrument.instrument.strike.unwrap() as u64;
538 strikes_map
539 .entry(strike_price)
540 .or_insert(OptionInstrumentPair {
541 call: None,
542 put: None,
543 });
544 match instrument.instrument.option_type.clone() {
545 Some(option_type) => match option_type {
546 OptionType::Call => {
547 strikes_map.get_mut(&strike_price).unwrap().call = Some(instrument.clone());
548 }
549 OptionType::Put => {
550 strikes_map.get_mut(&strike_price).unwrap().put = Some(instrument.clone());
551 }
552 },
553 None => {
554 return Err(HttpError::RequestFailed(
555 "Option instrument has no option type".to_string(),
556 ));
557 }
558 }
559 }
560
561 Ok(strikes_map)
562 }
563
564 /// Get available instruments
565 ///
566 /// Returns a list of available trading instruments.
567 ///
568 /// # Arguments
569 ///
570 /// * `currency` - The currency (e.g., "BTC", "ETH")
571 /// * `kind` - Optional instrument kind ("future", "option", "spot")
572 /// * `expired` - Whether to include expired instruments
573 pub async fn get_instruments(
574 &self,
575 currency: &str,
576 kind: Option<&str>,
577 expired: Option<bool>,
578 ) -> Result<Vec<Instrument>, HttpError> {
579 let mut query = format!("?currency={}", currency);
580 if let Some(k) = kind {
581 query.push_str(&format!("&kind={}", k));
582 }
583 if let Some(exp) = expired {
584 query.push_str(&format!("&expired={}", exp));
585 }
586 self.public_get(GET_INSTRUMENTS, &query).await
587 }
588
589 /// Get recent trades for an instrument
590 ///
591 /// Returns recent trade history for the specified instrument.
592 ///
593 /// # Arguments
594 ///
595 /// * `instrument_name` - The instrument identifier
596 /// * `count` - Optional number of trades to return (default: 10, max: 1000)
597 /// * `include_old` - Whether to include old trades
598 pub async fn get_last_trades(
599 &self,
600 instrument_name: &str,
601 count: Option<u32>,
602 include_old: Option<bool>,
603 ) -> Result<Vec<Trade>, HttpError> {
604 let mut query = format!("?instrument_name={}", urlencoding::encode(instrument_name));
605 if let Some(c) = count {
606 query.push_str(&format!("&count={}", c));
607 }
608 if let Some(old) = include_old {
609 query.push_str(&format!("&include_old={}", old));
610 }
611
612 let trades_response: LastTradesResponse = self
613 .public_get(GET_LAST_TRADES_BY_INSTRUMENT, &query)
614 .await?;
615
616 // Convert LastTrade to Trade
617 let trades: Vec<Trade> = trades_response
618 .trades
619 .into_iter()
620 .map(|last_trade| {
621 Trade {
622 trade_id: last_trade.trade_id,
623 instrument_name: last_trade.instrument_name,
624 order_id: String::new(), // Not available in LastTrade
625 direction: match last_trade.direction.as_str() {
626 "buy" => OrderSide::Buy,
627 "sell" => OrderSide::Sell,
628 _ => OrderSide::Buy, // Default fallback
629 },
630 amount: last_trade.amount,
631 price: last_trade.price,
632 timestamp: last_trade.timestamp as i64,
633 fee: 0.0, // Not available in LastTrade
634 fee_currency: String::new(), // Not available in LastTrade
635 liquidity: Liquidity::Taker, // Default
636 mark_price: 0.0, // Not available in LastTrade
637 index_price: last_trade.index_price,
638 instrument_kind: None, // Not available in LastTrade
639 trade_seq: Some(last_trade.trade_seq),
640 user_role: None,
641 block_trade: None,
642 underlying_price: None,
643 iv: last_trade.iv,
644 label: None,
645 profit_loss: None,
646 tick_direction: Some(last_trade.tick_direction),
647 self_trade: None,
648 }
649 })
650 .collect();
651
652 Ok(trades)
653 }
654
655 /// Get historical volatility
656 ///
657 /// Provides information about historical volatility for given cryptocurrency.
658 ///
659 /// # Arguments
660 ///
661 /// * `currency` - Currency symbol (BTC, ETH, etc.)
662 ///
663 /// # Examples
664 ///
665 /// ```rust
666 /// use deribit_http::DeribitHttpClient;
667 ///
668 /// let client = DeribitHttpClient::new();
669 /// // let volatility = client.get_historical_volatility("BTC").await?;
670 /// // tracing::info!("Found {} volatility data points", volatility.len());
671 /// ```
672 pub async fn get_historical_volatility(
673 &self,
674 currency: &str,
675 ) -> Result<Vec<[f64; 2]>, HttpError> {
676 let query = format!("?currency={}", urlencoding::encode(currency));
677 self.public_get(GET_HISTORICAL_VOLATILITY, &query).await
678 }
679
680 /// Get mark price history
681 ///
682 /// Retrieves 5-minute historical mark price data for an instrument.
683 /// Mark prices are used for margin calculations and position valuations.
684 ///
685 /// **Note**: Currently, mark price history is available only for a subset of options
686 /// that participate in volatility index calculations. All other instruments,
687 /// including futures and perpetuals, will return an empty list.
688 ///
689 /// # Arguments
690 ///
691 /// * `instrument_name` - Unique instrument identifier (e.g., "BTC-25JUN21-50000-C")
692 /// * `start_timestamp` - The earliest timestamp to return results from (milliseconds since Unix epoch)
693 /// * `end_timestamp` - The most recent timestamp to return results from (milliseconds since Unix epoch)
694 ///
695 /// # Returns
696 ///
697 /// Returns a vector of `MarkPriceHistoryPoint` containing timestamp and mark price pairs.
698 ///
699 /// # Errors
700 ///
701 /// Returns `HttpError` if the request fails or the response cannot be parsed.
702 ///
703 /// # Examples
704 ///
705 /// ```rust
706 /// use deribit_http::DeribitHttpClient;
707 ///
708 /// let client = DeribitHttpClient::new();
709 /// // let history = client.get_mark_price_history(
710 /// // "BTC-25JUN21-50000-C",
711 /// // 1609376800000,
712 /// // 1609376810000
713 /// // ).await?;
714 /// // for point in history {
715 /// // println!("Time: {}, Mark Price: {}", point.timestamp, point.mark_price);
716 /// // }
717 /// ```
718 pub async fn get_mark_price_history(
719 &self,
720 instrument_name: &str,
721 start_timestamp: u64,
722 end_timestamp: u64,
723 ) -> Result<Vec<MarkPriceHistoryPoint>, HttpError> {
724 let query = format!(
725 "?instrument_name={}&start_timestamp={}&end_timestamp={}",
726 urlencoding::encode(instrument_name),
727 start_timestamp,
728 end_timestamp
729 );
730 self.public_get(GET_MARK_PRICE_HISTORY, &query).await
731 }
732
733 /// Get supported index names
734 ///
735 /// Retrieves the identifiers (names) of all supported price indexes.
736 /// Price indexes are reference prices used for mark price calculations,
737 /// settlement, and other market operations.
738 ///
739 /// # Arguments
740 ///
741 /// * `index_type` - Optional filter by index type: "all", "spot", or "derivative"
742 ///
743 /// # Returns
744 ///
745 /// Returns a vector of index name strings (e.g., "btc_eth", "btc_usdc").
746 ///
747 /// # Errors
748 ///
749 /// Returns `HttpError` if the request fails or the response cannot be parsed.
750 ///
751 /// # Examples
752 ///
753 /// ```rust
754 /// use deribit_http::DeribitHttpClient;
755 ///
756 /// let client = DeribitHttpClient::new();
757 /// // Get all index names
758 /// // let names = client.get_supported_index_names(None).await?;
759 /// // for name in names {
760 /// // println!("Index: {}", name);
761 /// // }
762 /// //
763 /// // Get only spot indexes
764 /// // let spot_names = client.get_supported_index_names(Some("spot")).await?;
765 /// ```
766 pub async fn get_supported_index_names(
767 &self,
768 index_type: Option<&str>,
769 ) -> Result<Vec<String>, HttpError> {
770 let query = match index_type {
771 Some(t) => format!("?type={}", urlencoding::encode(t)),
772 None => String::new(),
773 };
774 self.public_get(GET_SUPPORTED_INDEX_NAMES, &query).await
775 }
776
777 /// Get supported index names with extended information
778 ///
779 /// Retrieves the identifiers (names) of all supported price indexes
780 /// along with combo trading availability flags.
781 ///
782 /// # Arguments
783 ///
784 /// * `index_type` - Optional filter by index type: "all", "spot", or "derivative"
785 ///
786 /// # Returns
787 ///
788 /// Returns a vector of `IndexNameInfo` containing index names and
789 /// optional combo trading flags.
790 ///
791 /// # Errors
792 ///
793 /// Returns `HttpError` if the request fails or the response cannot be parsed.
794 ///
795 /// # Examples
796 ///
797 /// ```rust
798 /// use deribit_http::DeribitHttpClient;
799 ///
800 /// let client = DeribitHttpClient::new();
801 /// // let indexes = client.get_supported_index_names_extended(None).await?;
802 /// // for idx in indexes {
803 /// // println!("Index: {}, Future combo: {:?}", idx.name, idx.future_combo_enabled);
804 /// // }
805 /// ```
806 pub async fn get_supported_index_names_extended(
807 &self,
808 index_type: Option<&str>,
809 ) -> Result<Vec<IndexNameInfo>, HttpError> {
810 let query = match index_type {
811 Some(t) => format!("?type={}&extended=true", urlencoding::encode(t)),
812 None => "?extended=true".to_string(),
813 };
814 self.public_get(GET_SUPPORTED_INDEX_NAMES, &query).await
815 }
816
817 /// Get trade volumes
818 ///
819 /// Retrieves aggregated 24-hour trade volumes for different instrument types
820 /// and currencies. Block trades and Block RFQ trades are included.
821 /// Position moves are not included.
822 ///
823 /// # Arguments
824 ///
825 /// * `extended` - If true, include 7-day and 30-day volumes
826 ///
827 /// # Returns
828 ///
829 /// Returns a vector of `TradeVolume` with volume data per currency.
830 ///
831 /// # Errors
832 ///
833 /// Returns `HttpError` if the request fails or the response cannot be parsed.
834 ///
835 /// # Examples
836 ///
837 /// ```rust
838 /// use deribit_http::DeribitHttpClient;
839 ///
840 /// let client = DeribitHttpClient::new();
841 /// // Get basic 24h volumes
842 /// // let volumes = client.get_trade_volumes(false).await?;
843 /// // for vol in volumes {
844 /// // println!("{}: futures={}, calls={}", vol.currency, vol.futures_volume, vol.calls_volume);
845 /// // }
846 /// //
847 /// // Get extended volumes (7d, 30d)
848 /// // let extended = client.get_trade_volumes(true).await?;
849 /// ```
850 pub async fn get_trade_volumes(&self, extended: bool) -> Result<Vec<TradeVolume>, HttpError> {
851 let query = if extended { "?extended=true" } else { "" };
852 self.public_get(GET_TRADE_VOLUMES, query).await
853 }
854
855 /// Get volatility index data
856 ///
857 /// Retrieves volatility index (VIX) chart data formatted as OHLC candles.
858 /// Useful for risk assessment and trading strategies.
859 ///
860 /// # Arguments
861 ///
862 /// * `currency` - Currency symbol (e.g., "BTC", "ETH")
863 /// * `start_timestamp` - Start timestamp in milliseconds since UNIX epoch
864 /// * `end_timestamp` - End timestamp in milliseconds since UNIX epoch
865 /// * `resolution` - Candle interval ("1", "60", "3600", "43200", "1D")
866 ///
867 /// # Returns
868 ///
869 /// Returns `VolatilityIndexData` with candles and optional continuation token.
870 ///
871 /// # Errors
872 ///
873 /// Returns `HttpError` if the request fails or the response cannot be parsed.
874 ///
875 /// # Examples
876 ///
877 /// ```rust
878 /// use deribit_http::DeribitHttpClient;
879 ///
880 /// let client = DeribitHttpClient::new();
881 /// // Get 1-hour VIX candles for BTC
882 /// // let vix_data = client.get_volatility_index_data(
883 /// // "BTC",
884 /// // 1599373800000,
885 /// // 1599376800000,
886 /// // "60"
887 /// // ).await?;
888 /// // for candle in &vix_data.data {
889 /// // println!("ts={}, close={}", candle.timestamp, candle.close);
890 /// // }
891 /// ```
892 pub async fn get_volatility_index_data(
893 &self,
894 currency: &str,
895 start_timestamp: u64,
896 end_timestamp: u64,
897 resolution: &str,
898 ) -> Result<VolatilityIndexData, HttpError> {
899 let query = format!(
900 "?currency={}&start_timestamp={}&end_timestamp={}&resolution={}",
901 currency, start_timestamp, end_timestamp, resolution
902 );
903 self.public_get(GET_VOLATILITY_INDEX_DATA, &query).await
904 }
905
906 /// Get funding chart data
907 ///
908 /// Retrieves the list of the latest PERPETUAL funding chart points within a given time period.
909 ///
910 /// # Arguments
911 ///
912 /// * `instrument_name` - Instrument name
913 /// * `length` - Time period (8h, 24h, 1m)
914 ///
915 /// # Examples
916 ///
917 /// ```rust
918 /// use deribit_http::DeribitHttpClient;
919 ///
920 /// let client = DeribitHttpClient::new();
921 /// // let funding_data = client.get_funding_chart_data("BTC-PERPETUAL", "8h").await?;
922 /// // tracing::info!("Current interest: {}", funding_data.current_interest);
923 /// ```
924 pub async fn get_funding_chart_data(
925 &self,
926 instrument_name: &str,
927 length: &str,
928 ) -> Result<FundingChartData, HttpError> {
929 let query = format!(
930 "?instrument_name={}&length={}",
931 urlencoding::encode(instrument_name),
932 urlencoding::encode(length)
933 );
934 self.public_get(GET_FUNDING_CHART_DATA, &query).await
935 }
936
937 /// Get TradingView chart data
938 ///
939 /// Publicly available market data used to generate a TradingView candle chart.
940 ///
941 /// # Arguments
942 ///
943 /// * `instrument_name` - Instrument name
944 /// * `start_timestamp` - Start timestamp in milliseconds
945 /// * `end_timestamp` - End timestamp in milliseconds
946 /// * `resolution` - Chart resolution (1, 3, 5, 10, 15, 30, 60, 120, 180, 360)
947 ///
948 /// # Examples
949 ///
950 /// ```rust
951 /// use deribit_http::DeribitHttpClient;
952 ///
953 /// let client = DeribitHttpClient::new();
954 /// // let chart_data = client.get_tradingview_chart_data("BTC-PERPETUAL", 1554373800000, 1554376800000, "30").await?;
955 /// // tracing::info!("Chart status: {}", chart_data.status);
956 /// ```
957 pub async fn get_tradingview_chart_data(
958 &self,
959 instrument_name: &str,
960 start_timestamp: u64,
961 end_timestamp: u64,
962 resolution: &str,
963 ) -> Result<TradingViewChartData, HttpError> {
964 let query = format!(
965 "?instrument_name={}&start_timestamp={}&end_timestamp={}&resolution={}",
966 urlencoding::encode(instrument_name),
967 start_timestamp,
968 end_timestamp,
969 urlencoding::encode(resolution)
970 );
971 self.public_get(GET_TRADINGVIEW_CHART_DATA, &query).await
972 }
973
974 /// Get delivery prices
975 ///
976 /// Retrieves delivery prices for the given index.
977 /// This is a public endpoint that doesn't require authentication.
978 ///
979 /// # Arguments
980 ///
981 /// * `index_name` - Index identifier (e.g., "btc_usd", "eth_usd")
982 /// * `count` - Number of requested items (optional, default 20)
983 /// * `offset` - Offset for pagination (optional, default 0)
984 ///
985 /// # Examples
986 ///
987 /// ```rust
988 /// # use deribit_http::DeribitHttpClient;
989 /// # #[tokio::main]
990 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
991 /// let client = DeribitHttpClient::new(); // testnet
992 /// let delivery_prices = client.get_delivery_prices("btc_usd", Some(5), Some(0)).await?;
993 /// for price in delivery_prices.data {
994 /// println!("Date: {} - Price: {}", price.date, price.delivery_price);
995 /// }
996 /// # Ok(())
997 /// # }
998 /// ```
999 pub async fn get_delivery_prices(
1000 &self,
1001 index_name: &str,
1002 count: Option<u32>,
1003 offset: Option<u32>,
1004 ) -> Result<DeliveryPricesResponse, HttpError> {
1005 let mut query = format!("?index_name={}", urlencoding::encode(index_name));
1006 if let Some(count) = count {
1007 query.push_str(&format!("&count={}", count));
1008 }
1009 if let Some(offset) = offset {
1010 query.push_str(&format!("&offset={}", offset));
1011 }
1012 self.public_get(GET_DELIVERY_PRICES, &query).await
1013 }
1014
1015 /// Get expirations
1016 ///
1017 /// Retrieves expirations for instruments. This method can be used to see instrument expirations.
1018 /// This is a public endpoint that doesn't require authentication.
1019 ///
1020 /// # Arguments
1021 ///
1022 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, any, grouped)
1023 /// * `kind` - Instrument kind (future, option, any)
1024 /// * `currency_pair` - Currency pair identifier (optional)
1025 ///
1026 pub async fn get_expirations(
1027 &self,
1028 currency: &str,
1029 kind: &str,
1030 currency_pair: Option<&str>,
1031 ) -> Result<ExpirationsResponse, HttpError> {
1032 let mut query = format!(
1033 "?currency={}&kind={}",
1034 urlencoding::encode(currency),
1035 urlencoding::encode(kind)
1036 );
1037 if let Some(currency_pair) = currency_pair {
1038 query.push_str(&format!(
1039 "¤cy_pair={}",
1040 urlencoding::encode(currency_pair)
1041 ));
1042 }
1043 self.public_get(GET_EXPIRATIONS, &query).await
1044 }
1045
1046 /// Get funding rate history
1047 ///
1048 /// Retrieves hourly historical interest rate for requested PERPETUAL instrument.
1049 /// This is a public endpoint that doesn't require authentication.
1050 ///
1051 /// # Arguments
1052 ///
1053 /// * `instrument_name` - Instrument name
1054 /// * `start_timestamp` - The earliest timestamp to return result from (milliseconds since UNIX epoch)
1055 /// * `end_timestamp` - The most recent timestamp to return result from (milliseconds since UNIX epoch)
1056 ///
1057 pub async fn get_funding_rate_history(
1058 &self,
1059 instrument_name: &str,
1060 start_timestamp: u64,
1061 end_timestamp: u64,
1062 ) -> Result<Vec<FundingRateData>, HttpError> {
1063 let query = format!(
1064 "?instrument_name={}&start_timestamp={}&end_timestamp={}",
1065 urlencoding::encode(instrument_name),
1066 start_timestamp,
1067 end_timestamp
1068 );
1069 self.public_get(GET_FUNDING_RATE_HISTORY, &query).await
1070 }
1071
1072 /// Get funding rate value
1073 ///
1074 /// Retrieves interest rate value for requested period. Applicable only for PERPETUAL instruments.
1075 /// This is a public endpoint that doesn't require authentication.
1076 ///
1077 /// # Arguments
1078 ///
1079 /// * `instrument_name` - Instrument name
1080 /// * `start_timestamp` - The earliest timestamp to return result from (milliseconds since UNIX epoch)
1081 /// * `end_timestamp` - The most recent timestamp to return result from (milliseconds since UNIX epoch)
1082 ///
1083 /// # Examples
1084 ///
1085 /// ```rust
1086 /// # use deribit_http::DeribitHttpClient;
1087 /// # #[tokio::main]
1088 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1089 /// let client = DeribitHttpClient::new(); // testnet
1090 /// let funding_rate = client.get_funding_rate_value("BTC-PERPETUAL", 1569888000000, 1569974400000).await?;
1091 /// println!("Funding rate for period: {}", funding_rate);
1092 /// # Ok(())
1093 /// # }
1094 /// ```
1095 pub async fn get_funding_rate_value(
1096 &self,
1097 instrument_name: &str,
1098 start_timestamp: u64,
1099 end_timestamp: u64,
1100 ) -> Result<f64, HttpError> {
1101 let query = format!(
1102 "?instrument_name={}&start_timestamp={}&end_timestamp={}",
1103 urlencoding::encode(instrument_name),
1104 start_timestamp,
1105 end_timestamp
1106 );
1107 self.public_get(GET_FUNDING_RATE_VALUE, &query).await
1108 }
1109
1110 /// Get last settlements by currency
1111 ///
1112 /// Retrieves historical settlement, delivery and bankruptcy events coming from all instruments within a given currency.
1113 /// This is a public endpoint that doesn't require authentication.
1114 ///
1115 /// # Arguments
1116 ///
1117 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
1118 /// * `settlement_type` - Settlement type (settlement, delivery, bankruptcy) - optional
1119 /// * `count` - Number of requested items (optional, default 20)
1120 /// * `continuation` - Continuation token for pagination (optional)
1121 /// * `search_start_timestamp` - The latest timestamp to return result from (optional)
1122 ///
1123 pub async fn get_last_settlements_by_currency(
1124 &self,
1125 currency: &str,
1126 settlement_type: Option<&str>,
1127 count: Option<u32>,
1128 continuation: Option<&str>,
1129 search_start_timestamp: Option<u64>,
1130 ) -> Result<SettlementsResponse, HttpError> {
1131 let mut query = format!("?currency={}", urlencoding::encode(currency));
1132 if let Some(settlement_type) = settlement_type {
1133 query.push_str(&format!("&type={}", urlencoding::encode(settlement_type)));
1134 }
1135 if let Some(count) = count {
1136 query.push_str(&format!("&count={}", count));
1137 }
1138 if let Some(continuation) = continuation {
1139 query.push_str(&format!(
1140 "&continuation={}",
1141 urlencoding::encode(continuation)
1142 ));
1143 }
1144 if let Some(search_start_timestamp) = search_start_timestamp {
1145 query.push_str(&format!(
1146 "&search_start_timestamp={}",
1147 search_start_timestamp
1148 ));
1149 }
1150 self.public_get(GET_LAST_SETTLEMENTS_BY_CURRENCY, &query)
1151 .await
1152 }
1153
1154 /// Get last settlements by instrument
1155 ///
1156 /// Retrieves historical public settlement, delivery and bankruptcy events filtered by instrument name.
1157 /// This is a public endpoint that doesn't require authentication.
1158 ///
1159 /// # Arguments
1160 ///
1161 /// * `instrument_name` - Instrument name
1162 /// * `settlement_type` - Settlement type (settlement, delivery, bankruptcy) - optional
1163 /// * `count` - Number of requested items (optional, default 20)
1164 /// * `continuation` - Continuation token for pagination (optional)
1165 /// * `search_start_timestamp` - The latest timestamp to return result from (optional)
1166 ///
1167 pub async fn get_last_settlements_by_instrument(
1168 &self,
1169 instrument_name: &str,
1170 settlement_type: Option<&str>,
1171 count: Option<u32>,
1172 continuation: Option<&str>,
1173 search_start_timestamp: Option<u64>,
1174 ) -> Result<SettlementsResponse, HttpError> {
1175 let mut query = format!("?instrument_name={}", urlencoding::encode(instrument_name));
1176 if let Some(settlement_type) = settlement_type {
1177 query.push_str(&format!("&type={}", urlencoding::encode(settlement_type)));
1178 }
1179 if let Some(count) = count {
1180 query.push_str(&format!("&count={}", count));
1181 }
1182 if let Some(continuation) = continuation {
1183 query.push_str(&format!(
1184 "&continuation={}",
1185 urlencoding::encode(continuation)
1186 ));
1187 }
1188 if let Some(search_start_timestamp) = search_start_timestamp {
1189 query.push_str(&format!(
1190 "&search_start_timestamp={}",
1191 search_start_timestamp
1192 ));
1193 }
1194 self.public_get(GET_LAST_SETTLEMENTS_BY_INSTRUMENT, &query)
1195 .await
1196 }
1197
1198 /// Get last trades by currency
1199 ///
1200 /// Retrieves the latest trades that have occurred for instruments in a specific currency.
1201 /// This is a public endpoint that doesn't require authentication.
1202 ///
1203 /// # Arguments
1204 ///
1205 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
1206 /// * `kind` - Instrument kind (future, option, spot, etc.) - optional
1207 /// * `count` - Number of requested items (optional, default 10)
1208 /// * `include_old` - Include trades older than 7 days (optional)
1209 /// * `sorting` - Direction of results sorting (optional)
1210 ///
1211 /// # Examples
1212 ///
1213 /// ```rust
1214 /// # use deribit_http::DeribitHttpClient;
1215 /// # #[tokio::main]
1216 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1217 /// let client = DeribitHttpClient::new(); // testnet
1218 /// let trades = client.get_last_trades_by_currency("BTC", Some("future"), Some(10), Some(false), Some("desc")).await?;
1219 /// for trade in trades.trades {
1220 /// println!("Trade: {} {} at {}", trade.amount, trade.instrument_name, trade.price);
1221 /// }
1222 /// # Ok(())
1223 /// # }
1224 /// ```
1225 pub async fn get_last_trades_by_currency(
1226 &self,
1227 currency: &str,
1228 kind: Option<&str>,
1229 count: Option<u32>,
1230 include_old: Option<bool>,
1231 sorting: Option<&str>,
1232 ) -> Result<LastTradesResponse, HttpError> {
1233 let mut query = format!("?currency={}", urlencoding::encode(currency));
1234 if let Some(kind) = kind {
1235 query.push_str(&format!("&kind={}", urlencoding::encode(kind)));
1236 }
1237 if let Some(count) = count {
1238 query.push_str(&format!("&count={}", count));
1239 }
1240 if let Some(include_old) = include_old {
1241 query.push_str(&format!("&include_old={}", include_old));
1242 }
1243 if let Some(sorting) = sorting {
1244 query.push_str(&format!("&sorting={}", urlencoding::encode(sorting)));
1245 }
1246 self.public_get(GET_LAST_TRADES_BY_CURRENCY, &query).await
1247 }
1248
1249 /// Get last trades by currency and time
1250 ///
1251 /// Retrieves the latest trades that have occurred for instruments in a specific currency within a time range.
1252 /// This is a public endpoint that doesn't require authentication.
1253 ///
1254 /// # Arguments
1255 ///
1256 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
1257 /// * `start_timestamp` - The earliest timestamp to return result from (milliseconds since UNIX epoch)
1258 /// * `end_timestamp` - The most recent timestamp to return result from (milliseconds since UNIX epoch)
1259 /// * `kind` - Instrument kind (future, option, spot, etc.) - optional
1260 /// * `count` - Number of requested items (optional, default 10)
1261 /// * `include_old` - Include trades older than 7 days (optional)
1262 /// * `sorting` - Direction of results sorting (optional)
1263 ///
1264 /// # Examples
1265 ///
1266 /// ```rust
1267 /// # use deribit_http::DeribitHttpClient;
1268 /// # #[tokio::main]
1269 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1270 /// let client = DeribitHttpClient::new(); // testnet
1271 /// let trades = client.get_last_trades_by_currency_and_time("BTC", 1569888000000, 1569974400000, Some("future"), Some(10), Some(false), Some("desc")).await?;
1272 /// for trade in trades.trades {
1273 /// println!("Trade: {} {} at {}", trade.amount, trade.instrument_name, trade.price);
1274 /// }
1275 /// # Ok(())
1276 /// # }
1277 /// ```
1278 #[allow(clippy::too_many_arguments)]
1279 pub async fn get_last_trades_by_currency_and_time(
1280 &self,
1281 currency: &str,
1282 start_timestamp: u64,
1283 end_timestamp: u64,
1284 kind: Option<&str>,
1285 count: Option<u32>,
1286 include_old: Option<bool>,
1287 sorting: Option<&str>,
1288 ) -> Result<LastTradesResponse, HttpError> {
1289 let mut query = format!(
1290 "?currency={}&start_timestamp={}&end_timestamp={}",
1291 urlencoding::encode(currency),
1292 start_timestamp,
1293 end_timestamp
1294 );
1295 if let Some(kind) = kind {
1296 query.push_str(&format!("&kind={}", urlencoding::encode(kind)));
1297 }
1298 if let Some(count) = count {
1299 query.push_str(&format!("&count={}", count));
1300 }
1301 if let Some(include_old) = include_old {
1302 query.push_str(&format!("&include_old={}", include_old));
1303 }
1304 if let Some(sorting) = sorting {
1305 query.push_str(&format!("&sorting={}", urlencoding::encode(sorting)));
1306 }
1307 self.public_get(GET_LAST_TRADES_BY_CURRENCY_AND_TIME, &query)
1308 .await
1309 }
1310
1311 /// Get last trades by instrument and time
1312 ///
1313 /// Retrieves the latest trades that have occurred for a specific instrument within a time range.
1314 /// This is a public endpoint that doesn't require authentication.
1315 ///
1316 /// # Arguments
1317 ///
1318 /// * `instrument_name` - Instrument name
1319 /// * `start_timestamp` - The earliest timestamp to return result from (milliseconds since UNIX epoch)
1320 /// * `end_timestamp` - The most recent timestamp to return result from (milliseconds since UNIX epoch)
1321 /// * `count` - Number of requested items (optional, default 10)
1322 /// * `include_old` - Include trades older than 7 days (optional)
1323 /// * `sorting` - Direction of results sorting (optional)
1324 ///
1325 /// # Examples
1326 ///
1327 /// ```rust
1328 /// # use deribit_http::DeribitHttpClient;
1329 /// # #[tokio::main]
1330 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1331 /// let client = DeribitHttpClient::new(); // testnet
1332 /// let trades = client.get_last_trades_by_instrument_and_time("BTC-PERPETUAL", 1569888000000, 1569974400000, Some(10), Some(false), Some("desc")).await?;
1333 /// for trade in trades.trades {
1334 /// println!("Trade: {} at {} ({})", trade.amount, trade.price, trade.direction);
1335 /// }
1336 /// # Ok(())
1337 /// # }
1338 /// ```
1339 pub async fn get_last_trades_by_instrument_and_time(
1340 &self,
1341 instrument_name: &str,
1342 start_timestamp: u64,
1343 end_timestamp: u64,
1344 count: Option<u32>,
1345 include_old: Option<bool>,
1346 sorting: Option<&str>,
1347 ) -> Result<LastTradesResponse, HttpError> {
1348 let mut query = format!(
1349 "?instrument_name={}&start_timestamp={}&end_timestamp={}",
1350 urlencoding::encode(instrument_name),
1351 start_timestamp,
1352 end_timestamp
1353 );
1354 if let Some(count) = count {
1355 query.push_str(&format!("&count={}", count));
1356 }
1357 if let Some(include_old) = include_old {
1358 query.push_str(&format!("&include_old={}", include_old));
1359 }
1360 if let Some(sorting) = sorting {
1361 query.push_str(&format!("&sorting={}", urlencoding::encode(sorting)));
1362 }
1363 self.public_get(GET_LAST_TRADES_BY_INSTRUMENT_AND_TIME, &query)
1364 .await
1365 }
1366
1367 /// Get order book by instrument ID
1368 ///
1369 /// Retrieves the order book for the specified instrument by its ID.
1370 /// This is a public endpoint that doesn't require authentication.
1371 ///
1372 /// # Arguments
1373 ///
1374 /// * `instrument_id` - Instrument ID
1375 /// * `depth` - The number of entries to return for bid and ask order book entries (optional)
1376 ///
1377 /// # Examples
1378 ///
1379 /// ```rust,no_run
1380 /// # use deribit_http::DeribitHttpClient;
1381 /// # #[tokio::main]
1382 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1383 /// let client = DeribitHttpClient::new(); // testnet
1384 /// let order_book = client.get_order_book_by_instrument_id(42, Some(5)).await?;
1385 /// println!("Order book for {}: {} bids, {} asks",
1386 /// order_book.instrument_name,
1387 /// order_book.bids.len(),
1388 /// order_book.asks.len());
1389 /// # Ok(())
1390 /// # }
1391 /// ```
1392 pub async fn get_order_book_by_instrument_id(
1393 &self,
1394 instrument_id: u32,
1395 depth: Option<u32>,
1396 ) -> Result<OrderBook, HttpError> {
1397 let mut query = format!("?instrument_id={}", instrument_id);
1398 if let Some(depth) = depth {
1399 query.push_str(&format!("&depth={}", depth));
1400 }
1401 self.public_get(GET_ORDER_BOOK_BY_INSTRUMENT_ID, &query)
1402 .await
1403 }
1404
1405 /// Get platform announcements
1406 ///
1407 /// Retrieves announcements from the platform. Default start_timestamp is current time,
1408 /// count must be between 1 and 50 (default is 5).
1409 ///
1410 /// # Arguments
1411 ///
1412 /// * `count` - Number of announcements to retrieve (1-50, default 5)
1413 /// * `start_timestamp` - Optional timestamp to start from in milliseconds
1414 ///
1415 /// # Examples
1416 ///
1417 /// ```rust
1418 /// # use deribit_http::DeribitHttpClient;
1419 /// # #[tokio::main]
1420 /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
1421 /// let client = DeribitHttpClient::new();
1422 /// let announcements = client.get_announcements(Some(10), None).await?;
1423 /// for announcement in announcements {
1424 /// println!("Announcement: {}", announcement.title);
1425 /// }
1426 /// # Ok(())
1427 /// # }
1428 /// ```
1429 pub async fn get_announcements(
1430 &self,
1431 count: Option<u32>,
1432 start_timestamp: Option<u64>,
1433 ) -> Result<Vec<crate::model::Announcement>, HttpError> {
1434 let mut query_params = Vec::new();
1435 if let Some(count) = count {
1436 query_params.push(format!("count={}", count));
1437 }
1438 if let Some(ts) = start_timestamp {
1439 query_params.push(format!("start_timestamp={}", ts));
1440 }
1441 let query = if query_params.is_empty() {
1442 String::new()
1443 } else {
1444 format!("?{}", query_params.join("&"))
1445 };
1446 self.public_get(crate::constants::endpoints::GET_ANNOUNCEMENTS, &query)
1447 .await
1448 }
1449
1450 // ========================================================================
1451 // Combo Books Endpoints
1452 // ========================================================================
1453
1454 /// Get combo details by ID
1455 ///
1456 /// Retrieves information about a specific combo instrument.
1457 /// This is a public endpoint that doesn't require authentication.
1458 ///
1459 /// # Arguments
1460 ///
1461 /// * `combo_id` - The combo identifier (e.g., "BTC-FS-29APR22_PERP")
1462 ///
1463 /// # Errors
1464 ///
1465 /// Returns `HttpError` if the request fails or the response is invalid.
1466 ///
1467 /// # Examples
1468 ///
1469 /// ```rust,no_run
1470 /// use deribit_http::DeribitHttpClient;
1471 ///
1472 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1473 /// let client = DeribitHttpClient::new();
1474 /// let combo = client.get_combo_details("BTC-FS-29APR22_PERP").await?;
1475 /// println!("Combo {} has {} legs", combo.id, combo.legs.len());
1476 /// # Ok(())
1477 /// # }
1478 /// ```
1479 pub async fn get_combo_details(
1480 &self,
1481 combo_id: &str,
1482 ) -> Result<crate::model::Combo, HttpError> {
1483 let query = format!("?combo_id={}", urlencoding::encode(combo_id));
1484 self.public_get(GET_COMBO_DETAILS, &query).await
1485 }
1486
1487 /// Get combo IDs by currency
1488 ///
1489 /// Retrieves the list of available combo IDs for the specified currency.
1490 /// This is a public endpoint that doesn't require authentication.
1491 ///
1492 /// # Arguments
1493 ///
1494 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR)
1495 /// * `state` - Optional combo state filter (rfq, active, inactive)
1496 ///
1497 /// # Errors
1498 ///
1499 /// Returns `HttpError` if the request fails or the response is invalid.
1500 ///
1501 /// # Examples
1502 ///
1503 /// ```rust,no_run
1504 /// use deribit_http::DeribitHttpClient;
1505 ///
1506 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1507 /// let client = DeribitHttpClient::new();
1508 /// let combo_ids = client.get_combo_ids("BTC", Some("active")).await?;
1509 /// println!("Found {} active combos", combo_ids.len());
1510 /// # Ok(())
1511 /// # }
1512 /// ```
1513 pub async fn get_combo_ids(
1514 &self,
1515 currency: &str,
1516 state: Option<&str>,
1517 ) -> Result<Vec<String>, HttpError> {
1518 let mut query = format!("?currency={}", urlencoding::encode(currency));
1519 if let Some(s) = state {
1520 query.push_str(&format!("&state={}", urlencoding::encode(s)));
1521 }
1522 self.public_get(GET_COMBO_IDS, &query).await
1523 }
1524
1525 /// Get all active combos by currency
1526 ///
1527 /// Retrieves information about all active combo instruments for a currency.
1528 /// This is a public endpoint that doesn't require authentication.
1529 ///
1530 /// # Arguments
1531 ///
1532 /// * `currency` - The currency symbol (BTC, ETH, USDC, USDT, EURR, or "any" for all)
1533 ///
1534 /// # Errors
1535 ///
1536 /// Returns `HttpError` if the request fails or the response is invalid.
1537 ///
1538 /// # Examples
1539 ///
1540 /// ```rust,no_run
1541 /// use deribit_http::DeribitHttpClient;
1542 ///
1543 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1544 /// let client = DeribitHttpClient::new();
1545 /// let combos = client.get_combos("BTC").await?;
1546 /// for combo in combos {
1547 /// println!("Combo: {} ({:?})", combo.id, combo.state);
1548 /// }
1549 /// # Ok(())
1550 /// # }
1551 /// ```
1552 pub async fn get_combos(&self, currency: &str) -> Result<Vec<crate::model::Combo>, HttpError> {
1553 let query = format!("?currency={}", urlencoding::encode(currency));
1554 self.public_get(GET_COMBOS, &query).await
1555 }
1556
1557 /// Retrieves a list of recent Block RFQ trades.
1558 ///
1559 /// This is a public method that provides market data about completed Block RFQ trades.
1560 /// Can be optionally filtered by currency.
1561 ///
1562 /// # Arguments
1563 ///
1564 /// * `currency` - Optional currency filter (e.g., "BTC", "ETH")
1565 /// * `count` - Optional number of trades to return (max 1000)
1566 /// * `continuation` - Optional continuation token for pagination
1567 ///
1568 /// # Returns
1569 ///
1570 /// Returns a `BlockRfqTradesResponse` containing the list of trades and pagination info.
1571 ///
1572 /// # Errors
1573 ///
1574 /// Returns `HttpError` if the request fails or the response cannot be parsed.
1575 ///
1576 /// # Examples
1577 ///
1578 /// ```no_run
1579 /// use deribit_http::DeribitHttpClient;
1580 ///
1581 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1582 /// let client = DeribitHttpClient::builder().testnet().build()?;
1583 /// let trades = client.get_block_rfq_trades(Some("BTC"), Some(20), None).await?;
1584 /// println!("Found {} Block RFQ trades", trades.len());
1585 /// # Ok(())
1586 /// # }
1587 /// ```
1588 pub async fn get_block_rfq_trades(
1589 &self,
1590 currency: Option<&str>,
1591 count: Option<u32>,
1592 continuation: Option<&str>,
1593 ) -> Result<crate::model::response::BlockRfqTradesResponse, HttpError> {
1594 let mut query_params: Vec<String> = Vec::new();
1595 if let Some(curr) = currency {
1596 query_params.push(format!("currency={}", curr));
1597 }
1598 if let Some(c) = count {
1599 query_params.push(format!("count={}", c));
1600 }
1601 if let Some(cont) = continuation {
1602 query_params.push(format!("continuation={}", cont));
1603 }
1604 let query = if query_params.is_empty() {
1605 String::new()
1606 } else {
1607 format!("?{}", query_params.join("&"))
1608 };
1609 self.public_get(crate::constants::endpoints::GET_BLOCK_RFQ_TRADES, &query)
1610 .await
1611 }
1612}