wmjtyd_libstock/data/
orderbook.rs1use std::{
4 collections::HashMap,
5 io::{BufRead, BufReader},
6};
7
8use crypto_msg_parser::{Order, OrderBookMsg};
9use rust_decimal::prelude::ToPrimitive;
10
11use super::{
12 fields::{
13 ExchangeTimestampRepr, ExchangeTypeRepr, InfoTypeRepr, MarketTypeRepr, MessageTypeRepr,
14 ReadExt, ReceivedTimestampRepr, StructureError, SymbolPairRepr,
15 },
16 hex::{HexDataError, NumToBytesExt},
17 order::{get_orders, OrderType},
18 types::InfoType,
19};
20
21pub fn generate_diff(old: &OrderBookMsg, latest: &OrderBookMsg) -> OrderBookMsg {
22 let asks = get_orders(&old.asks, &latest.asks, OrderType::Ask);
23 let bids = get_orders(&old.bids, &latest.bids, OrderType::Bid);
24
25 OrderBookMsg {
26 asks,
27 bids,
28 exchange: latest.exchange.clone(),
29 market_type: latest.market_type,
30 symbol: latest.symbol.clone(),
31 pair: latest.pair.clone(),
32 msg_type: latest.msg_type,
33 timestamp: latest.timestamp,
34 snapshot: latest.snapshot,
35 seq_id: latest.seq_id,
36 prev_seq_id: latest.prev_seq_id,
37 json: latest.json.clone(),
38 }
39}
40
41pub fn encode_orderbook(orderbook: &OrderBookMsg) -> OrderbookResult<Vec<u8>> {
43 let mut bytes = Vec::<u8>::with_capacity(21);
45
46 bytes.extend_from_slice(&ExchangeTimestampRepr(orderbook.timestamp).to_bytes());
48
49 bytes.extend_from_slice(&ReceivedTimestampRepr::try_new_from_now()?.to_bytes());
51
52 bytes.extend_from_slice(&ExchangeTypeRepr::try_from_str(&orderbook.exchange)?.to_bytes());
54
55 bytes.extend_from_slice(&MarketTypeRepr(orderbook.market_type).to_bytes());
57
58 bytes.extend_from_slice(&MessageTypeRepr(orderbook.msg_type).to_bytes());
60
61 bytes.extend_from_slice(&SymbolPairRepr::from_pair(&orderbook.pair).to_bytes());
63
64 {
66 let markets = {
67 let mut markets = HashMap::new();
68
69 markets.insert("asks", &orderbook.asks);
70 markets.insert("bids", &orderbook.bids);
71
72 markets
73 };
74
75 for (k, order_list) in markets {
76 bytes.extend_from_slice(&{ InfoTypeRepr::try_from_str(k)?.to_bytes() });
78
79 bytes.extend_from_slice(&{
81 let list_len = (order_list.len() * 10) as u16;
82 list_len.to_be_bytes()
83 });
84
85 for order in order_list {
87 bytes.extend_from_slice(&u32::encode_bytes(&order.price.to_string())?);
88 bytes.extend_from_slice(&u32::encode_bytes(&order.quantity_base.to_string())?);
89 }
90 }
91 }
92
93 Ok(bytes)
96}
97
98pub fn decode_orderbook(payload: &[u8]) -> OrderbookResult<OrderBookMsg> {
100 let mut reader = BufReader::new(payload);
101
102 let exchange_timestamp = ExchangeTimestampRepr::try_from_reader(&mut reader)?.0;
104
105 reader.consume(8);
107 let exchange_type = ExchangeTypeRepr::try_from_reader(&mut reader)?.0;
111
112 let market_type = MarketTypeRepr::try_from_reader(&mut reader)?.0;
114
115 let msg_type = MessageTypeRepr::try_from_reader(&mut reader)?.0;
117
118 let SymbolPairRepr(symbol, pair) = SymbolPairRepr::try_from_reader(&mut reader)?;
120
121 let (asks, bids) = {
123 let mut asks: Vec<Order> = Vec::new();
124 let mut bids: Vec<Order> = Vec::new();
125
126 while reader.fill_buf().map(|b| !b.is_empty()).unwrap_or(false) {
131 let info_type = InfoTypeRepr::try_from_reader(&mut reader)?.0;
133
134 let info_len = {
136 let data = reader.read_exact_array()?;
137 let info_len_raw = u16::from_be_bytes(data);
138 info_len_raw / 10 };
140
141 for _ in 0..info_len {
143 let price = {
144 let raw_bytes = reader.read_exact_array()?;
145 u32::decode_bytes(&raw_bytes).to_f64().ok_or_else(|| {
146 OrderbookError::DecimalConvertF64Failed(raw_bytes.to_vec())
147 })?
148 };
149
150 let quantity_base = {
151 let raw_bytes = reader.read_exact_array()?;
152 u32::decode_bytes(&raw_bytes).to_f64().ok_or_else(|| {
153 OrderbookError::DecimalConvertF64Failed(raw_bytes.to_vec())
154 })?
155 };
156
157 let order = Order {
158 price,
159 quantity_base,
160 quantity_quote: 0.0,
161 quantity_contract: None,
162 };
163
164 match info_type {
165 InfoType::Asks => asks.push(order),
166 InfoType::Bids => bids.push(order),
167 }
168 }
169 }
170
171 (asks, bids)
172 };
173
174 Ok(OrderBookMsg {
175 exchange: exchange_type.to_string(),
176 market_type,
177 symbol: symbol.to_string(),
178 pair: pair.to_string(),
179 msg_type,
180 timestamp: exchange_timestamp,
181 seq_id: None,
182 prev_seq_id: None,
183 asks,
184 bids,
185 snapshot: true,
186 json: String::new(),
187 })
188}
189
190#[derive(thiserror::Error, Debug)]
191pub enum OrderbookError {
192 #[error("data/hex error: {0}")]
193 HexDataError(#[from] HexDataError),
194
195 #[error("structure error: {0}")]
196 StructureError(#[from] StructureError),
197
198 #[error("failed to convert the following bytes to f64: {0:?}")]
199 DecimalConvertF64Failed(Vec<u8>),
200}
201
202pub type OrderbookResult<T> = Result<T, OrderbookError>;