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