Skip to main content

binance_api_client/
types.rs

1//! Common types used across the Binance API.
2//!
3//! This module contains enums and types that are shared between
4//! different API endpoints.
5
6use serde::{Deserialize, Serialize};
7
8/// Order side (buy or sell).
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
10#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
11pub enum OrderSide {
12    /// Buy order
13    #[default]
14    Buy,
15    /// Sell order
16    Sell,
17}
18
19/// Order type.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
21#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
22pub enum OrderType {
23    /// Limit order - specify price and quantity
24    Limit,
25    /// Market order - execute at current market price
26    #[default]
27    Market,
28    /// Stop loss order - triggers market order when stop price is reached
29    StopLoss,
30    /// Stop loss limit order - triggers limit order when stop price is reached
31    StopLossLimit,
32    /// Take profit order - triggers market order when target price is reached
33    TakeProfit,
34    /// Take profit limit order - triggers limit order when target price is reached
35    TakeProfitLimit,
36    /// Limit maker order - rejected if it would immediately match
37    LimitMaker,
38    /// Unknown order type
39    #[serde(other)]
40    Other,
41}
42
43/// Time in force - how long an order remains active.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
45pub enum TimeInForce {
46    /// Good Till Canceled - order remains until filled or canceled
47    #[default]
48    GTC,
49    /// Immediate Or Cancel - fill as much as possible, cancel the rest
50    IOC,
51    /// Fill Or Kill - fill completely or cancel entirely
52    FOK,
53    /// Good Till Crossing - only for Post Only orders
54    GTX,
55    /// Unknown time in force
56    #[serde(other)]
57    Other,
58}
59
60/// Order status.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
62#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
63pub enum OrderStatus {
64    /// The order has been accepted by the engine
65    New,
66    /// A part of the order has been filled
67    PartiallyFilled,
68    /// The order has been completely filled
69    Filled,
70    /// The order has been canceled by the user
71    Canceled,
72    /// Currently unused
73    PendingCancel,
74    /// The order was not accepted by the engine and not processed
75    Rejected,
76    /// The order was canceled according to the order type's rules
77    Expired,
78    /// The order was canceled by the exchange due to STP trigger
79    ExpiredInMatch,
80}
81
82/// Execution type for order updates.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
84#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
85pub enum ExecutionType {
86    /// The order has been accepted into the engine
87    New,
88    /// The order has been canceled by the user
89    Canceled,
90    /// Currently unused
91    Replaced,
92    /// The order has been rejected
93    Rejected,
94    /// Part of the order or all of the order's quantity has filled
95    Trade,
96    /// The order was canceled according to the order type's rules
97    Expired,
98    /// The order has expired due to STP trigger
99    TradePrevention,
100    /// Order modified
101    Amendment,
102}
103
104/// Kline/candlestick interval.
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
106pub enum KlineInterval {
107    /// 1 second
108    #[serde(rename = "1s")]
109    Seconds1,
110    /// 1 minute
111    #[serde(rename = "1m")]
112    Minutes1,
113    /// 3 minutes
114    #[serde(rename = "3m")]
115    Minutes3,
116    /// 5 minutes
117    #[serde(rename = "5m")]
118    Minutes5,
119    /// 15 minutes
120    #[serde(rename = "15m")]
121    Minutes15,
122    /// 30 minutes
123    #[serde(rename = "30m")]
124    Minutes30,
125    /// 1 hour
126    #[serde(rename = "1h")]
127    Hours1,
128    /// 2 hours
129    #[serde(rename = "2h")]
130    Hours2,
131    /// 4 hours
132    #[serde(rename = "4h")]
133    Hours4,
134    /// 6 hours
135    #[serde(rename = "6h")]
136    Hours6,
137    /// 8 hours
138    #[serde(rename = "8h")]
139    Hours8,
140    /// 12 hours
141    #[serde(rename = "12h")]
142    Hours12,
143    /// 1 day
144    #[serde(rename = "1d")]
145    Days1,
146    /// 3 days
147    #[serde(rename = "3d")]
148    Days3,
149    /// 1 week
150    #[serde(rename = "1w")]
151    Weeks1,
152    /// 1 month
153    #[serde(rename = "1M")]
154    Months1,
155}
156
157impl std::fmt::Display for KlineInterval {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        let s = match self {
160            Self::Seconds1 => "1s",
161            Self::Minutes1 => "1m",
162            Self::Minutes3 => "3m",
163            Self::Minutes5 => "5m",
164            Self::Minutes15 => "15m",
165            Self::Minutes30 => "30m",
166            Self::Hours1 => "1h",
167            Self::Hours2 => "2h",
168            Self::Hours4 => "4h",
169            Self::Hours6 => "6h",
170            Self::Hours8 => "8h",
171            Self::Hours12 => "12h",
172            Self::Days1 => "1d",
173            Self::Days3 => "3d",
174            Self::Weeks1 => "1w",
175            Self::Months1 => "1M",
176        };
177        write!(f, "{}", s)
178    }
179}
180
181/// Ticker response type for market data endpoints.
182#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
183#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
184pub enum TickerType {
185    /// Full response payload.
186    Full,
187    /// Mini response payload.
188    Mini,
189}
190
191impl std::fmt::Display for TickerType {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        let s = match self {
194            Self::Full => "FULL",
195            Self::Mini => "MINI",
196        };
197        write!(f, "{}", s)
198    }
199}
200
201/// Symbol status.
202#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
203#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
204pub enum SymbolStatus {
205    /// Pre-trading period
206    PreTrading,
207    /// Currently trading
208    Trading,
209    /// Post-trading period
210    PostTrading,
211    /// End of day
212    EndOfDay,
213    /// Trading halted
214    Halt,
215    /// Auction match
216    AuctionMatch,
217    /// Trading break
218    Break,
219    /// Pending trading
220    PendingTrading,
221    /// Unknown status
222    #[serde(other)]
223    Other,
224}
225
226impl std::fmt::Display for SymbolStatus {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        let s = match self {
229            Self::PreTrading => "PRE_TRADING",
230            Self::Trading => "TRADING",
231            Self::PostTrading => "POST_TRADING",
232            Self::EndOfDay => "END_OF_DAY",
233            Self::Halt => "HALT",
234            Self::AuctionMatch => "AUCTION_MATCH",
235            Self::Break => "BREAK",
236            Self::PendingTrading => "PENDING_TRADING",
237            Self::Other => "OTHER",
238        };
239        write!(f, "{}", s)
240    }
241}
242
243/// Symbol permission type.
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
245#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
246pub enum SymbolPermission {
247    /// Spot trading
248    Spot,
249    /// Margin trading
250    Margin,
251    /// Unknown permission
252    #[serde(other)]
253    Other,
254}
255
256/// Account type.
257#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
258#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
259pub enum AccountType {
260    /// Spot account
261    Spot,
262    /// USDT futures account
263    UsdtFuture,
264    /// Coin futures account
265    CoinFuture,
266    /// Leveraged account
267    Leveraged,
268    /// Unknown account type
269    #[serde(other)]
270    Other,
271}
272
273/// Rate limit type.
274#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
275#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
276pub enum RateLimitType {
277    /// Request weight limit
278    RequestWeight,
279    /// Orders limit
280    Orders,
281    /// Raw requests limit
282    RawRequests,
283    /// Unknown limit type
284    #[serde(other)]
285    Other,
286}
287
288/// Rate limit interval.
289#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
290#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
291pub enum RateLimitInterval {
292    /// Per second
293    Second,
294    /// Per minute
295    Minute,
296    /// Per day
297    Day,
298}
299
300/// Order response type for new orders.
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
302#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
303pub enum OrderResponseType {
304    /// Acknowledgement only
305    Ack,
306    /// Result with order details
307    Result,
308    /// Full response with fills
309    Full,
310    /// Unknown response type
311    #[serde(other)]
312    Other,
313}
314
315/// OCO order status.
316#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
317#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
318pub enum OcoStatus {
319    /// Response received
320    Response,
321    /// Execution started
322    ExecStarted,
323    /// All done
324    AllDone,
325}
326
327/// OCO order status.
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
329#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
330pub enum OcoOrderStatus {
331    /// Executing
332    Executing,
333    /// All done
334    AllDone,
335    /// Rejected
336    Reject,
337}
338
339/// Contingency type for OCO orders.
340#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
341#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
342pub enum ContingencyType {
343    /// One Cancels Other
344    Oco,
345    /// One-Triggers-the-Other
346    Oto,
347    /// One-Triggers-One-Cancels-the-Other
348    Otoco,
349    /// One-Places-the-Other
350    Opo,
351    /// One-Places-One-Cancels-the-Other
352    Opoco,
353    /// Unknown contingency type
354    #[serde(other)]
355    Other,
356}
357
358/// Cancel-replace mode.
359#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
360#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
361pub enum CancelReplaceMode {
362    /// Stop if the cancel fails.
363    StopOnFailure,
364    /// Allow new order placement even if cancel fails.
365    AllowFailure,
366}
367
368impl std::fmt::Display for CancelReplaceMode {
369    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370        let s = match self {
371            Self::StopOnFailure => "STOP_ON_FAILURE",
372            Self::AllowFailure => "ALLOW_FAILURE",
373        };
374        write!(f, "{}", s)
375    }
376}
377
378/// Cancel-replace result status.
379#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
380#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
381pub enum CancelReplaceResult {
382    /// Operation succeeded.
383    Success,
384    /// Operation failed.
385    Failure,
386    /// Operation was not attempted.
387    NotAttempted,
388}
389
390/// Cancel restrictions for cancel-replace.
391#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
392#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
393pub enum CancelRestrictions {
394    /// Cancel only if the order is NEW.
395    OnlyNew,
396    /// Cancel only if the order is PARTIALLY_FILLED.
397    OnlyPartiallyFilled,
398}
399
400impl std::fmt::Display for CancelRestrictions {
401    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402        let s = match self {
403            Self::OnlyNew => "ONLY_NEW",
404            Self::OnlyPartiallyFilled => "ONLY_PARTIALLY_FILLED",
405        };
406        write!(f, "{}", s)
407    }
408}
409
410/// Order rate limit exceeded mode for cancel-replace.
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
412#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
413pub enum OrderRateLimitExceededMode {
414    /// Do not attempt cancel when exceeded.
415    DoNothing,
416    /// Cancel only even if exceeded.
417    CancelOnly,
418}
419
420impl std::fmt::Display for OrderRateLimitExceededMode {
421    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
422        let s = match self {
423            Self::DoNothing => "DO_NOTHING",
424            Self::CancelOnly => "CANCEL_ONLY",
425        };
426        write!(f, "{}", s)
427    }
428}
429
430#[cfg(test)]
431mod tests {
432    use super::*;
433
434    #[test]
435    fn test_order_side_serde() {
436        let buy: OrderSide = serde_json::from_str("\"BUY\"").unwrap();
437        assert_eq!(buy, OrderSide::Buy);
438
439        let sell: OrderSide = serde_json::from_str("\"SELL\"").unwrap();
440        assert_eq!(sell, OrderSide::Sell);
441
442        let serialized = serde_json::to_string(&OrderSide::Buy).unwrap();
443        assert_eq!(serialized, "\"BUY\"");
444    }
445
446    #[test]
447    fn test_order_type_serde() {
448        let limit: OrderType = serde_json::from_str("\"LIMIT\"").unwrap();
449        assert_eq!(limit, OrderType::Limit);
450
451        let market: OrderType = serde_json::from_str("\"MARKET\"").unwrap();
452        assert_eq!(market, OrderType::Market);
453
454        let stop_loss: OrderType = serde_json::from_str("\"STOP_LOSS\"").unwrap();
455        assert_eq!(stop_loss, OrderType::StopLoss);
456
457        // Unknown type should deserialize to Other
458        let other: OrderType = serde_json::from_str("\"UNKNOWN_TYPE\"").unwrap();
459        assert_eq!(other, OrderType::Other);
460    }
461
462    #[test]
463    fn test_time_in_force_serde() {
464        let gtc: TimeInForce = serde_json::from_str("\"GTC\"").unwrap();
465        assert_eq!(gtc, TimeInForce::GTC);
466
467        let ioc: TimeInForce = serde_json::from_str("\"IOC\"").unwrap();
468        assert_eq!(ioc, TimeInForce::IOC);
469
470        let fok: TimeInForce = serde_json::from_str("\"FOK\"").unwrap();
471        assert_eq!(fok, TimeInForce::FOK);
472    }
473
474    #[test]
475    fn test_order_status_serde() {
476        let new: OrderStatus = serde_json::from_str("\"NEW\"").unwrap();
477        assert_eq!(new, OrderStatus::New);
478
479        let filled: OrderStatus = serde_json::from_str("\"FILLED\"").unwrap();
480        assert_eq!(filled, OrderStatus::Filled);
481
482        let canceled: OrderStatus = serde_json::from_str("\"CANCELED\"").unwrap();
483        assert_eq!(canceled, OrderStatus::Canceled);
484    }
485
486    #[test]
487    fn test_kline_interval_display() {
488        assert_eq!(KlineInterval::Minutes1.to_string(), "1m");
489        assert_eq!(KlineInterval::Hours1.to_string(), "1h");
490        assert_eq!(KlineInterval::Days1.to_string(), "1d");
491        assert_eq!(KlineInterval::Months1.to_string(), "1M");
492    }
493
494    #[test]
495    fn test_kline_interval_serde() {
496        let interval: KlineInterval = serde_json::from_str("\"1h\"").unwrap();
497        assert_eq!(interval, KlineInterval::Hours1);
498
499        let serialized = serde_json::to_string(&KlineInterval::Minutes15).unwrap();
500        assert_eq!(serialized, "\"15m\"");
501    }
502}