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, OrderBookDepth10},
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            encode_order_book_delta_fields(writer, delta);
102            encode_instrument_id(writer, &delta.instrument_id)?;
103        }
104        Ok(())
105    }
106
107    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
108        let mut scratch = Vec::new();
109        decode_order_book_deltas_body(cursor, &mut scratch)
110    }
111
112    fn encoded_body_size(&self) -> usize {
113        usize::from(Self::BLOCK_LENGTH)
114            + encoded_instrument_id_size(&self.instrument_id)
115            + GROUP_HEADER_16_LENGTH
116            + self
117                .deltas
118                .iter()
119                .map(encoded_order_book_delta_size)
120                .sum::<usize>()
121    }
122}
123
124impl FromSbeReuse for OrderBookDeltas {
125    type Scratch = Vec<OrderBookDelta>;
126
127    fn from_sbe_reuse(
128        bytes: &[u8],
129        scratch: &mut Vec<OrderBookDelta>,
130    ) -> Result<Self, SbeDecodeError> {
131        let mut cursor = SbeCursor::new(bytes);
132        let header = decode_header(&mut cursor)?;
133        validate_header(
134            header,
135            <Self as MarketSbeMessage>::TEMPLATE_ID,
136            <Self as MarketSbeMessage>::BLOCK_LENGTH,
137        )?;
138        decode_order_book_deltas_body(&mut cursor, scratch)
139    }
140}
141
142fn decode_order_book_deltas_body(
143    cursor: &mut SbeCursor<'_>,
144    scratch: &mut Vec<OrderBookDelta>,
145) -> Result<OrderBookDeltas, SbeDecodeError> {
146    let flags = cursor.read_u8()?;
147    let sequence = cursor.read_u64_le()?;
148    let ts_event = decode_unix_nanos(cursor)?;
149    let ts_init = decode_unix_nanos(cursor)?;
150    let instrument_id = decode_instrument_id(cursor)?;
151    let (block_length, count) = cursor.read_group_header_16()?;
152
153    if block_length != ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH {
154        return Err(SbeDecodeError::InvalidBlockLength {
155            expected: ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH,
156            actual: block_length,
157        });
158    }
159
160    let count = usize::from(count);
161    scratch.clear();
162    scratch.reserve(count);
163
164    for _ in 0..count {
165        let action = decode_book_action(cursor)?;
166        let order = decode_book_order(cursor)?;
167        let delta_flags = cursor.read_u8()?;
168        let delta_sequence = cursor.read_u64_le()?;
169        let delta_ts_event = decode_unix_nanos(cursor)?;
170        let delta_ts_init = decode_unix_nanos(cursor)?;
171        let delta_instrument_id = decode_instrument_id(cursor)?;
172
173        scratch.push(OrderBookDelta {
174            instrument_id: delta_instrument_id,
175            action,
176            order,
177            flags: delta_flags,
178            sequence: delta_sequence,
179            ts_event: delta_ts_event,
180            ts_init: delta_ts_init,
181        });
182    }
183
184    Ok(OrderBookDeltas {
185        instrument_id,
186        deltas: std::mem::take(scratch),
187        flags,
188        sequence,
189        ts_event,
190        ts_init,
191    })
192}
193
194impl MarketSbeMessage for OrderBookDepth10 {
195    const TEMPLATE_ID: u16 = template_id::ORDER_BOOK_DEPTH10;
196    const BLOCK_LENGTH: u16 =
197        (DEPTH10_LEVEL_BLOCK_LENGTH * 20) + (DEPTH10_COUNTS_BLOCK_LENGTH as u16 * 2) + 25;
198
199    fn encode_body(&self, writer: &mut SbeWriter<'_>) -> Result<(), SbeEncodeError> {
200        for bid in &self.bids {
201            encode_price(writer, &bid.price);
202            encode_quantity(writer, &bid.size);
203        }
204
205        for ask in &self.asks {
206            encode_price(writer, &ask.price);
207            encode_quantity(writer, &ask.size);
208        }
209
210        for count in &self.bid_counts {
211            writer.write_u32_le(*count);
212        }
213
214        for count in &self.ask_counts {
215            writer.write_u32_le(*count);
216        }
217        writer.write_u8(self.flags);
218        writer.write_u64_le(self.sequence);
219        encode_unix_nanos(writer, self.ts_event);
220        encode_unix_nanos(writer, self.ts_init);
221        encode_instrument_id(writer, &self.instrument_id)
222    }
223
224    fn decode_body(cursor: &mut SbeCursor<'_>) -> Result<Self, SbeDecodeError> {
225        let mut bids = [BookOrder::default(); DEPTH10_LEVEL_COUNT];
226        let mut asks = [BookOrder::default(); DEPTH10_LEVEL_COUNT];
227
228        for bid in &mut bids {
229            *bid = BookOrder::new(
230                OrderSide::Buy,
231                decode_price(cursor)?,
232                decode_quantity(cursor)?,
233                0,
234            );
235        }
236
237        for ask in &mut asks {
238            *ask = BookOrder::new(
239                OrderSide::Sell,
240                decode_price(cursor)?,
241                decode_quantity(cursor)?,
242                0,
243            );
244        }
245
246        let mut bid_counts = [0u32; DEPTH10_LEVEL_COUNT];
247        let mut ask_counts = [0u32; DEPTH10_LEVEL_COUNT];
248
249        for count in &mut bid_counts {
250            *count = cursor.read_u32_le()?;
251        }
252
253        for count in &mut ask_counts {
254            *count = cursor.read_u32_le()?;
255        }
256
257        let flags = cursor.read_u8()?;
258        let sequence = cursor.read_u64_le()?;
259        let ts_event = decode_unix_nanos(cursor)?;
260        let ts_init = decode_unix_nanos(cursor)?;
261        let instrument_id = decode_instrument_id(cursor)?;
262
263        Ok(Self {
264            instrument_id,
265            bids,
266            asks,
267            bid_counts,
268            ask_counts,
269            flags,
270            sequence,
271            ts_event,
272            ts_init,
273        })
274    }
275
276    fn encoded_body_size(&self) -> usize {
277        usize::from(Self::BLOCK_LENGTH) + encoded_instrument_id_size(&self.instrument_id)
278    }
279}
280
281fn encode_book_order(writer: &mut SbeWriter<'_>, order: &BookOrder) {
282    encode_price(writer, &order.price);
283    encode_quantity(writer, &order.size);
284    writer.write_u8(order.side as u8);
285    writer.write_u64_le(order.order_id);
286}
287
288fn decode_book_order(cursor: &mut SbeCursor<'_>) -> Result<BookOrder, SbeDecodeError> {
289    let price = decode_price(cursor)?;
290    let size = decode_quantity(cursor)?;
291    let side = decode_order_side(cursor)?;
292    let order_id = cursor.read_u64_le()?;
293    Ok(BookOrder {
294        side,
295        price,
296        size,
297        order_id,
298    })
299}
300
301fn encode_order_book_delta_fields(writer: &mut SbeWriter<'_>, delta: &OrderBookDelta) {
302    writer.write_u8(delta.action as u8);
303    encode_book_order(writer, &delta.order);
304    writer.write_u8(delta.flags);
305    writer.write_u64_le(delta.sequence);
306    encode_unix_nanos(writer, delta.ts_event);
307    encode_unix_nanos(writer, delta.ts_init);
308}
309
310fn encoded_order_book_delta_size(delta: &OrderBookDelta) -> usize {
311    usize::from(ORDER_BOOK_DELTA_GROUP_BLOCK_LENGTH)
312        + encoded_instrument_id_size(&delta.instrument_id)
313}