barter_data/exchange/binance/futures/
liquidation.rs

1use super::super::BinanceChannel;
2use crate::{
3    Identifier,
4    event::{MarketEvent, MarketIter},
5    subscription::liquidation::Liquidation,
6};
7use barter_instrument::{Side, exchange::ExchangeId};
8use barter_integration::subscription::SubscriptionId;
9use chrono::{DateTime, Utc};
10use serde::{Deserialize, Serialize};
11
12/// [`BinanceFuturesUsd`](super::BinanceFuturesUsd) Liquidation order message.
13///
14/// ### Raw Payload Examples
15/// See docs: <https://binance-docs.github.io/apidocs/futures/en/#liquidation-order-streams>
16/// ```json
17/// {
18///     "e": "forceOrder",
19///     "E": 1665523974222,
20///     "o": {
21///         "s": "BTCUSDT",
22///         "S": "SELL",
23///         "o": "LIMIT",
24///         "f": "IOC",
25///         "q": "0.009",
26///         "p": "18917.15",
27///         "ap": "18990.00",
28///         "X": "FILLED",
29///         "l": "0.009",
30///         "z": "0.009",
31///         "T": 1665523974217
32///     }
33/// }
34/// ```
35#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
36pub struct BinanceLiquidation {
37    #[serde(alias = "o")]
38    pub order: BinanceLiquidationOrder,
39}
40
41/// [`BinanceFuturesUsd`](super::BinanceFuturesUsd) Liquidation order.
42///
43/// ### Raw Payload Examples
44/// ```json
45/// {
46///     "s": "BTCUSDT",
47///     "S": "SELL",
48///     "o": "LIMIT",
49///     "f": "IOC",
50///     "q": "0.009",
51///     "p": "18917.15",
52///     "ap": "18990.00",
53///     "X": "FILLED",
54///     "l": "0.009",
55///     "z": "0.009",
56///     "T": 1665523974217
57/// }
58/// ```
59///
60/// See docs: <https://binance-docs.github.io/apidocs/futures/en/#liquidation-order-streams>
61#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
62pub struct BinanceLiquidationOrder {
63    #[serde(alias = "s", deserialize_with = "de_liquidation_subscription_id")]
64    pub subscription_id: SubscriptionId,
65    #[serde(alias = "S")]
66    pub side: Side,
67    #[serde(alias = "p", deserialize_with = "barter_integration::de::de_str")]
68    pub price: f64,
69    #[serde(alias = "q", deserialize_with = "barter_integration::de::de_str")]
70    pub quantity: f64,
71    #[serde(
72        alias = "T",
73        deserialize_with = "barter_integration::de::de_u64_epoch_ms_as_datetime_utc"
74    )]
75    pub time: DateTime<Utc>,
76}
77
78impl Identifier<Option<SubscriptionId>> for BinanceLiquidation {
79    fn id(&self) -> Option<SubscriptionId> {
80        Some(self.order.subscription_id.clone())
81    }
82}
83
84impl<InstrumentKey> From<(ExchangeId, InstrumentKey, BinanceLiquidation)>
85    for MarketIter<InstrumentKey, Liquidation>
86{
87    fn from(
88        (exchange_id, instrument, liquidation): (ExchangeId, InstrumentKey, BinanceLiquidation),
89    ) -> Self {
90        Self(vec![Ok(MarketEvent {
91            time_exchange: liquidation.order.time,
92            time_received: Utc::now(),
93            exchange: exchange_id,
94            instrument,
95            kind: Liquidation {
96                side: liquidation.order.side,
97                price: liquidation.order.price,
98                quantity: liquidation.order.quantity,
99                time: liquidation.order.time,
100            },
101        })])
102    }
103}
104
105/// Deserialize a [`BinanceLiquidationOrder`] "s" (eg/ "BTCUSDT") as the associated
106/// [`SubscriptionId`].
107///
108/// eg/ "forceOrder|BTCUSDT"
109pub fn de_liquidation_subscription_id<'de, D>(deserializer: D) -> Result<SubscriptionId, D::Error>
110where
111    D: serde::de::Deserializer<'de>,
112{
113    Deserialize::deserialize(deserializer).map(|market: String| {
114        SubscriptionId::from(format!("{}|{}", BinanceChannel::LIQUIDATIONS.0, market))
115    })
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    mod de {
123        use super::*;
124        use barter_integration::de::datetime_utc_from_epoch_duration;
125        use std::time::Duration;
126
127        #[test]
128        fn test_binance_liquidation() {
129            let input = r#"
130            {
131                "e": "forceOrder",
132                "E": 1665523974222,
133                "o": {
134                    "s": "BTCUSDT",
135                    "S": "SELL",
136                    "o": "LIMIT",
137                    "f": "IOC",
138                    "q": "0.009",
139                    "p": "18917.15",
140                    "ap": "18990.00",
141                    "X": "FILLED",
142                    "l": "0.009",
143                    "z": "0.009",
144                    "T": 1665523974217
145                }
146            }
147            "#;
148
149            assert_eq!(
150                serde_json::from_str::<BinanceLiquidation>(input).unwrap(),
151                BinanceLiquidation {
152                    order: BinanceLiquidationOrder {
153                        subscription_id: SubscriptionId::from("@forceOrder|BTCUSDT"),
154                        side: Side::Sell,
155                        price: 18917.15,
156                        quantity: 0.009,
157                        time: datetime_utc_from_epoch_duration(Duration::from_millis(
158                            1665523974217,
159                        )),
160                    },
161                }
162            );
163        }
164    }
165}