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::Serializable,
28};
29use pyo3::{prelude::*, pyclass::CompareOp, types::PyDict};
30
31use super::data_to_pycapsule;
32use crate::{
33 data::{
34 Data,
35 depth::{DEPTH10_LEN, OrderBookDepth10},
36 order::BookOrder,
37 },
38 enums::OrderSide,
39 identifiers::InstrumentId,
40 python::common::PY_MODULE_MODEL,
41 types::{Price, Quantity},
42};
43
44#[pymethods]
45impl OrderBookDepth10 {
46 #[allow(clippy::too_many_arguments)]
47 #[new]
48 fn py_new(
49 instrument_id: InstrumentId,
50 bids: [BookOrder; DEPTH10_LEN],
51 asks: [BookOrder; DEPTH10_LEN],
52 bid_counts: [u32; DEPTH10_LEN],
53 ask_counts: [u32; DEPTH10_LEN],
54 flags: u8,
55 sequence: u64,
56 ts_event: u64,
57 ts_init: u64,
58 ) -> Self {
59 Self::new(
60 instrument_id,
61 bids,
62 asks,
63 bid_counts,
64 ask_counts,
65 flags,
66 sequence,
67 ts_event.into(),
68 ts_init.into(),
69 )
70 }
71
72 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
73 match op {
74 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
75 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
76 _ => py.NotImplemented(),
77 }
78 }
79
80 fn __hash__(&self) -> isize {
81 let mut h = DefaultHasher::new();
82 self.hash(&mut h);
83 h.finish() as isize
84 }
85
86 fn __repr__(&self) -> String {
87 format!("{self:?}")
88 }
89
90 fn __str__(&self) -> String {
91 self.to_string()
92 }
93
94 #[getter]
95 #[pyo3(name = "instrument_id")]
96 fn py_instrument_id(&self) -> InstrumentId {
97 self.instrument_id
98 }
99
100 #[getter]
101 #[pyo3(name = "bids")]
102 fn py_bids(&self) -> [BookOrder; DEPTH10_LEN] {
103 self.bids
104 }
105
106 #[getter]
107 #[pyo3(name = "asks")]
108 fn py_asks(&self) -> [BookOrder; DEPTH10_LEN] {
109 self.asks
110 }
111
112 #[getter]
113 #[pyo3(name = "bid_counts")]
114 fn py_bid_counts(&self) -> [u32; DEPTH10_LEN] {
115 self.bid_counts
116 }
117
118 #[getter]
119 #[pyo3(name = "ask_counts")]
120 fn py_ask_counts(&self) -> [u32; DEPTH10_LEN] {
121 self.ask_counts
122 }
123
124 #[getter]
125 #[pyo3(name = "flags")]
126 fn py_flags(&self) -> u8 {
127 self.flags
128 }
129
130 #[getter]
131 #[pyo3(name = "sequence")]
132 fn py_sequence(&self) -> u64 {
133 self.sequence
134 }
135
136 #[getter]
137 #[pyo3(name = "ts_event")]
138 fn py_ts_event(&self) -> u64 {
139 self.ts_event.as_u64()
140 }
141
142 #[getter]
143 #[pyo3(name = "ts_init")]
144 fn py_ts_init(&self) -> u64 {
145 self.ts_init.as_u64()
146 }
147
148 #[staticmethod]
149 #[pyo3(name = "fully_qualified_name")]
150 fn py_fully_qualified_name() -> String {
151 format!("{}:{}", PY_MODULE_MODEL, stringify!(OrderBookDepth10))
152 }
153
154 #[staticmethod]
155 #[pyo3(name = "get_metadata")]
156 fn py_get_metadata(
157 instrument_id: &InstrumentId,
158 price_precision: u8,
159 size_precision: u8,
160 ) -> PyResult<HashMap<String, String>> {
161 Ok(Self::get_metadata(
162 instrument_id,
163 price_precision,
164 size_precision,
165 ))
166 }
167
168 #[staticmethod]
169 #[pyo3(name = "get_fields")]
170 fn py_get_fields(py: Python<'_>) -> PyResult<Bound<'_, PyDict>> {
171 let py_dict = PyDict::new(py);
172 for (k, v) in Self::get_fields() {
173 py_dict.set_item(k, v)?;
174 }
175
176 Ok(py_dict)
177 }
178
179 #[staticmethod]
181 #[pyo3(name = "get_stub")]
182 fn py_get_stub() -> Self {
183 let instrument_id = InstrumentId::from("AAPL.XNAS");
184 let flags = 0;
185 let sequence = 0;
186 let ts_event = 1;
187 let ts_init = 2;
188
189 let mut bids: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
190 let mut asks: [BookOrder; DEPTH10_LEN] = [BookOrder::default(); DEPTH10_LEN];
191
192 let mut price = 99.00;
194 let mut quantity = 100.0;
195 let mut order_id = 1;
196
197 for order in bids.iter_mut().take(DEPTH10_LEN) {
198 *order = BookOrder::new(
199 OrderSide::Buy,
200 Price::new(price, 2),
201 Quantity::new(quantity, 0),
202 order_id,
203 );
204
205 price -= 1.0;
206 quantity += 100.0;
207 order_id += 1;
208 }
209
210 let mut price = 100.00;
212 let mut quantity = 100.0;
213 let mut order_id = 11;
214
215 for order in asks.iter_mut().take(DEPTH10_LEN) {
216 *order = BookOrder::new(
217 OrderSide::Sell,
218 Price::new(price, 2),
219 Quantity::new(quantity, 0),
220 order_id,
221 );
222
223 price += 1.0;
224 quantity += 100.0;
225 order_id += 1;
226 }
227
228 let bid_counts: [u32; 10] = [1; 10];
229 let ask_counts: [u32; 10] = [1; 10];
230
231 Self::new(
232 instrument_id,
233 bids,
234 asks,
235 bid_counts,
236 ask_counts,
237 flags,
238 sequence,
239 ts_event.into(),
240 ts_init.into(),
241 )
242 }
243
244 #[staticmethod]
246 #[pyo3(name = "from_dict")]
247 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
248 from_dict_pyo3(py, values)
249 }
250
251 #[staticmethod]
252 #[pyo3(name = "from_json")]
253 fn py_from_json(data: Vec<u8>) -> PyResult<Self> {
254 Self::from_json_bytes(&data).map_err(to_pyvalue_err)
255 }
256
257 #[staticmethod]
258 #[pyo3(name = "from_msgpack")]
259 fn py_from_msgpack(data: Vec<u8>) -> PyResult<Self> {
260 Self::from_msgpack_bytes(&data).map_err(to_pyvalue_err)
261 }
262
263 #[pyo3(name = "as_pycapsule")]
279 fn py_as_pycapsule(&self, py: Python<'_>) -> PyObject {
280 data_to_pycapsule(py, Data::from(*self))
281 }
282
283 #[pyo3(name = "as_dict")]
285 fn py_as_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
286 to_dict_pyo3(py, self)
287 }
288
289 #[pyo3(name = "as_json")]
291 fn py_as_json(&self, py: Python<'_>) -> Py<PyAny> {
292 self.as_json_bytes().unwrap().into_py_any_unwrap(py)
294 }
295
296 #[pyo3(name = "as_msgpack")]
298 fn py_as_msgpack(&self, py: Python<'_>) -> Py<PyAny> {
299 self.as_msgpack_bytes().unwrap().into_py_any_unwrap(py)
301 }
302}