nautilus_model/python/data/
deltas.rs1use std::{
17 collections::hash_map::DefaultHasher,
18 hash::{Hash, Hasher},
19 ops::Deref,
20};
21
22use nautilus_core::python::{IntoPyObjectNautilusExt, serialization::to_dict_pyo3, to_pyvalue_err};
23use pyo3::{
24 IntoPyObjectExt,
25 prelude::*,
26 pyclass::CompareOp,
27 types::{PyCapsule, PyList},
28};
29
30use super::data_to_pycapsule;
31use crate::{
32 data::{Data, OrderBookDelta, OrderBookDeltas, OrderBookDeltas_API},
33 identifiers::InstrumentId,
34 python::common::PY_MODULE_MODEL,
35};
36
37#[pymethods]
38#[pyo3_stub_gen::derive::gen_stub_pymethods]
39impl OrderBookDeltas {
40 #[new]
44 fn py_new(instrument_id: InstrumentId, deltas: Vec<OrderBookDelta>) -> PyResult<Self> {
45 Self::new_checked(instrument_id, deltas).map_err(to_pyvalue_err)
46 }
47
48 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
49 match op {
50 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
51 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
52 _ => py.NotImplemented(),
53 }
54 }
55
56 fn __hash__(&self) -> isize {
57 let mut h = DefaultHasher::new();
58 self.hash(&mut h);
59 h.finish() as isize
60 }
61
62 fn __repr__(&self) -> String {
63 format!("{self:?}")
64 }
65
66 fn __str__(&self) -> String {
67 self.to_string()
68 }
69
70 #[getter]
71 #[pyo3(name = "instrument_id")]
72 fn py_instrument_id(&self) -> InstrumentId {
73 self.instrument_id
74 }
75
76 #[getter]
77 #[pyo3(name = "deltas")]
78 fn py_deltas(&self) -> Vec<OrderBookDelta> {
79 self.deltas.clone()
81 }
82
83 #[getter]
84 #[pyo3(name = "flags")]
85 fn py_flags(&self) -> u8 {
86 self.flags
87 }
88
89 #[getter]
90 #[pyo3(name = "sequence")]
91 fn py_sequence(&self) -> u64 {
92 self.sequence
93 }
94
95 #[getter]
96 #[pyo3(name = "ts_event")]
97 fn py_ts_event(&self) -> u64 {
98 self.ts_event.as_u64()
99 }
100
101 #[getter]
102 #[pyo3(name = "ts_init")]
103 fn py_ts_init(&self) -> u64 {
104 self.ts_init.as_u64()
105 }
106
107 #[staticmethod]
108 #[pyo3(name = "fully_qualified_name")]
109 fn py_fully_qualified_name() -> String {
110 format!("{}:{}", PY_MODULE_MODEL, stringify!(OrderBookDeltas))
111 }
112
113 #[staticmethod]
117 #[pyo3(name = "from_pycapsule")]
118 #[allow(unsafe_code)]
119 #[must_use]
120 pub fn py_from_pycapsule(capsule: &Bound<'_, PyAny>) -> Self {
121 let capsule: &Bound<'_, PyCapsule> = capsule
122 .cast::<PyCapsule>()
123 .expect("Error on downcast to `&PyCapsule`");
124 let data: &OrderBookDeltas_API = unsafe {
125 &*(capsule.pointer_checked(None).unwrap().as_ptr() as *const OrderBookDeltas_API)
126 };
127 data.deref().clone()
128 }
129
130 #[pyo3(name = "as_pycapsule")]
146 fn py_as_pycapsule(&self, py: Python<'_>) -> Py<PyAny> {
147 let deltas = OrderBookDeltas_API::new(self.clone());
148 data_to_pycapsule(py, Data::Deltas(deltas))
149 }
150
151 fn __reduce__(&self, py: Python) -> PyResult<Py<PyAny>> {
152 let reconstruct = py.get_type::<Self>().getattr("_from_dicts")?;
153 let delta_dicts: Vec<_> = self
154 .deltas
155 .iter()
156 .map(|d| to_dict_pyo3(py, d))
157 .collect::<PyResult<_>>()?;
158 let py_list = PyList::new(py, delta_dicts)?;
159 (reconstruct, (self.instrument_id, py_list)).into_py_any(py)
160 }
161
162 #[staticmethod]
163 fn _from_dicts(
164 instrument_id: InstrumentId,
165 delta_dicts: Vec<pyo3::Py<pyo3::types::PyDict>>,
166 ) -> PyResult<Self> {
167 use nautilus_core::python::serialization::from_dict_pyo3;
168 let deltas: Vec<OrderBookDelta> = pyo3::Python::attach(|py| {
169 delta_dicts
170 .into_iter()
171 .map(|d| from_dict_pyo3(py, d))
172 .collect::<PyResult<_>>()
173 })?;
174 Self::new_checked(instrument_id, deltas).map_err(to_pyvalue_err)
175 }
176}