nautilus_databento/python/
types.rs1use std::{
17 collections::hash_map::DefaultHasher,
18 hash::{Hash, Hasher},
19};
20
21use nautilus_core::python::{
22 IntoPyObjectNautilusExt,
23 serialization::{from_dict_pyo3, to_dict_pyo3},
24};
25use nautilus_model::{
26 enums::OrderSide,
27 identifiers::InstrumentId,
28 types::{Price, Quantity},
29};
30use pyo3::{basic::CompareOp, prelude::*, types::PyDict};
31
32use crate::{
33 enums::{DatabentoStatisticType, DatabentoStatisticUpdateAction},
34 types::{DatabentoImbalance, DatabentoStatistics},
35};
36
37#[pymethods]
38#[pyo3_stub_gen::derive::gen_stub_pymethods]
39impl DatabentoImbalance {
40 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
41 match op {
42 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
43 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
44 _ => py.NotImplemented(),
45 }
46 }
47
48 fn __hash__(&self) -> isize {
49 let mut hasher = DefaultHasher::new();
50 self.hash(&mut hasher);
51 hasher.finish() as isize
52 }
53
54 fn __repr__(&self) -> String {
55 let side = self.side.as_ref().map_or("NO_ORDER_SIDE", AsRef::as_ref);
56 format!(
57 "{}(instrument_id={}, ref_price={}, cont_book_clr_price={}, auct_interest_clr_price={}, paired_qty={}, total_imbalance_qty={}, side={}, significant_imbalance={}, ts_event={}, ts_recv={}, ts_init={})",
58 stringify!(DatabentoImbalance),
59 self.instrument_id,
60 self.ref_price,
61 self.cont_book_clr_price,
62 self.auct_interest_clr_price,
63 self.paired_qty,
64 self.total_imbalance_qty,
65 side,
66 self.significant_imbalance,
67 self.ts_event,
68 self.ts_recv,
69 self.ts_init,
70 )
71 }
72
73 fn __str__(&self) -> String {
74 self.__repr__()
75 }
76
77 #[getter]
78 #[pyo3(name = "instrument_id")]
79 const fn py_instrument_id(&self) -> InstrumentId {
80 self.instrument_id
81 }
82
83 #[getter]
84 #[pyo3(name = "ref_price")]
85 const fn py_ref_price(&self) -> Price {
86 self.ref_price
87 }
88
89 #[getter]
90 #[pyo3(name = "cont_book_clr_price")]
91 const fn py_cont_book_clr_price(&self) -> Price {
92 self.cont_book_clr_price
93 }
94
95 #[getter]
96 #[pyo3(name = "auct_interest_clr_price")]
97 const fn py_auct_interest_clr_price(&self) -> Price {
98 self.auct_interest_clr_price
99 }
100
101 #[getter]
102 #[pyo3(name = "paired_qty")]
103 const fn py_paired_qty(&self) -> Quantity {
104 self.paired_qty
105 }
106
107 #[getter]
108 #[pyo3(name = "total_imbalance_qty")]
109 const fn py_total_imbalance_qty(&self) -> Quantity {
110 self.total_imbalance_qty
111 }
112
113 #[getter]
114 #[pyo3(name = "side")]
115 const fn py_side(&self) -> Option<OrderSide> {
116 self.side
117 }
118
119 #[getter]
120 #[pyo3(name = "significant_imbalance")]
121 fn py_significant_imbalance(&self) -> String {
122 self.significant_imbalance.to_string()
123 }
124
125 #[getter]
126 #[pyo3(name = "ts_event")]
127 const fn py_ts_event(&self) -> u64 {
128 self.ts_event.as_u64()
129 }
130
131 #[getter]
132 #[pyo3(name = "ts_recv")]
133 const fn py_ts_recv(&self) -> u64 {
134 self.ts_recv.as_u64()
135 }
136
137 #[getter]
138 #[pyo3(name = "ts_init")]
139 const fn py_ts_init(&self) -> u64 {
140 self.ts_init.as_u64()
141 }
142
143 #[staticmethod]
144 #[pyo3(name = "from_dict")]
145 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
146 from_dict_pyo3(py, values)
147 }
148
149 #[pyo3(name = "to_dict")]
151 pub fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
152 to_dict_pyo3(py, self)
153 }
154}
155
156#[pymethods]
157#[pyo3_stub_gen::derive::gen_stub_pymethods]
158impl DatabentoStatistics {
159 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
160 match op {
161 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
162 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
163 _ => py.NotImplemented(),
164 }
165 }
166
167 fn __hash__(&self) -> isize {
168 let mut hasher = DefaultHasher::new();
169 self.hash(&mut hasher);
170 hasher.finish() as isize
171 }
172
173 fn __repr__(&self) -> String {
174 format!(
175 "{}(instrument_id={}, stat_type={}, update_action={}, price={}, quantity={}, channel_id={}, stat_flags={}, sequence={}, ts_ref={}, ts_in_delta={}, ts_event={}, ts_recv={}, ts_init={})",
176 stringify!(DatabentoStatistics),
177 self.instrument_id,
178 self.stat_type,
179 self.update_action,
180 self.price
181 .map_or_else(|| "None".to_string(), |p| format!("{p}")),
182 self.quantity
183 .map_or_else(|| "None".to_string(), |q| format!("{q}")),
184 self.channel_id,
185 self.stat_flags,
186 self.sequence,
187 self.ts_ref,
188 self.ts_in_delta,
189 self.ts_event,
190 self.ts_recv,
191 self.ts_init,
192 )
193 }
194
195 fn __str__(&self) -> String {
196 self.__repr__()
197 }
198
199 #[getter]
200 #[pyo3(name = "instrument_id")]
201 const fn py_instrument_id(&self) -> InstrumentId {
202 self.instrument_id
203 }
204
205 #[getter]
206 #[pyo3(name = "stat_type")]
207 const fn py_stat_type(&self) -> DatabentoStatisticType {
208 self.stat_type
209 }
210
211 #[getter]
212 #[pyo3(name = "update_action")]
213 const fn py_update_action(&self) -> DatabentoStatisticUpdateAction {
214 self.update_action
215 }
216
217 #[getter]
218 #[pyo3(name = "price")]
219 const fn py_price(&self) -> Option<Price> {
220 self.price
221 }
222
223 #[getter]
224 #[pyo3(name = "quantity")]
225 const fn py_quantity(&self) -> Option<Quantity> {
226 self.quantity
227 }
228
229 #[getter]
230 #[pyo3(name = "channel_id")]
231 const fn py_channel_id(&self) -> u16 {
232 self.channel_id
233 }
234
235 #[getter]
236 #[pyo3(name = "stat_flags")]
237 const fn py_stat_flags(&self) -> u8 {
238 self.stat_flags
239 }
240
241 #[getter]
242 #[pyo3(name = "sequence")]
243 const fn py_sequence(&self) -> u32 {
244 self.sequence
245 }
246
247 #[getter]
248 #[pyo3(name = "ts_ref")]
249 const fn py_ts_ref(&self) -> u64 {
250 self.ts_ref.as_u64()
251 }
252
253 #[getter]
254 #[pyo3(name = "ts_in_delta")]
255 const fn py_ts_in_delta(&self) -> i32 {
256 self.ts_in_delta
257 }
258
259 #[getter]
260 #[pyo3(name = "ts_event")]
261 const fn py_ts_event(&self) -> u64 {
262 self.ts_event.as_u64()
263 }
264
265 #[pyo3(name = "ts_recv")]
266 #[getter]
267 const fn py_ts_recv(&self) -> u64 {
268 self.ts_recv.as_u64()
269 }
270
271 #[pyo3(name = "ts_init")]
272 #[getter]
273 const fn py_ts_init(&self) -> u64 {
274 self.ts_init.as_u64()
275 }
276
277 #[staticmethod]
278 #[pyo3(name = "from_dict")]
279 fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
280 from_dict_pyo3(py, values)
281 }
282
283 #[pyo3(name = "to_dict")]
285 pub fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyDict>> {
286 to_dict_pyo3(py, self)
287 }
288}
289
290#[cfg_attr(
292 feature = "python",
293 pyo3::pyclass(module = "nautilus_trader.adapters.databento", from_py_object)
294)]
295#[cfg_attr(
296 feature = "python",
297 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.databento")
298)]
299#[derive(Debug, Clone)]
300pub struct DatabentoSubscriptionAck {
301 #[pyo3(get)]
302 pub schema: String,
303 #[pyo3(get)]
304 pub message: String,
305 #[pyo3(get)]
306 pub ts_received: u64,
307}
308
309impl From<crate::types::SubscriptionAckEvent> for DatabentoSubscriptionAck {
310 fn from(event: crate::types::SubscriptionAckEvent) -> Self {
311 Self {
312 schema: event.schema,
313 message: event.message,
314 ts_received: event.ts_received.as_u64(),
315 }
316 }
317}