1use std::fmt;
2
3use serde::de::{Error, SeqAccess, Unexpected, Visitor};
4use serde::{Deserialize, Deserializer};
5
6#[derive(Debug)]
8pub enum CandleInterval {
9 OneMinute,
10 FiveMinutes,
11 FifteenMinutes,
12 ThirtyMinutes,
13 OneHour,
14 TwoHours,
15 FourHours,
16 SixHours,
17 EightHours,
18 TwelveHours,
19 OneDay,
20}
21
22impl fmt::Display for CandleInterval {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 CandleInterval::OneMinute => write!(f, "1m"),
26 CandleInterval::FiveMinutes => write!(f, "5m"),
27 CandleInterval::FifteenMinutes => write!(f, "15m"),
28 CandleInterval::ThirtyMinutes => write!(f, "30m"),
29 CandleInterval::OneHour => write!(f, "1h"),
30 CandleInterval::TwoHours => write!(f, "2h"),
31 CandleInterval::FourHours => write!(f, "4h"),
32 CandleInterval::SixHours => write!(f, "6h"),
33 CandleInterval::EightHours => write!(f, "8h"),
34 CandleInterval::TwelveHours => write!(f, "12h"),
35 CandleInterval::OneDay => write!(f, "1d"),
36 }
37 }
38}
39
40#[derive(Debug)]
42pub struct OHLCV {
43 pub time: u64,
44 pub open: String,
45 pub high: String,
46 pub low: String,
47 pub close: String,
48 pub volume: String,
49}
50
51macro_rules! next_seq_element {
52 ($seq:ident, $name:ident) => {
53 $seq.next_element()?
54 .ok_or_else(|| A::Error::missing_field(stringify!($name)))?
55 };
56}
57
58impl<'de> Deserialize<'de> for OHLCV {
59 fn deserialize<D>(deserializer: D) -> crate::Result<Self, D::Error>
60 where
61 D: Deserializer<'de>,
62 {
63 struct OHLCVVisitor;
64
65 impl<'de> Visitor<'de> for OHLCVVisitor {
66 type Value = OHLCV;
67
68 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 write!(f, "OHLCV")
70 }
71
72 fn visit_seq<A>(self, mut seq: A) -> crate::Result<Self::Value, A::Error>
73 where
74 A: SeqAccess<'de>,
75 {
76 Ok(OHLCV {
77 time: next_seq_element!(seq, time),
78 open: next_seq_element!(seq, open),
79 high: next_seq_element!(seq, high),
80 low: next_seq_element!(seq, low),
81 close: next_seq_element!(seq, close),
82 volume: next_seq_element!(seq, volume),
83 })
84 }
85 }
86
87 deserializer.deserialize_seq(OHLCVVisitor)
88 }
89}
90
91#[derive(Debug, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct Asset {
95 pub symbol: String,
96 pub name: String,
97 pub decimals: u64,
98 pub deposit_fee: String,
99 pub deposit_confirmations: u64,
100 pub deposit_status: AssetStatus,
101 pub withdrawal_fee: String,
102 pub withdrawal_min_amount: String,
103 pub withdrawal_status: AssetStatus,
104 pub networks: Vec<String>,
105 pub message: Option<String>,
106}
107
108#[derive(Debug)]
110pub enum AssetStatus {
111 Ok,
112 Maintenance,
113 Delisted,
114}
115
116impl<'de> Deserialize<'de> for AssetStatus {
117 fn deserialize<D>(deserializer: D) -> crate::Result<AssetStatus, D::Error>
118 where
119 D: Deserializer<'de>,
120 {
121 let s = String::deserialize(deserializer)?;
122
123 match s.as_str() {
124 "OK" => Ok(AssetStatus::Ok),
125 "MAINTENANCE" => Ok(AssetStatus::Maintenance),
126 "DELISTED" => Ok(AssetStatus::Delisted),
127 s => Err(D::Error::invalid_value(
128 Unexpected::Str(s),
129 &"[OK, MAINTENANCE, DELISTED]",
130 )),
131 }
132 }
133}
134
135#[derive(Debug, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct Market {
139 #[serde(rename = "market")]
140 pub pair: String,
141 pub status: MarketStatus,
142 pub base: String,
143 pub quote: String,
144 pub price_precision: u64,
145 pub min_order_in_base_asset: String,
146 pub min_order_in_quote_asset: String,
147 pub max_order_in_base_asset: String,
148 pub max_order_in_quote_asset: String,
149 pub order_types: Vec<String>,
150}
151
152#[derive(Debug)]
154pub enum MarketStatus {
155 Trading,
156 Halted,
157 Auction,
158}
159
160impl<'de> Deserialize<'de> for MarketStatus {
161 fn deserialize<D>(deserializer: D) -> crate::Result<MarketStatus, D::Error>
162 where
163 D: Deserializer<'de>,
164 {
165 let s = String::deserialize(deserializer)?;
166
167 match s.as_str() {
168 "trading" => Ok(MarketStatus::Trading),
169 "halted" => Ok(MarketStatus::Halted),
170 "auction" => Ok(MarketStatus::Auction),
171 s => Err(D::Error::invalid_value(
172 Unexpected::Str(s),
173 &"[trading, halted, auction]",
174 )),
175 }
176 }
177}
178
179#[derive(Debug, Deserialize)]
181pub struct OrderBook {
182 pub market: String,
183 pub nonce: u64,
184 pub bids: Vec<Quote>,
185 pub asks: Vec<Quote>,
186}
187
188#[derive(Debug)]
190pub struct Quote {
191 pub price: String,
192 pub amount: String,
193}
194
195impl<'de> Deserialize<'de> for Quote {
196 fn deserialize<D>(deserializer: D) -> crate::Result<Self, D::Error>
197 where
198 D: Deserializer<'de>,
199 {
200 struct QuoteVisitor;
201
202 impl<'de> Visitor<'de> for QuoteVisitor {
203 type Value = Quote;
204
205 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
206 write!(f, "Quote")
207 }
208
209 fn visit_seq<A>(self, mut seq: A) -> crate::Result<Self::Value, A::Error>
210 where
211 A: SeqAccess<'de>,
212 {
213 Ok(Quote {
214 price: next_seq_element!(seq, price),
215 amount: next_seq_element!(seq, amount),
216 })
217 }
218 }
219
220 deserializer.deserialize_seq(QuoteVisitor)
221 }
222}
223
224#[derive(Debug, Deserialize)]
226pub struct Trade {
227 pub id: String,
228 pub timestamp: u64,
229 pub amount: String,
230 pub price: String,
231 pub side: TradeSide,
232}
233
234#[derive(Debug)]
236pub enum TradeSide {
237 Buy,
238 Sell,
239}
240
241impl<'de> Deserialize<'de> for TradeSide {
242 fn deserialize<D>(deserializer: D) -> crate::Result<TradeSide, D::Error>
243 where
244 D: Deserializer<'de>,
245 {
246 let s = String::deserialize(deserializer)?;
247
248 match s.as_str() {
249 "buy" => Ok(TradeSide::Buy),
250 "sell" => Ok(TradeSide::Sell),
251 s => Err(D::Error::invalid_value(Unexpected::Str(s), &"[buy, sell]")),
252 }
253 }
254}
255
256#[derive(Debug, Deserialize)]
258pub struct TickerPrice {
259 pub market: String,
260 pub price: Option<String>,
261}
262
263#[derive(Debug, Deserialize)]
265#[serde(rename_all = "camelCase")]
266pub struct TickerBook {
267 pub market: Option<String>,
268 pub bid: Option<String>,
269 pub bid_size: Option<String>,
270 pub ask: Option<String>,
271 pub ask_size: Option<String>,
272}
273
274#[derive(Debug, Deserialize)]
276#[serde(rename_all = "camelCase")]
277pub struct Ticker24h {
278 pub market: String,
279 pub start_timestamp: Option<u64>,
280 pub timestamp: Option<u64>,
281 pub open: Option<String>,
282 pub open_timestamp: Option<u64>,
283 pub high: Option<String>,
284 pub low: Option<String>,
285 pub last: Option<String>,
286 pub close_timestamp: Option<u64>,
287 pub bid: Option<String>,
288 pub bid_size: Option<String>,
289 pub ask: Option<String>,
290 pub ask_size: Option<String>,
291 pub volume: Option<String>,
292 pub volume_quote: Option<String>,
293}