Skip to main content

wmjtyd_libstock/data/
bbo.rs

1//! The bbo-related operations.
2
3use std::io::{BufRead, BufReader};
4
5use crypto_msg_parser::BboMsg;
6use rust_decimal::prelude::ToPrimitive;
7
8use super::{
9    fields::{
10        ExchangeTimestampRepr, ExchangeTypeRepr, MarketTypeRepr, MessageTypeRepr, ReadExt,
11        ReceivedTimestampRepr, StructureError, SymbolPairRepr,
12    },
13    hex::{HexDataError, NumToBytesExt},
14};
15
16/// Encode a [`BboMsg`] to bytes.
17pub fn encode_bbo(bbo: &BboMsg) -> BboResult<Vec<u8>> {
18    // This data should have 41 bytes.
19    let mut bytes = Vec::<u8>::with_capacity(41);
20
21    // 1. 交易所时间戳: 6 字节
22    bytes.extend_from_slice(&ExchangeTimestampRepr(bbo.timestamp).to_bytes());
23
24    // 2. 收到时间戳: 6 字节
25    bytes.extend_from_slice(&ReceivedTimestampRepr::try_new_from_now()?.to_bytes());
26
27    // 3. EXCHANGE: 1 字节
28    bytes.extend_from_slice(&ExchangeTypeRepr::try_from_str(&bbo.exchange)?.to_bytes());
29
30    // 4. MARKET_TYPE: 1 字节信息标识
31    bytes.extend_from_slice(&MarketTypeRepr(bbo.market_type).to_bytes());
32
33    // 5. MESSAGE_TYPE: 1 字节信息标识
34    bytes.extend_from_slice(&MessageTypeRepr(bbo.msg_type).to_bytes());
35
36    // 6. SYMBOL: 2 字节信息标识
37    bytes.extend_from_slice(&SymbolPairRepr::from_pair(&bbo.pair).to_bytes());
38
39    // 7. asks price(5)、quant(5)
40    bytes.extend_from_slice(&u32::encode_bytes(&bbo.ask_price.to_string())?);
41    bytes.extend_from_slice(&u32::encode_bytes(&bbo.ask_quantity_base.to_string())?);
42
43    // 8. bids price(5)、quant(5)
44    bytes.extend_from_slice(&u32::encode_bytes(&bbo.bid_price.to_string())?);
45    bytes.extend_from_slice(&u32::encode_bytes(&bbo.bid_quantity_base.to_string())?);
46
47    Ok(bytes)
48}
49
50/// Decode the specified bytes to a [`BboMsg`].
51pub fn decode_bbo(payload: &[u8]) -> BboResult<BboMsg> {
52    let mut reader = BufReader::new(payload);
53
54    // 1. 交易所时间戳: 6 字节时间戳
55    let exchange_timestamp = ExchangeTimestampRepr::try_from_reader(&mut reader)?.0;
56
57    // 2. 收到时间戳: 6 字节时间戳 (NOT USED)
58    reader.consume(8);
59
60    // 3. EXCHANGE: 1 字节信息标识
61    let exchange_type = ExchangeTypeRepr::try_from_reader(&mut reader)?.0;
62
63    // 4. MARKET_TYPE: 1 字节信息标识
64    let market_type = MarketTypeRepr::try_from_reader(&mut reader)?.0;
65
66    // 5. MESSAGE_TYPE: 1 字节信息标识
67    let msg_type = MessageTypeRepr::try_from_reader(&mut reader)?.0;
68
69    // 6. SYMBOL_PAIR: 2 字节信息标识
70    let SymbolPairRepr(symbol, pair) = SymbolPairRepr::try_from_reader(&mut reader)?;
71
72    // 7. asks price(5)、quant(5)
73    let ask_price = {
74        let raw_bytes = reader.read_exact_array()?;
75        u32::decode_bytes(&raw_bytes)
76            .to_f64()
77            .ok_or_else(|| BboError::DecimalConvertF64Failed(raw_bytes.to_vec()))?
78    };
79
80    let ask_quantity_base = {
81        let raw_bytes = reader.read_exact_array()?;
82        u32::decode_bytes(&raw_bytes)
83            .to_f64()
84            .ok_or_else(|| BboError::DecimalConvertF64Failed(raw_bytes.to_vec()))?
85    };
86
87    // 8. bids price(5)、quant(5)
88    let bid_price = {
89        let raw_bytes = reader.read_exact_array()?;
90        u32::decode_bytes(&raw_bytes)
91            .to_f64()
92            .ok_or_else(|| BboError::DecimalConvertF64Failed(raw_bytes.to_vec()))?
93    };
94
95    let bid_quantity_base = {
96        let raw_bytes = reader.read_exact_array()?;
97        u32::decode_bytes(&raw_bytes)
98            .to_f64()
99            .ok_or_else(|| BboError::DecimalConvertF64Failed(raw_bytes.to_vec()))?
100    };
101
102    Ok(BboMsg {
103        exchange: exchange_type.to_string(),
104        market_type,
105        msg_type,
106        pair: pair.to_string(),
107        symbol: symbol.to_string(),
108        timestamp: exchange_timestamp,
109        ask_price,
110        ask_quantity_base,
111        ask_quantity_quote: 0.0,
112        ask_quantity_contract: None,
113        bid_price,
114        bid_quantity_base,
115        bid_quantity_quote: 0.0,
116        bid_quantity_contract: None,
117        id: None,
118        json: String::new(),
119    })
120}
121
122#[derive(thiserror::Error, Debug)]
123pub enum BboError {
124    #[error("data/hex error: {0}")]
125    HexDataError(#[from] HexDataError),
126
127    #[error("structure error: {0}")]
128    StructureError(#[from] StructureError),
129
130    #[error("failed to convert the following bytes to f64: {0:?}")]
131    DecimalConvertF64Failed(Vec<u8>),
132}
133
134pub type BboResult<T> = Result<T, BboError>;