mexc_rust_sdk/
market.rs

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        // limit: default 100; max 5000
156
157        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}