barter_data/exchange/binance/book/
l2.rs1use super::{super::channel::BinanceChannel, BinanceLevel};
2use crate::{
3 Identifier, books::OrderBook, event::MarketEvent, exchange::subscription::ExchangeSub,
4 subscription::book::OrderBookEvent,
5};
6use barter_instrument::exchange::ExchangeId;
7use barter_integration::subscription::SubscriptionId;
8use chrono::{DateTime, Utc};
9use derive_more::Constructor;
10use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Constructor)]
13pub struct BinanceOrderBookL2Meta<InstrumentKey, Sequencer> {
14 pub key: InstrumentKey,
15 pub sequencer: Sequencer,
16}
17
18#[derive(Clone, PartialEq, PartialOrd, Debug, Deserialize, Serialize)]
54pub struct BinanceOrderBookL2Snapshot {
55 #[serde(rename = "lastUpdateId")]
56 pub last_update_id: u64,
57 #[serde(default, rename = "E", with = "chrono::serde::ts_milliseconds_option")]
58 pub time_exchange: Option<DateTime<Utc>>,
59 #[serde(default, rename = "T", with = "chrono::serde::ts_milliseconds_option")]
60 pub time_engine: Option<DateTime<Utc>>,
61 pub bids: Vec<BinanceLevel>,
62 pub asks: Vec<BinanceLevel>,
63}
64
65impl<InstrumentKey> From<(ExchangeId, InstrumentKey, BinanceOrderBookL2Snapshot)>
66 for MarketEvent<InstrumentKey, OrderBookEvent>
67{
68 fn from(
69 (exchange, instrument, snapshot): (ExchangeId, InstrumentKey, BinanceOrderBookL2Snapshot),
70 ) -> Self {
71 let time_received = Utc::now();
72 Self {
73 time_exchange: snapshot.time_exchange.unwrap_or(time_received),
74 time_received,
75 exchange,
76 instrument,
77 kind: OrderBookEvent::from(snapshot),
78 }
79 }
80}
81
82impl From<BinanceOrderBookL2Snapshot> for OrderBookEvent {
83 fn from(snapshot: BinanceOrderBookL2Snapshot) -> Self {
84 Self::Snapshot(OrderBook::new(
85 snapshot.last_update_id,
86 snapshot.time_engine,
87 snapshot.bids,
88 snapshot.asks,
89 ))
90 }
91}
92
93pub fn de_ob_l2_subscription_id<'de, D>(deserializer: D) -> Result<SubscriptionId, D::Error>
100where
101 D: serde::de::Deserializer<'de>,
102{
103 <&str as Deserialize>::deserialize(deserializer)
104 .map(|market| ExchangeSub::from((BinanceChannel::ORDER_BOOK_L2, market)).id())
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 mod de {
112 use super::*;
113 use rust_decimal_macros::dec;
114
115 #[test]
116 fn test_binance_order_book_l2_snapshot() {
117 struct TestCase {
118 input: &'static str,
119 expected: BinanceOrderBookL2Snapshot,
120 }
121
122 let tests = vec![
123 TestCase {
124 input: r#"
126 {
127 "lastUpdateId": 1027024,
128 "bids": [
129 [
130 "4.00000000",
131 "431.00000000"
132 ]
133 ],
134 "asks": [
135 [
136 "4.00000200",
137 "12.00000000"
138 ]
139 ]
140 }
141 "#,
142 expected: BinanceOrderBookL2Snapshot {
143 last_update_id: 1027024,
144 time_exchange: Default::default(),
145 time_engine: Default::default(),
146 bids: vec![BinanceLevel {
147 price: dec!(4.00000000),
148 amount: dec!(431.00000000),
149 }],
150 asks: vec![BinanceLevel {
151 price: dec!(4.00000200),
152 amount: dec!(12.00000000),
153 }],
154 },
155 },
156 TestCase {
157 input: r#"
159 {
160 "lastUpdateId": 1027024,
161 "E": 1589436922972,
162 "T": 1589436922959,
163 "bids": [
164 [
165 "4.00000000",
166 "431.00000000"
167 ]
168 ],
169 "asks": [
170 [
171 "4.00000200",
172 "12.00000000"
173 ]
174 ]
175 }
176 "#,
177 expected: BinanceOrderBookL2Snapshot {
178 last_update_id: 1027024,
179 time_exchange: Some(
180 DateTime::from_timestamp_millis(1589436922972).unwrap(),
181 ),
182 time_engine: Some(DateTime::from_timestamp_millis(1589436922959).unwrap()),
183 bids: vec![BinanceLevel {
184 price: dec!(4.0),
185 amount: dec!(431.0),
186 }],
187 asks: vec![BinanceLevel {
188 price: dec!(4.00000200),
189 amount: dec!(12.0),
190 }],
191 },
192 },
193 ];
194
195 for (index, test) in tests.into_iter().enumerate() {
196 assert_eq!(
197 serde_json::from_str::<BinanceOrderBookL2Snapshot>(test.input).unwrap(),
198 test.expected,
199 "TC{} failed",
200 index
201 );
202 }
203 }
204 }
205}