nautilus_model/python/orderbook/
book.rs1use indexmap::IndexMap;
17use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
18use pyo3::prelude::*;
19use rust_decimal::Decimal;
20
21use crate::{
22 data::{BookOrder, OrderBookDelta, OrderBookDeltas, OrderBookDepth10, QuoteTick, TradeTick},
23 enums::{BookType, OrderSide},
24 identifiers::InstrumentId,
25 orderbook::{analysis::book_check_integrity, BookLevel, OrderBook},
26 types::{Price, Quantity},
27};
28
29#[pymethods]
30impl OrderBook {
31 #[new]
32 fn py_new(instrument_id: InstrumentId, book_type: BookType) -> Self {
33 Self::new(instrument_id, book_type)
34 }
35
36 fn __repr__(&self) -> String {
37 format!("{self:?}")
38 }
39
40 fn __str__(&self) -> String {
41 format!("{self:?}")
43 }
44
45 #[getter]
46 #[pyo3(name = "instrument_id")]
47 fn py_instrument_id(&self) -> InstrumentId {
48 self.instrument_id
49 }
50
51 #[getter]
52 #[pyo3(name = "book_type")]
53 fn py_book_type(&self) -> BookType {
54 self.book_type
55 }
56
57 #[getter]
58 #[pyo3(name = "sequence")]
59 fn py_sequence(&self) -> u64 {
60 self.sequence
61 }
62
63 #[getter]
64 #[pyo3(name = "ts_event")]
65 fn py_ts_event(&self) -> u64 {
66 self.ts_last.as_u64()
67 }
68
69 #[getter]
70 #[pyo3(name = "ts_init")]
71 fn py_ts_init(&self) -> u64 {
72 self.ts_last.as_u64()
73 }
74
75 #[getter]
76 #[pyo3(name = "ts_last")]
77 fn py_ts_last(&self) -> u64 {
78 self.ts_last.as_u64()
79 }
80
81 #[getter]
82 #[pyo3(name = "count")]
83 fn py_count(&self) -> u64 {
84 self.count
85 }
86
87 #[pyo3(name = "reset")]
88 fn py_reset(&mut self) {
89 self.reset();
90 }
91
92 #[pyo3(signature = (order, flags, sequence, ts_event))]
93 #[pyo3(name = "add")]
94 fn py_add(&mut self, order: BookOrder, flags: u8, sequence: u64, ts_event: u64) {
95 self.add(order, flags, sequence, ts_event.into());
96 }
97
98 #[pyo3(signature = (order, flags, sequence, ts_event))]
99 #[pyo3(name = "update")]
100 fn py_update(&mut self, order: BookOrder, flags: u8, sequence: u64, ts_event: u64) {
101 self.update(order, flags, sequence, ts_event.into());
102 }
103
104 #[pyo3(signature = (order, flags, sequence, ts_event))]
105 #[pyo3(name = "delete")]
106 fn py_delete(&mut self, order: BookOrder, flags: u8, sequence: u64, ts_event: u64) {
107 self.delete(order, flags, sequence, ts_event.into());
108 }
109
110 #[pyo3(signature = (sequence, ts_event))]
111 #[pyo3(name = "clear")]
112 fn py_clear(&mut self, sequence: u64, ts_event: u64) {
113 self.clear(sequence, ts_event.into());
114 }
115
116 #[pyo3(signature = (sequence, ts_event))]
117 #[pyo3(name = "clear_bids")]
118 fn py_clear_bids(&mut self, sequence: u64, ts_event: u64) {
119 self.clear_bids(sequence, ts_event.into());
120 }
121
122 #[pyo3(signature = (sequence, ts_event))]
123 #[pyo3(name = "clear_asks")]
124 fn py_clear_asks(&mut self, sequence: u64, ts_event: u64) {
125 self.clear_asks(sequence, ts_event.into());
126 }
127
128 #[pyo3(name = "apply_delta")]
129 fn py_apply_delta(&mut self, delta: &OrderBookDelta) {
130 self.apply_delta(delta);
131 }
132
133 #[pyo3(name = "apply_deltas")]
134 fn py_apply_deltas(&mut self, deltas: &OrderBookDeltas) {
135 self.apply_deltas(deltas);
136 }
137
138 #[pyo3(name = "apply_depth")]
139 fn py_apply_depth(&mut self, depth: &OrderBookDepth10) {
140 self.apply_depth(depth);
141 }
142
143 #[pyo3(name = "check_integrity")]
144 fn py_check_integrity(&mut self) -> PyResult<()> {
145 book_check_integrity(self).map_err(to_pyruntime_err)
146 }
147
148 #[pyo3(signature = (depth=None))]
149 #[pyo3(name = "bids")]
150 fn py_bids(&self, depth: Option<usize>) -> Vec<BookLevel> {
151 self.bids(depth)
152 .map(|level_ref| (*level_ref).clone())
153 .collect()
154 }
155
156 #[pyo3(signature = (depth=None))]
157 #[pyo3(name = "asks")]
158 fn py_asks(&self, depth: Option<usize>) -> Vec<BookLevel> {
159 self.asks(depth)
160 .map(|level_ref| (*level_ref).clone())
161 .collect()
162 }
163
164 #[pyo3(signature = (depth=None))]
165 #[pyo3(name = "bids_to_dict")]
166 fn py_bids_to_dict(&self, depth: Option<usize>) -> IndexMap<Decimal, Decimal> {
167 self.bids_as_map(depth)
168 }
169
170 #[pyo3(signature = (depth=None))]
171 #[pyo3(name = "asks_to_dict")]
172 fn py_asks_to_dict(&self, depth: Option<usize>) -> IndexMap<Decimal, Decimal> {
173 self.asks_as_map(depth)
174 }
175
176 #[pyo3(signature = (group_size, depth=None))]
177 #[pyo3(name = "group_bids")]
178 pub fn py_group_bids(
179 &self,
180 group_size: Decimal,
181 depth: Option<usize>,
182 ) -> IndexMap<Decimal, Decimal> {
183 self.group_bids(group_size, depth)
184 }
185
186 #[pyo3(signature = (group_size, depth=None))]
187 #[pyo3(name = "group_asks")]
188 pub fn py_group_asks(
189 &self,
190 group_size: Decimal,
191 depth: Option<usize>,
192 ) -> IndexMap<Decimal, Decimal> {
193 self.group_asks(group_size, depth)
194 }
195
196 #[pyo3(name = "best_bid_price")]
197 fn py_best_bid_price(&self) -> Option<Price> {
198 self.best_bid_price()
199 }
200
201 #[pyo3(name = "best_ask_price")]
202 fn py_best_ask_price(&self) -> Option<Price> {
203 self.best_ask_price()
204 }
205
206 #[pyo3(name = "best_bid_size")]
207 fn py_best_bid_size(&self) -> Option<Quantity> {
208 self.best_bid_size()
209 }
210
211 #[pyo3(name = "best_ask_size")]
212 fn py_best_ask_size(&self) -> Option<Quantity> {
213 self.best_ask_size()
214 }
215
216 #[pyo3(name = "spread")]
217 fn py_spread(&self) -> Option<f64> {
218 self.spread()
219 }
220
221 #[pyo3(name = "midpoint")]
222 fn py_midpoint(&self) -> Option<f64> {
223 self.midpoint()
224 }
225
226 #[pyo3(name = "get_avg_px_for_quantity")]
227 fn py_get_avg_px_for_quantity(&self, qty: Quantity, order_side: OrderSide) -> f64 {
228 self.get_avg_px_for_quantity(qty, order_side)
229 }
230
231 #[pyo3(name = "get_avg_px_qty_for_exposure")]
232 fn py_get_avg_px_qty_for_exposure(
233 &self,
234 qty: Quantity,
235 order_side: OrderSide,
236 ) -> (f64, f64, f64) {
237 self.get_avg_px_qty_for_exposure(qty, order_side)
238 }
239
240 #[pyo3(name = "get_quantity_for_price")]
241 fn py_get_quantity_for_price(&self, price: Price, order_side: OrderSide) -> f64 {
242 self.get_quantity_for_price(price, order_side)
243 }
244
245 #[pyo3(name = "simulate_fills")]
246 fn py_simulate_fills(&self, order: &BookOrder) -> Vec<(Price, Quantity)> {
247 self.simulate_fills(order)
248 }
249
250 #[pyo3(name = "pprint")]
251 fn py_pprint(&self, num_levels: usize) -> String {
252 self.pprint(num_levels)
253 }
254}
255
256#[pyfunction()]
257#[pyo3(name = "update_book_with_quote_tick")]
258pub fn py_update_book_with_quote_tick(book: &mut OrderBook, quote: &QuoteTick) -> PyResult<()> {
259 book.update_quote_tick(quote).map_err(to_pyvalue_err)
260}
261
262#[pyfunction()]
263#[pyo3(name = "update_book_with_trade_tick")]
264pub fn py_update_book_with_trade_tick(book: &mut OrderBook, trade: &TradeTick) -> PyResult<()> {
265 book.update_trade_tick(trade).map_err(to_pyvalue_err)
266}