Skip to main content

nautilus_serialization/sbe/market/
book.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_model::{
17    data::{BookOrder, OrderBookDelta, OrderBookDeltas, OrderBookDepth},
18    enums::OrderSide,
19};
20
21use super::{
22    super::{SbeCursor, SbeDecodeError, SbeEncodeError, SbeWriter},
23    FromSbeReuse, MarketSbeMessage,
24    common::{
25        BOOK_ORDER_BLOCK_LENGTH, DEPTH10_COUNTS_BLOCK_LENGTH, DEPTH10_LEVEL_BLOCK_LENGTH,
26        DEPTH10_LEVEL_COUNT, GROUP_HEADER_16_LENGTH, ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH,
27        decode_book_action, decode_header, decode_instrument_id, decode_order_side, decode_price,
28        decode_quantity, decode_unix_nanos, encode_group_header_16, encode_instrument_id,
29        encode_price, encode_quantity, encode_unix_nanos, encoded_instrument_id_size,
30        validate_header,
31    },
32    template_id,
33};
34
35impl MarketSbeMessage for BookOrder {
36    const TEMPLATE_ID: u16 = template_id::BOOK_ORDER;
37    const BLOCK_LENGTH: u16 = BOOK_ORDER_BLOCK_LENGTH;
38
39    fn encode_body(&self, writer: &mut SbeWriter<'_>) -> Result<(), SbeEncodeError> {
40        encode_book_order(writer, self);
41        Ok(())
42    }
43
44    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
45        decode_book_order(cursor)
46    }
47}
48
49impl MarketSbeMessage for OrderBookDelta {
50    const TEMPLATE_ID: u16 = template_id::ORDER_BOOK_DELTA;
51    const BLOCK_LENGTH: u16 = ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH;
52
53    fn encode_body(&self, writer: &mut SbeWriter<'_>) -> Result<(), SbeEncodeError> {
54        encode_order_book_delta_fields(writer, self);
55        encode_instrument_id(writer, &self.instrument_id)
56    }
57
58    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
59        let action = decode_book_action(cursor)?;
60        let order = decode_book_order(cursor)?;
61        let flags = cursor.read_u8()?;
62        let sequence = cursor.read_u64_le()?;
63        let ts_event = decode_unix_nanos(cursor)?;
64        let ts_init = decode_unix_nanos(cursor)?;
65        let instrument_id = decode_instrument_id(cursor)?;
66
67        Ok(Self {
68            instrument_id,
69            action,
70            order,
71            flags,
72            sequence,
73            ts_event,
74            ts_init,
75        })
76    }
77
78    fn encoded_body_size(&self) -> usize {
79        usize::from(Self::BLOCK_LENGTH) + encoded_instrument_id_size(&self.instrument_id)
80    }
81}
82
83impl MarketSbeMessage for OrderBookDeltas {
84    const TEMPLATE_ID: u16 = template_id::ORDER_BOOK_DELTAS;
85    const BLOCK_LENGTH: u16 = 25;
86
87    fn encode_body(&self, writer: &mut SbeWriter<'_>) -> Result<(), SbeEncodeError> {
88        writer.write_u8(self.flags);
89        writer.write_u64_le(self.sequence);
90        encode_unix_nanos(writer, self.ts_event);
91        encode_unix_nanos(writer, self.ts_init);
92        encode_instrument_id(writer, &self.instrument_id)?;
93        encode_group_header_16(
94            writer,
95            "OrderBookDeltas.deltas",
96            self.deltas.len(),
97            ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH,
98        )?;
99
100        for delta in &self.deltas {
101            <OrderBookDelta as MarketSbeMessage>::encode_body(delta, writer)?;
102        }
103        Ok(())
104    }
105
106    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
107        let mut scratch = Vec::new();
108        decode_order_book_deltas_body(cursor, &mut scratch)
109    }
110
111    fn encoded_body_size(&self) -> usize {
112        usize::from(Self::BLOCK_LENGTH)
113            + encoded_instrument_id_size(&self.instrument_id)
114            + GROUP_HEADER_16_LENGTH
115            + self
116                .deltas
117                .iter()
118                .map(MarketSbeMessage::encoded_body_size)
119                .sum::<usize>()
120    }
121}
122
123impl FromSbeReuse for OrderBookDeltas {
124    type Scratch = Vec<OrderBookDelta>;
125
126    fn from_sbe_reuse(
127        bytes: &[u8],
128        scratch: &mut Vec<OrderBookDelta>,
129    ) -> Result<Self, SbeDecodeError> {
130        let mut cursor = SbeCursor::new(bytes);
131        let header = decode_header(&mut cursor)?;
132        validate_header(
133            header,
134            <Self as MarketSbeMessage>::TEMPLATE_ID,
135            <Self as MarketSbeMessage>::BLOCK_LENGTH,
136        )?;
137        decode_order_book_deltas_body(&mut cursor, scratch)
138    }
139}
140
141fn decode_order_book_deltas_body(
142    cursor: &mut SbeCursor<'_>,
143    scratch: &mut Vec<OrderBookDelta>,
144) -> Result<OrderBookDeltas, SbeDecodeError> {
145    let flags = cursor.read_u8()?;
146    let sequence = cursor.read_u64_le()?;
147    let ts_event = decode_unix_nanos(cursor)?;
148    let ts_init = decode_unix_nanos(cursor)?;
149    let instrument_id = decode_instrument_id(cursor)?;
150    let (block_length, count) = cursor.read_group_header_16()?;
151
152    if block_length != ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH {
153        return Err(SbeDecodeError::InvalidBlockLength {
154            expected: ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH,
155            actual: block_length,
156        });
157    }
158
159    let count = usize::from(count);
160    scratch.clear();
161    scratch.reserve(count);
162
163    for _ in 0..count {
164        scratch.push(<OrderBookDelta as MarketSbeMessage>::decode_body(cursor)?);
165    }
166
167    Ok(OrderBookDeltas {
168        instrument_id,
169        deltas: std::mem::take(scratch),
170        flags,
171        sequence,
172        ts_event,
173        ts_init,
174    })
175}
176
177impl MarketSbeMessage for OrderBookDepth {
178    const TEMPLATE_ID: u16 = template_id::ORDER_BOOK_DEPTH;
179    const BLOCK_LENGTH: u16 =
180        (DEPTH10_LEVEL_BLOCK_LENGTH * 20) + (DEPTH10_COUNTS_BLOCK_LENGTH as u16 * 2) + 25;
181
182    fn encode_body(&self, writer: &mut SbeWriter<'_>) -> Result<(), SbeEncodeError> {
183        for (group, count) in [
184            ("bids", self.bids.len()),
185            ("asks", self.asks.len()),
186            ("bid_counts", self.bid_counts.len()),
187            ("ask_counts", self.ask_counts.len()),
188        ] {
189            if count != DEPTH10_LEVEL_COUNT {
190                return Err(SbeEncodeError::InvalidGroupSize {
191                    group,
192                    count,
193                    expected: DEPTH10_LEVEL_COUNT,
194                });
195            }
196        }
197
198        for bid in &self.bids {
199            encode_price(writer, &bid.price);
200            encode_quantity(writer, &bid.size);
201        }
202
203        for ask in &self.asks {
204            encode_price(writer, &ask.price);
205            encode_quantity(writer, &ask.size);
206        }
207
208        for count in &self.bid_counts {
209            writer.write_u32_le(*count);
210        }
211
212        for count in &self.ask_counts {
213            writer.write_u32_le(*count);
214        }
215        writer.write_u8(self.flags);
216        writer.write_u64_le(self.sequence);
217        encode_unix_nanos(writer, self.ts_event);
218        encode_unix_nanos(writer, self.ts_init);
219        encode_instrument_id(writer, &self.instrument_id)
220    }
221
222    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
223        let mut bids = [BookOrder::default(); DEPTH10_LEVEL_COUNT];
224        let mut asks = [BookOrder::default(); DEPTH10_LEVEL_COUNT];
225
226        for bid in &mut bids {
227            *bid = BookOrder::new(
228                OrderSide::Buy,
229                decode_price(cursor)?,
230                decode_quantity(cursor)?,
231                0,
232            );
233        }
234
235        for ask in &mut asks {
236            *ask = BookOrder::new(
237                OrderSide::Sell,
238                decode_price(cursor)?,
239                decode_quantity(cursor)?,
240                0,
241            );
242        }
243
244        let mut bid_counts = [0u32; DEPTH10_LEVEL_COUNT];
245        let mut ask_counts = [0u32; DEPTH10_LEVEL_COUNT];
246
247        for count in &mut bid_counts {
248            *count = cursor.read_u32_le()?;
249        }
250
251        for count in &mut ask_counts {
252            *count = cursor.read_u32_le()?;
253        }
254
255        let flags = cursor.read_u8()?;
256        let sequence = cursor.read_u64_le()?;
257        let ts_event = decode_unix_nanos(cursor)?;
258        let ts_init = decode_unix_nanos(cursor)?;
259        let instrument_id = decode_instrument_id(cursor)?;
260
261        Ok(Self {
262            instrument_id,
263            bids: bids.into(),
264            asks: asks.into(),
265            bid_counts: bid_counts.into(),
266            ask_counts: ask_counts.into(),
267            flags,
268            sequence,
269            ts_event,
270            ts_init,
271        })
272    }
273
274    fn encoded_body_size(&self) -> usize {
275        usize::from(Self::BLOCK_LENGTH) + encoded_instrument_id_size(&self.instrument_id)
276    }
277}
278
279fn encode_book_order(writer: &mut SbeWriter<'_>, order: &BookOrder) {
280    encode_price(writer, &order.price);
281    encode_quantity(writer, &order.size);
282    writer.write_u8(order.side.map_or(0, |side| side as u8));
283    writer.write_u64_le(order.order_id);
284}
285
286fn decode_book_order(cursor: &mut SbeCursor<'_>) -> Result<BookOrder, SbeDecodeError> {
287    let price = decode_price(cursor)?;
288    let size = decode_quantity(cursor)?;
289    let side = decode_order_side(cursor)?;
290    let order_id = cursor.read_u64_le()?;
291    Ok(BookOrder {
292        side,
293        price,
294        size,
295        order_id,
296    })
297}
298
299fn encode_order_book_delta_fields(writer: &mut SbeWriter<'_>, delta: &OrderBookDelta) {
300    writer.write_u8(delta.action as u8);
301    encode_book_order(writer, &delta.order);
302    writer.write_u8(delta.flags);
303    writer.write_u64_le(delta.sequence);
304    encode_unix_nanos(writer, delta.ts_event);
305    encode_unix_nanos(writer, delta.ts_init);
306}