nautilus_model/python/orderbook/
own.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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 std::{
17    collections::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},
29    orderbook::{OwnBookOrder, own::OwnOrderBook},
30    types::{Price, Quantity},
31};
32
33#[pymethods]
34impl OwnBookOrder {
35    #[new]
36    #[allow(clippy::too_many_arguments)]
37    fn py_new(
38        client_order_id: ClientOrderId,
39        side: OrderSide,
40        price: Price,
41        size: Quantity,
42        order_type: OrderType,
43        time_in_force: TimeInForce,
44        status: OrderStatus,
45        ts_last: u64,
46        ts_init: u64,
47    ) -> PyResult<Self> {
48        Ok(OwnBookOrder::new(
49            client_order_id,
50            side.as_specified(),
51            price,
52            size,
53            order_type,
54            time_in_force,
55            status,
56            ts_last.into(),
57            ts_init.into(),
58        ))
59    }
60
61    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
62        match op {
63            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
64            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
65            _ => py.NotImplemented(),
66        }
67    }
68
69    fn __hash__(&self) -> isize {
70        let mut hasher = DefaultHasher::new();
71        self.hash(&mut hasher);
72        hasher.finish() as isize
73    }
74
75    fn __repr__(&self) -> String {
76        format!("{self:?}")
77    }
78
79    fn __str__(&self) -> String {
80        self.to_string()
81    }
82
83    #[getter]
84    #[pyo3(name = "client_order_id")]
85    fn py_client_order_id(&self) -> ClientOrderId {
86        self.client_order_id
87    }
88
89    #[getter]
90    #[pyo3(name = "side")]
91    fn py_side(&self) -> OrderSide {
92        self.side.as_order_side()
93    }
94
95    #[getter]
96    #[pyo3(name = "price")]
97    fn py_price(&self) -> Price {
98        self.price
99    }
100
101    #[getter]
102    #[pyo3(name = "size")]
103    fn py_size(&self) -> Quantity {
104        self.size
105    }
106
107    #[getter]
108    #[pyo3(name = "order_type")]
109    fn py_order_type(&self) -> OrderType {
110        self.order_type
111    }
112
113    #[getter]
114    #[pyo3(name = "time_in_force")]
115    fn py_time_in_force(&self) -> TimeInForce {
116        self.time_in_force
117    }
118
119    #[getter]
120    #[pyo3(name = "status")]
121    fn py_status(&self) -> OrderStatus {
122        self.status
123    }
124
125    #[getter]
126    #[pyo3(name = "ts_last")]
127    fn py_ts_last(&self) -> u64 {
128        self.ts_last.into()
129    }
130
131    #[getter]
132    #[pyo3(name = "ts_init")]
133    fn py_ts_init(&self) -> u64 {
134        self.ts_init.into()
135    }
136
137    #[pyo3(name = "exposure")]
138    fn py_exposure(&self) -> f64 {
139        self.exposure()
140    }
141
142    #[pyo3(name = "signed_size")]
143    fn py_signed_size(&self) -> f64 {
144        self.signed_size()
145    }
146}
147
148#[pymethods]
149impl OwnOrderBook {
150    #[new]
151    fn py_new(instrument_id: InstrumentId) -> Self {
152        Self::new(instrument_id)
153    }
154
155    fn __repr__(&self) -> String {
156        format!("{self:?}")
157    }
158
159    fn __str__(&self) -> String {
160        self.to_string()
161    }
162
163    #[getter]
164    #[pyo3(name = "instrument_id")]
165    fn py_instrument_id(&self) -> InstrumentId {
166        self.instrument_id
167    }
168
169    #[getter]
170    #[pyo3(name = "ts_last")]
171    fn py_ts_last(&self) -> u64 {
172        self.ts_last.as_u64()
173    }
174
175    #[getter]
176    #[pyo3(name = "event_count")]
177    fn py_count(&self) -> u64 {
178        self.event_count
179    }
180
181    #[pyo3(name = "reset")]
182    fn py_reset(&mut self) {
183        self.reset();
184    }
185
186    #[pyo3(name = "add")]
187    fn py_add(&mut self, order: OwnBookOrder) {
188        self.add(order);
189    }
190
191    #[pyo3(name = "update")]
192    fn py_update(&mut self, order: OwnBookOrder) -> PyResult<()> {
193        self.update(order).map_err(to_pyruntime_err)
194    }
195
196    #[pyo3(name = "delete")]
197    fn py_delete(&mut self, order: OwnBookOrder) -> PyResult<()> {
198        self.delete(order).map_err(to_pyruntime_err)
199    }
200
201    #[pyo3(name = "clear")]
202    fn py_clear(&mut self) {
203        self.clear();
204    }
205
206    #[pyo3(name = "bids_to_dict")]
207    fn py_bids_to_dict(&self) -> IndexMap<Decimal, Vec<OwnBookOrder>> {
208        self.bids_as_map()
209    }
210
211    #[pyo3(name = "asks_to_dict")]
212    fn py_asks_to_dict(&self) -> IndexMap<Decimal, Vec<OwnBookOrder>> {
213        self.asks_as_map()
214    }
215
216    #[pyo3(name = "bid_quantity")]
217    fn py_bid_quantity(&self) -> IndexMap<Decimal, Decimal> {
218        self.bid_quantity()
219    }
220
221    #[pyo3(name = "ask_quantity")]
222    fn py_ask_quantity(&self) -> IndexMap<Decimal, Decimal> {
223        self.ask_quantity()
224    }
225
226    #[pyo3(signature = (num_levels=3))]
227    #[pyo3(name = "pprint")]
228    fn py_pprint(&self, num_levels: usize) -> String {
229        self.pprint(num_levels)
230    }
231}