nautilus_model/python/orderbook/
own.rs
1use std::{
17 collections::{HashSet, hash_map::DefaultHasher},
18 hash::{Hash, Hasher},
19};
20
21use indexmap::IndexMap;
22use nautilus_core::python::{IntoPyObjectNautilusExt, to_pyruntime_err};
23use pyo3::{Python, prelude::*, pyclass::CompareOp};
24use rust_decimal::Decimal;
25
26use crate::{
27 enums::{OrderSide, OrderStatus, OrderType, TimeInForce},
28 identifiers::{ClientOrderId, InstrumentId, TraderId, VenueOrderId},
29 orderbook::{OwnBookOrder, own::OwnOrderBook},
30 types::{Price, Quantity},
31};
32
33#[pymethods]
34impl OwnBookOrder {
35 #[pyo3(signature = (trader_id, client_order_id, side, price, size, order_type, time_in_force, status, ts_last, ts_accepted, ts_submitted, ts_init, venue_order_id=None))]
36 #[new]
37 #[allow(clippy::too_many_arguments)]
38 fn py_new(
39 trader_id: TraderId,
40 client_order_id: ClientOrderId,
41 side: OrderSide,
42 price: Price,
43 size: Quantity,
44 order_type: OrderType,
45 time_in_force: TimeInForce,
46 status: OrderStatus,
47 ts_last: u64,
48 ts_accepted: u64,
49 ts_submitted: u64,
50 ts_init: u64,
51 venue_order_id: Option<VenueOrderId>,
52 ) -> PyResult<Self> {
53 Ok(OwnBookOrder::new(
54 trader_id,
55 client_order_id,
56 venue_order_id,
57 side.as_specified(),
58 price,
59 size,
60 order_type,
61 time_in_force,
62 status,
63 ts_last.into(),
64 ts_accepted.into(),
65 ts_submitted.into(),
66 ts_init.into(),
67 ))
68 }
69
70 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
71 match op {
72 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
73 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
74 _ => py.NotImplemented(),
75 }
76 }
77
78 fn __hash__(&self) -> isize {
79 let mut hasher = DefaultHasher::new();
80 self.hash(&mut hasher);
81 hasher.finish() as isize
82 }
83
84 fn __repr__(&self) -> String {
85 format!("{self:?}")
86 }
87
88 fn __str__(&self) -> String {
89 self.to_string()
90 }
91
92 #[getter]
93 #[pyo3(name = "client_order_id")]
94 fn py_client_order_id(&self) -> ClientOrderId {
95 self.client_order_id
96 }
97
98 #[getter]
99 #[pyo3(name = "side")]
100 fn py_side(&self) -> OrderSide {
101 self.side.as_order_side()
102 }
103
104 #[getter]
105 #[pyo3(name = "price")]
106 fn py_price(&self) -> Price {
107 self.price
108 }
109
110 #[getter]
111 #[pyo3(name = "size")]
112 fn py_size(&self) -> Quantity {
113 self.size
114 }
115
116 #[getter]
117 #[pyo3(name = "order_type")]
118 fn py_order_type(&self) -> OrderType {
119 self.order_type
120 }
121
122 #[getter]
123 #[pyo3(name = "time_in_force")]
124 fn py_time_in_force(&self) -> TimeInForce {
125 self.time_in_force
126 }
127
128 #[getter]
129 #[pyo3(name = "status")]
130 fn py_status(&self) -> OrderStatus {
131 self.status
132 }
133
134 #[getter]
135 #[pyo3(name = "ts_last")]
136 fn py_ts_last(&self) -> u64 {
137 self.ts_last.into()
138 }
139
140 #[getter]
141 #[pyo3(name = "ts_init")]
142 fn py_ts_init(&self) -> u64 {
143 self.ts_init.into()
144 }
145
146 #[pyo3(name = "exposure")]
147 fn py_exposure(&self) -> f64 {
148 self.exposure()
149 }
150
151 #[pyo3(name = "signed_size")]
152 fn py_signed_size(&self) -> f64 {
153 self.signed_size()
154 }
155}
156
157#[pymethods]
158impl OwnOrderBook {
159 #[new]
160 fn py_new(instrument_id: InstrumentId) -> Self {
161 Self::new(instrument_id)
162 }
163
164 fn __repr__(&self) -> String {
165 format!("{self:?}")
166 }
167
168 fn __str__(&self) -> String {
169 self.to_string()
170 }
171
172 #[getter]
173 #[pyo3(name = "instrument_id")]
174 fn py_instrument_id(&self) -> InstrumentId {
175 self.instrument_id
176 }
177
178 #[getter]
179 #[pyo3(name = "ts_last")]
180 fn py_ts_last(&self) -> u64 {
181 self.ts_last.as_u64()
182 }
183
184 #[getter]
185 #[pyo3(name = "update_count")]
186 fn py_update_count(&self) -> u64 {
187 self.update_count
188 }
189
190 #[pyo3(name = "reset")]
191 fn py_reset(&mut self) {
192 self.reset();
193 }
194
195 #[pyo3(name = "add")]
196 fn py_add(&mut self, order: OwnBookOrder) {
197 self.add(order);
198 }
199
200 #[pyo3(name = "update")]
201 fn py_update(&mut self, order: OwnBookOrder) -> PyResult<()> {
202 self.update(order).map_err(to_pyruntime_err)
203 }
204
205 #[pyo3(name = "delete")]
206 fn py_delete(&mut self, order: OwnBookOrder) -> PyResult<()> {
207 self.delete(order).map_err(to_pyruntime_err)
208 }
209
210 #[pyo3(name = "clear")]
211 fn py_clear(&mut self) {
212 self.clear();
213 }
214
215 #[pyo3(name = "bid_client_order_ids")]
216 pub fn py_bid_client_order_ids(&self) -> Vec<ClientOrderId> {
217 self.bid_client_order_ids()
218 }
219
220 #[pyo3(name = "ask_client_order_ids")]
221 pub fn py_ask_client_order_ids(&self) -> Vec<ClientOrderId> {
222 self.ask_client_order_ids()
223 }
224
225 #[pyo3(name = "is_order_in_book")]
226 pub fn py_is_order_in_book(&self, client_order_id: &ClientOrderId) -> bool {
227 self.is_order_in_book(client_order_id)
228 }
229
230 #[pyo3(name = "orders_to_list")]
231 fn py_orders_to_list(&self) -> Vec<OwnBookOrder> {
232 let total_orders = self.bids.cache.len() + self.asks.cache.len();
233 let mut all_orders = Vec::with_capacity(total_orders);
234
235 all_orders.extend(
236 self.bids()
237 .flat_map(|level| level.orders.values().cloned())
238 .chain(self.asks().flat_map(|level| level.orders.values().cloned())),
239 );
240
241 all_orders
242 }
243
244 #[pyo3(name = "bids_to_list")]
245 fn py_bids_to_list(&self) -> Vec<OwnBookOrder> {
246 self.bids()
247 .flat_map(|level| level.orders.values().cloned())
248 .collect()
249 }
250
251 #[pyo3(name = "asks_to_list")]
252 fn py_asks_to_list(&self) -> Vec<OwnBookOrder> {
253 self.asks()
254 .flat_map(|level| level.orders.values().cloned())
255 .collect()
256 }
257
258 #[pyo3(name = "bids_to_dict")]
259 #[pyo3(signature = (status=None, accepted_buffer_ns=None, ts_now=None))]
260 fn py_bids_to_dict(
261 &self,
262 status: Option<HashSet<OrderStatus>>,
263 accepted_buffer_ns: Option<u64>,
264 ts_now: Option<u64>,
265 ) -> IndexMap<Decimal, Vec<OwnBookOrder>> {
266 self.bids_as_map(status, accepted_buffer_ns, ts_now)
267 }
268
269 #[pyo3(name = "asks_to_dict")]
270 #[pyo3(signature = (status=None, accepted_buffer_ns=None, ts_now=None))]
271 fn py_asks_to_dict(
272 &self,
273 status: Option<HashSet<OrderStatus>>,
274 accepted_buffer_ns: Option<u64>,
275 ts_now: Option<u64>,
276 ) -> IndexMap<Decimal, Vec<OwnBookOrder>> {
277 self.asks_as_map(status, accepted_buffer_ns, ts_now)
278 }
279
280 #[pyo3(name = "bid_quantity")]
281 #[pyo3(signature = (status=None, accepted_buffer_ns=None, ts_now=None))]
282 fn py_bid_quantity(
283 &self,
284 status: Option<HashSet<OrderStatus>>,
285 accepted_buffer_ns: Option<u64>,
286 ts_now: Option<u64>,
287 ) -> IndexMap<Decimal, Decimal> {
288 self.bid_quantity(status, accepted_buffer_ns, ts_now)
289 }
290
291 #[pyo3(name = "ask_quantity")]
292 #[pyo3(signature = (status=None, accepted_buffer_ns=None, ts_now=None))]
293 fn py_ask_quantity(
294 &self,
295 status: Option<HashSet<OrderStatus>>,
296 accepted_buffer_ns: Option<u64>,
297 ts_now: Option<u64>,
298 ) -> IndexMap<Decimal, Decimal> {
299 self.ask_quantity(status, accepted_buffer_ns, ts_now)
300 }
301
302 #[pyo3(name = "group_bids")]
303 #[pyo3(signature = (group_size, depth=None, status=None, accepted_buffer_ns=None, ts_now=None))]
304 fn py_group_bids(
305 &self,
306 group_size: Decimal,
307 depth: Option<usize>,
308 status: Option<HashSet<OrderStatus>>,
309 accepted_buffer_ns: Option<u64>,
310 ts_now: Option<u64>,
311 ) -> IndexMap<Decimal, Decimal> {
312 self.group_bids(group_size, depth, status, accepted_buffer_ns, ts_now)
313 }
314
315 #[pyo3(name = "group_asks")]
316 #[pyo3(signature = (group_size, depth=None, status=None, accepted_buffer_ns=None, ts_now=None))]
317 fn py_group_asks(
318 &self,
319 group_size: Decimal,
320 depth: Option<usize>,
321 status: Option<HashSet<OrderStatus>>,
322 accepted_buffer_ns: Option<u64>,
323 ts_now: Option<u64>,
324 ) -> IndexMap<Decimal, Decimal> {
325 self.group_asks(group_size, depth, status, accepted_buffer_ns, ts_now)
326 }
327
328 #[pyo3(name = "audit_open_orders")]
329 fn py_audit_open_orders(&mut self, open_order_ids: HashSet<ClientOrderId>) {
330 self.audit_open_orders(&open_order_ids)
331 }
332
333 #[pyo3(name = "pprint")]
334 #[pyo3(signature = (num_levels=3))]
335 fn py_pprint(&self, num_levels: usize) -> String {
336 self.pprint(num_levels)
337 }
338}