nautilus_binance/futures/websocket/
parse.rs1use nautilus_core::nanos::UnixNanos;
19use nautilus_model::{
20 data::{BookOrder, OrderBookDelta, OrderBookDeltas, QuoteTick, TradeTick},
21 enums::{AggressorSide, BookAction, OrderSide, RecordFlag},
22 identifiers::TradeId,
23 instruments::{Instrument, InstrumentAny},
24 types::{Price, Quantity},
25};
26use ustr::Ustr;
27
28use super::messages::{
29 BinanceFuturesAggTradeMsg, BinanceFuturesBookTickerMsg, BinanceFuturesDepthUpdateMsg,
30 BinanceFuturesTradeMsg,
31};
32use crate::{common::enums::BinanceWsEventType, websocket::error::BinanceWsResult};
33
34pub fn parse_agg_trade(
40 msg: &BinanceFuturesAggTradeMsg,
41 instrument: &InstrumentAny,
42) -> BinanceWsResult<TradeTick> {
43 let instrument_id = instrument.id();
44 let price_precision = instrument.price_precision();
45 let size_precision = instrument.size_precision();
46
47 let price = msg
48 .price
49 .parse::<f64>()
50 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
51 let size = msg
52 .quantity
53 .parse::<f64>()
54 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
55
56 let aggressor_side = if msg.is_buyer_maker {
57 AggressorSide::Seller
58 } else {
59 AggressorSide::Buyer
60 };
61
62 let ts_event = UnixNanos::from(msg.trade_time as u64 * 1_000_000); let trade_id = TradeId::new(msg.agg_trade_id.to_string());
64
65 Ok(TradeTick::new(
66 instrument_id,
67 Price::new(price, price_precision),
68 Quantity::new(size, size_precision),
69 aggressor_side,
70 trade_id,
71 ts_event,
72 ts_event,
73 ))
74}
75
76pub fn parse_trade(
82 msg: &BinanceFuturesTradeMsg,
83 instrument: &InstrumentAny,
84) -> BinanceWsResult<TradeTick> {
85 let instrument_id = instrument.id();
86 let price_precision = instrument.price_precision();
87 let size_precision = instrument.size_precision();
88
89 let price = msg
90 .price
91 .parse::<f64>()
92 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
93 let size = msg
94 .quantity
95 .parse::<f64>()
96 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
97
98 let aggressor_side = if msg.is_buyer_maker {
99 AggressorSide::Seller
100 } else {
101 AggressorSide::Buyer
102 };
103
104 let ts_event = UnixNanos::from(msg.trade_time as u64 * 1_000_000); let trade_id = TradeId::new(msg.trade_id.to_string());
106
107 Ok(TradeTick::new(
108 instrument_id,
109 Price::new(price, price_precision),
110 Quantity::new(size, size_precision),
111 aggressor_side,
112 trade_id,
113 ts_event,
114 ts_event,
115 ))
116}
117
118pub fn parse_book_ticker(
124 msg: &BinanceFuturesBookTickerMsg,
125 instrument: &InstrumentAny,
126) -> BinanceWsResult<QuoteTick> {
127 let instrument_id = instrument.id();
128 let price_precision = instrument.price_precision();
129 let size_precision = instrument.size_precision();
130
131 let bid_price = msg
132 .best_bid_price
133 .parse::<f64>()
134 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
135 let bid_size = msg
136 .best_bid_qty
137 .parse::<f64>()
138 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
139 let ask_price = msg
140 .best_ask_price
141 .parse::<f64>()
142 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
143 let ask_size = msg
144 .best_ask_qty
145 .parse::<f64>()
146 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
147
148 let ts_event = UnixNanos::from(msg.transaction_time as u64 * 1_000_000); Ok(QuoteTick::new(
151 instrument_id,
152 Price::new(bid_price, price_precision),
153 Price::new(ask_price, price_precision),
154 Quantity::new(bid_size, size_precision),
155 Quantity::new(ask_size, size_precision),
156 ts_event,
157 ts_event,
158 ))
159}
160
161pub fn parse_depth_update(
167 msg: &BinanceFuturesDepthUpdateMsg,
168 instrument: &InstrumentAny,
169) -> BinanceWsResult<OrderBookDeltas> {
170 let instrument_id = instrument.id();
171 let price_precision = instrument.price_precision();
172 let size_precision = instrument.size_precision();
173
174 let ts_event = UnixNanos::from(msg.transaction_time as u64 * 1_000_000); let mut deltas = Vec::with_capacity(msg.bids.len() + msg.asks.len());
177
178 for (i, bid) in msg.bids.iter().enumerate() {
180 let price = bid[0]
181 .parse::<f64>()
182 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
183 let size = bid[1]
184 .parse::<f64>()
185 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
186
187 let action = if size == 0.0 {
188 BookAction::Delete
189 } else {
190 BookAction::Update
191 };
192
193 let is_last = i == msg.bids.len() - 1 && msg.asks.is_empty();
194 let flags = if is_last { RecordFlag::F_LAST as u8 } else { 0 };
195
196 let order = BookOrder::new(
197 OrderSide::Buy,
198 Price::new(price, price_precision),
199 Quantity::new(size, size_precision),
200 0,
201 );
202
203 deltas.push(OrderBookDelta::new(
204 instrument_id,
205 action,
206 order,
207 flags,
208 msg.final_update_id,
209 ts_event,
210 ts_event,
211 ));
212 }
213
214 for (i, ask) in msg.asks.iter().enumerate() {
216 let price = ask[0]
217 .parse::<f64>()
218 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
219 let size = ask[1]
220 .parse::<f64>()
221 .map_err(|e| crate::websocket::error::BinanceWsError::ParseError(e.to_string()))?;
222
223 let action = if size == 0.0 {
224 BookAction::Delete
225 } else {
226 BookAction::Update
227 };
228
229 let is_last = i == msg.asks.len() - 1;
230 let flags = if is_last { RecordFlag::F_LAST as u8 } else { 0 };
231
232 let order = BookOrder::new(
233 OrderSide::Sell,
234 Price::new(price, price_precision),
235 Quantity::new(size, size_precision),
236 0,
237 );
238
239 deltas.push(OrderBookDelta::new(
240 instrument_id,
241 action,
242 order,
243 flags,
244 msg.final_update_id,
245 ts_event,
246 ts_event,
247 ));
248 }
249
250 Ok(OrderBookDeltas::new(instrument_id, deltas))
251}
252
253pub fn extract_symbol(json: &serde_json::Value) -> Option<Ustr> {
255 json.get("s").and_then(|v| v.as_str()).map(Ustr::from)
256}
257
258pub fn extract_event_type(json: &serde_json::Value) -> Option<BinanceWsEventType> {
260 json.get("e")
261 .and_then(|v| serde_json::from_value(v.clone()).ok())
262}