Skip to main content

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(
68        alias = "p",
69        deserialize_with = "barter_integration::serde::de::de_str"
70    )]
71    pub price: f64,
72    #[serde(
73        alias = "q",
74        deserialize_with = "barter_integration::serde::de::de_str"
75    )]
76    pub quantity: f64,
77    #[serde(
78        alias = "T",
79        deserialize_with = "barter_integration::serde::de::de_u64_epoch_ms_as_datetime_utc"
80    )]
81    pub time: DateTime<Utc>,
82}
83
84impl Identifier<Option<SubscriptionId>> for BinanceLiquidation {
85    fn id(&self) -> Option<SubscriptionId> {
86        Some(self.order.subscription_id.clone())
87    }
88}
89
90impl<InstrumentKey> From<(ExchangeId, InstrumentKey, BinanceLiquidation)>
91    for MarketIter<InstrumentKey, Liquidation>
92{
93    fn from(
94        (exchange_id, instrument, liquidation): (ExchangeId, InstrumentKey, BinanceLiquidation),
95    ) -> Self {
96        Self(vec![Ok(MarketEvent {
97            time_exchange: liquidation.order.time,
98            time_received: Utc::now(),
99            exchange: exchange_id,
100            instrument,
101            kind: Liquidation {
102                side: liquidation.order.side,
103                price: liquidation.order.price,
104                quantity: liquidation.order.quantity,
105                time: liquidation.order.time,
106            },
107        })])
108    }
109}
110
111/// Deserialize a [`BinanceLiquidationOrder`] "s" (eg/ "BTCUSDT") as the associated
112/// [`SubscriptionId`].
113///
114/// eg/ "forceOrder|BTCUSDT"
115pub fn de_liquidation_subscription_id<'de, D>(deserializer: D) -> Result<SubscriptionId, D::Error>
116where
117    D: serde::de::Deserializer<'de>,
118{
119    Deserialize::deserialize(deserializer).map(|market: String| {
120        SubscriptionId::from(format!("{}|{}", BinanceChannel::LIQUIDATIONS.0, market))
121    })
122}
123
124#[cfg(test)]
125mod tests {
126    use super::*;
127
128    mod de {
129        use super::*;
130        use barter_integration::serde::de::datetime_utc_from_epoch_duration;
131        use std::time::Duration;
132
133        #[test]
134        fn test_binance_liquidation() {
135            let input = r#"
136            {
137                "e": "forceOrder",
138                "E": 1665523974222,
139                "o": {
140                    "s": "BTCUSDT",
141                    "S": "SELL",
142                    "o": "LIMIT",
143                    "f": "IOC",
144                    "q": "0.009",
145                    "p": "18917.15",
146                    "ap": "18990.00",
147                    "X": "FILLED",
148                    "l": "0.009",
149                    "z": "0.009",
150                    "T": 1665523974217
151                }
152            }
153            "#;
154
155            assert_eq!(
156                serde_json::from_str::<BinanceLiquidation>(input).unwrap(),
157                BinanceLiquidation {
158                    order: BinanceLiquidationOrder {
159                        subscription_id: SubscriptionId::from("@forceOrder|BTCUSDT"),
160                        side: Side::Sell,
161                        price: 18917.15,
162                        quantity: 0.009,
163                        time: datetime_utc_from_epoch_duration(Duration::from_millis(
164                            1665523974217,
165                        )),
166                    },
167                }
168            );
169        }
170    }
171}