1use crate::{Mexc, PROD_API_URL, utils::parse_string_to_f64};
2use serde::Deserialize;
3use serde::de::{self, Visitor, SeqAccess};
4use std::fmt;
5use serde::Deserializer;
6
7
8
9#[derive(Deserialize, Debug)]
10pub struct Orderbook {
11 pub timestamp: u128,
12 pub bids: Vec<Level>,
13 pub asks: Vec<Level>
14}
15
16#[derive(Deserialize, Debug)]
17pub struct ExchangeInfo {
18 #[serde(rename= "serverTime")]
19 pub timestamp: u128,
20 pub symbols: Vec<SymbolInfo>
21}
22
23#[allow(dead_code)]
24#[derive(Deserialize, Debug)]
25pub struct SymbolInfo {
26 #[serde(rename = "baseAsset")]
27 pub base_asset: String,
28
29 #[serde(rename = "baseAssetPrecision")]
30 pub base_asset_precision: u32,
31
32 #[serde(rename = "baseCommissionPrecision")]
33 pub base_commission_precision: u32,
34
35 #[serde(rename = "baseSizePrecision", deserialize_with = "parse_string_to_f64")]
36 pub base_size_precision: f64,
37
38 #[serde(rename = "filters")]
39 pub filters: Vec<String>,
40
41 #[serde(rename = "fullName")]
42 pub full_name: String,
43
44 #[serde(rename = "isMarginTradingAllowed")]
45 pub is_margin_trading_allowed: bool,
46
47 #[serde(rename = "isSpotTradingAllowed")]
48 pub is_spot_trading_allowed: bool,
49
50 #[serde(rename = "makerCommission", deserialize_with = "parse_string_to_f64")]
51 pub maker_commission: f64,
52
53 #[serde(rename = "maxQuoteAmount", deserialize_with = "parse_string_to_f64")]
54 pub max_quote_amount: f64,
55
56 #[serde(rename = "maxQuoteAmountMarket", deserialize_with = "parse_string_to_f64")]
57 pub max_quote_amount_market: f64,
58
59 #[serde(rename = "orderTypes")]
60 pub order_types: Vec<String>,
61
62 #[serde(rename = "permissions")]
63 pub permissions: Vec<String>,
64
65 #[serde(rename = "quoteAmountPrecision", deserialize_with = "parse_string_to_f64")]
66 pub quote_amount_precision: f64,
67
68 #[serde(rename = "quoteAmountPrecisionMarket", deserialize_with = "parse_string_to_f64")]
69 pub quote_amount_precision_market: f64,
70
71 #[serde(rename = "quoteAsset")]
72 pub quote_asset: String,
73
74 #[serde(rename = "quoteAssetPrecision")]
75 pub quote_asset_precision: u32,
76
77 #[serde(rename = "quoteCommissionPrecision")]
78 pub quote_commission_precision: u32,
79
80 #[serde(rename = "quotePrecision")]
81 pub quote_precision: u32,
82
83 #[serde(rename = "status")]
84 pub status: String,
85
86 #[serde(rename = "symbol")]
87 pub symbol: String,
88
89 #[serde(rename = "takerCommission", deserialize_with = "parse_string_to_f64")]
90 pub taker_commission: f64,
91}
92
93#[derive(Debug)]
94pub struct Level {
95 pub px: f64,
96 pub sz: f64
97}
98
99impl<'de> Deserialize<'de> for Level {
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where
102 D: Deserializer<'de>,
103 {
104 struct LevelVisitor;
105
106 impl<'de> Visitor<'de> for LevelVisitor {
107 type Value = Level;
108
109 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
110 formatter.write_str("a two-element array [px, sz]")
111 }
112
113 fn visit_seq<V>(self, mut seq: V) -> Result<Level, V::Error>
114 where
115 V: SeqAccess<'de>,
116 {
117 let px: String = seq
118 .next_element()?
119 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
120 let sz: String = seq
121 .next_element()?
122 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
123
124 let px: f64 = px.parse().map_err(de::Error::custom)?;
125 let sz: f64 = sz.parse().map_err(de::Error::custom)?;
126
127 Ok(Level { px, sz })
128 }
129 }
130
131 deserializer.deserialize_seq(LevelVisitor)
132 }
133}
134
135impl Mexc {
136
137 pub async fn symbol_info(&self, symbol: &str) -> anyhow::Result<ExchangeInfo> {
138 let url = format!("{PROD_API_URL}/api/v3/exchangeInfo?symbol={symbol}");
139 let resp = self.client.get(url).send().await?;
140
141 let exchange_info: ExchangeInfo = resp.json().await?;
142 Ok(exchange_info)
143 }
144
145 pub async fn exchange_info(&self) -> anyhow::Result<ExchangeInfo> {
146 let url = format!("{PROD_API_URL}/api/v3/exchangeInfo");
147 let resp = self.client.get(url).send().await?;
148
149 let exchange_info: ExchangeInfo = resp.json().await?;
150 Ok(exchange_info)
151 }
152
153 pub async fn get_spot_orderbook(&self, symbol: &str, depth: Option<u32>) -> anyhow::Result<Orderbook> {
154
155 let url = if let Some(limit) = depth {
158 format!("{PROD_API_URL}/api/v3/depth?symbol={symbol}&limit={limit}")
159 } else {
160 format!("{PROD_API_URL}/api/v3/depth?symbol={symbol}")
161 };
162 let resp = self.client.get(url).send().await?;
163
164 let orderbook: Orderbook = resp.json().await?;
165 Ok(orderbook)
166 }
167}