rustrade_data/exchange/binance/futures/
liquidation.rs1use super::super::BinanceChannel;
2use crate::{
3 Identifier,
4 event::{MarketEvent, MarketIter},
5 subscription::liquidation::Liquidation,
6};
7use chrono::{DateTime, Utc};
8use rust_decimal::Decimal;
9use rustrade_instrument::{Side, exchange::ExchangeId};
10use rustrade_integration::subscription::SubscriptionId;
11use serde::{Deserialize, Serialize};
12
13#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
37pub struct BinanceLiquidation {
38 #[serde(alias = "o")]
39 pub order: BinanceLiquidationOrder,
40}
41
42#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
63pub struct BinanceLiquidationOrder {
64 #[serde(alias = "s", deserialize_with = "de_liquidation_subscription_id")]
65 pub subscription_id: SubscriptionId,
66 #[serde(alias = "S")]
67 pub side: Side,
68 #[serde(
69 alias = "p",
70 deserialize_with = "rustrade_integration::serde::de::de_str"
71 )]
72 pub price: Decimal,
73 #[serde(
74 alias = "q",
75 deserialize_with = "rustrade_integration::serde::de::de_str"
76 )]
77 pub quantity: Decimal,
78 #[serde(
79 alias = "T",
80 deserialize_with = "rustrade_integration::serde::de::de_u64_epoch_ms_as_datetime_utc"
81 )]
82 pub time: DateTime<Utc>,
83}
84
85impl Identifier<Option<SubscriptionId>> for BinanceLiquidation {
86 fn id(&self) -> Option<SubscriptionId> {
87 Some(self.order.subscription_id.clone())
88 }
89}
90
91impl<InstrumentKey> From<(ExchangeId, InstrumentKey, BinanceLiquidation)>
92 for MarketIter<InstrumentKey, Liquidation>
93{
94 fn from(
95 (exchange_id, instrument, liquidation): (ExchangeId, InstrumentKey, BinanceLiquidation),
96 ) -> Self {
97 Self(vec![Ok(MarketEvent {
98 time_exchange: liquidation.order.time,
99 time_received: Utc::now(),
100 exchange: exchange_id,
101 instrument,
102 kind: Liquidation {
103 side: liquidation.order.side,
104 price: liquidation.order.price,
105 quantity: liquidation.order.quantity,
106 time: liquidation.order.time,
107 },
108 })])
109 }
110}
111
112pub fn de_liquidation_subscription_id<'de, D>(deserializer: D) -> Result<SubscriptionId, D::Error>
117where
118 D: serde::de::Deserializer<'de>,
119{
120 Deserialize::deserialize(deserializer).map(|market: String| {
121 SubscriptionId::from(format!("{}|{}", BinanceChannel::LIQUIDATIONS.0, market))
122 })
123}
124
125#[cfg(test)]
126#[allow(clippy::unwrap_used)] mod tests {
128 use super::*;
129
130 mod de {
131 use super::*;
132 use rust_decimal_macros::dec;
133 use rustrade_integration::serde::de::datetime_utc_from_epoch_duration;
134 use std::time::Duration;
135
136 #[test]
137 fn test_binance_liquidation() {
138 let input = r#"
139 {
140 "e": "forceOrder",
141 "E": 1665523974222,
142 "o": {
143 "s": "BTCUSDT",
144 "S": "SELL",
145 "o": "LIMIT",
146 "f": "IOC",
147 "q": "0.009",
148 "p": "18917.15",
149 "ap": "18990.00",
150 "X": "FILLED",
151 "l": "0.009",
152 "z": "0.009",
153 "T": 1665523974217
154 }
155 }
156 "#;
157
158 assert_eq!(
159 serde_json::from_str::<BinanceLiquidation>(input).unwrap(),
160 BinanceLiquidation {
161 order: BinanceLiquidationOrder {
162 subscription_id: SubscriptionId::from("@forceOrder|BTCUSDT"),
163 side: Side::Sell,
164 price: dec!(18917.15),
165 quantity: dec!(0.009),
166 time: datetime_utc_from_epoch_duration(Duration::from_millis(
167 1665523974217,
168 )),
169 },
170 }
171 );
172 }
173 }
174}