nautilus_model/python/data/
depth.rs1use std::{
17 collections::{HashMap, hash_map::DefaultHasher},
18 hash::{Hash, Hasher},
19};
20
21use nautilus_core::{
22 python::{
23 IntoPyObjectNautilusExt,
24 serialization::{from_dict_pyo3, to_dict_pyo3},
25 to_pyvalue_err,
26 },
27 serialization::{
28 Serializable,
29 msgpack::{FromMsgPack, ToMsgPack},
30 },
31};
32use pyo3::{IntoPyObjectExt, prelude::*, pyclass::CompareOp, types::PyDict};
33
34use crate::{
35 data::{
36 depth::{DEPTH10_LEN, OrderBookDepth10},
37 order::BookOrder,
38 },
39 enums::OrderSide,
40 identifiers::InstrumentId,
41 python::common::PY_MODULE_MODEL,
42 types::{Price, Quantity},
43};
44
45#[pymethods]
46#[pyo3_stub_gen::derive::gen_stub_pymethods]
47impl OrderBookDepth10 {
48 #[expect(clippy::too_many_arguments)]
61 #[new]
62 fn py_new(
63 instrument_id: InstrumentId,
64 bids: [BookOrder; DEPTH10_LEN],
65 asks: [BookOrder; DEPTH10_LEN],
66 bid_counts: [u32; DEPTH10_LEN],
67 ask_counts: [u32; DEPTH10_LEN],
68 flags: u8,
69 sequence: u64,
70 ts_event: u64,
71 ts_init: u64,
72 ) -> Self {
73 Self::new(
74 instrument_id,
75 bids,
76 asks,
77 bid_counts,
78 ask_counts,
79 flags,
80 sequence,
81 ts_event.into(),
82 ts_init.into(),
83 )
84 }
85
86 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
87 match op {
88 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
89 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
90 _ => py.NotImplemented(),
91 }
92 }
93
94 fn __hash__(&self) -> isize {
95 let mut h = DefaultHasher::new();
96 self.hash(&mut h);
97 h.finish() as isize
98 }
99
100 fn __repr__(&self) -> String {
101 format!("{self:?}")
102 }
103
104 fn __str__(&self) -> String {
105 self.to_string()
106 }
107
108 #[getter]
109 #[pyo3(name = "instrument_id")]
110 fn py_instrument_id(&self) -> InstrumentId {
111 self.instrument_id
112 }
113
114 #[getter]
115 #[pyo3(name = "bids")]
116 fn py_bids(&self) -> [BookOrder; DEPTH10_LEN] {
117 self.bids
118 }
119
120 #[getter]
121 #[pyo3(name = "asks")]
122 fn py_asks(&self) -> [BookOrder; DEPTH10_LEN] {
123 self.asks
124 }
125
126 #[getter]
127 #[pyo3(name = "bid_counts")]
128 fn py_bid_counts(&self) -> [u32; DEPTH10_LEN] {
129 self.bid_counts
130 }
131
132 #[getter]
133 #[pyo3(name = "ask_counts")]
134 fn py_ask_counts(&self) -> [u32; DEPTH10_LEN] {
135 self.ask_counts
136 }
137
138 #[getter]
139 #[pyo3(name = "flags")]
140 fn py_flags(&self) -> u8 {
141 self.flags
142 }
143
144 #[getter]
145 #[pyo3(name = "sequence")]
146 fn py_sequence(&self) -> u64 {
147 self.sequence
148 }
149
150 #[getter]
151 #[pyo3(name = "ts_event")]
152 fn py_ts_event(&self) -> u64 {
153 self.ts_event.as_u64()
154 }
155
156 #[getter]
157 #[pyo3(name = "ts_init")]
158 fn py_ts_init(&self) -> u64 {
159 self.ts_init.as_u64()
160 }
161
162 #[staticmethod]
163 #[pyo3(name = "fully_qualified_name")]
164 fn py_fully_qualified_name() -> String {
165 format!("{}:{}", PY_MODULE_MODEL, stringify!(OrderBookDepth10))
166 }
167
168 #[staticmethod]
170 #[pyo3(name = "get_metadata")]
171 fn py_get_metadata(
172 instrument_id: &InstrumentId,
173 price_precision: u8,
174 size_precision: u8,
175 ) -> HashMap<String, String> {
176 Self::get_metadata(instrument_id, price_precision, size_precision)
177 }
178
179 #[staticmethod]
181 #[pyo3(name = "get_fields")]
182 fn py_get_fields(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
183 let py_dict = PyDict::new(py);
184 for (k, v) in Self::get_fields() {
185 py_dict.set_item(k, v)?;
186 }
187
188 Ok(py_dict)
189 }
190
191 #[staticmethod]
193 #[pyo3(name = "get_stub")]
194 fn py_get_stub() -> Self {
195 let instrument_id = InstrumentId::from("AAPL.XNAS");
196 let flags = 0;
197 let sequence = 0;
198 let ts_event = 1;
199 let ts_init = 2;
200
201 let mut bids: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
202 let mut asks: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
203
204 let mut price = 99.00;
206 let mut quantity = 100.0;
207
208 for (i, order) in bids.iter_mut().take(DEPTH10_LEN).enumerate() {
209 *order = BookOrder::new(
210 OrderSide::Buy,
211 Price::new(price, 2),
212 Quantity::new(quantity, 0),
213 (i + 1) as u64,
214 );
215
216 price -= 1.0;
217 quantity += 100.0;
218 }
219
220 let mut price = 100.00;
222 let mut quantity = 100.0;
223
224 for (i, order) in asks.iter_mut().take(DEPTH10_LEN).enumerate() {
225 *order = BookOrder::new(
226 OrderSide::Sell,
227 Price::new(price, 2),
228 Quantity::new(quantity, 0),
229 (i + 11) as u64,
230 );
231
232 price += 1.0;
233 quantity += 100.0;
234 }
235
236 let bid_counts: [u32; 10] = [1; 10];
237 let ask_counts: [u32; 10] = [1; 10];
238
239 Self::new(
240 instrument_id,
241 bids,
242 asks,
243 bid_counts,
244 ask_counts,
245 flags,
246 sequence,
247 ts_event.into(),
248 ts_init.into(),
249 )
250 }
251
252 #[staticmethod]
254 #[pyo3(name = "from_dict")]
255 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
256 from_dict_pyo3(py, values)
257 }
258
259 #[pyo3(name = "to_dict")]
261 fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
262 to_dict_pyo3(py, self)
263 }
264
265 #[pyo3(name = "to_json_bytes")]
267 fn py_to_json_bytes(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
268 self.to_json_bytes()
269 .map_err(to_pyvalue_err)?
270 .into_py_any(py)
271 }
272
273 #[pyo3(name = "to_msgpack_bytes")]
275 fn py_to_msgpack_bytes(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
276 self.to_msgpack_bytes()
277 .map_err(to_pyvalue_err)?
278 .into_py_any(py)
279 }
280}
281
282#[pymethods]
283impl OrderBookDepth10 {
284 #[staticmethod]
285 #[pyo3(name = "from_json")]
286 fn py_from_json(data: &[u8]) -> PyResult<Self> {
287 Self::from_json_bytes(data).map_err(to_pyvalue_err)
288 }
289
290 #[staticmethod]
291 #[pyo3(name = "from_msgpack")]
292 fn py_from_msgpack(data: &[u8]) -> PyResult<Self> {
293 Self::from_msgpack_bytes(data).map_err(to_pyvalue_err)
294 }
295}