1use std::{collections::HashMap, ffi::c_char, sync::Arc};
17
18use databento::dbn;
19use nautilus_core::UnixNanos;
20use nautilus_model::{
21 data::{HasTsInit, custom::CustomDataTrait},
22 enums::OrderSide,
23 identifiers::InstrumentId,
24 types::{Price, Quantity},
25};
26use serde::{Deserialize, Serialize};
27use ustr::Ustr;
28
29use super::enums::{DatabentoStatisticType, DatabentoStatisticUpdateAction};
30
31#[derive(Debug, Clone)]
33pub struct SubscriptionAckEvent {
34 pub schema: String,
36 pub message: String,
38 pub ts_received: UnixNanos,
40}
41
42pub type PublisherId = u16;
44
45pub type Dataset = Ustr;
47
48#[cfg_attr(
50 feature = "python",
51 pyo3::pyclass(
52 module = "nautilus_trader.core.nautilus_pyo3.databento",
53 from_py_object
54 )
55)]
56#[cfg_attr(
57 feature = "python",
58 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.databento")
59)]
60#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
61pub struct DatabentoPublisher {
62 pub publisher_id: PublisherId,
64 pub dataset: dbn::Dataset,
66 pub venue: dbn::Venue,
68 pub description: String,
70}
71
72#[cfg_attr(
77 feature = "python",
78 pyo3::pyclass(
79 module = "nautilus_trader.core.nautilus_pyo3.databento",
80 from_py_object
81 )
82)]
83#[cfg_attr(
84 feature = "python",
85 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.databento")
86)]
87#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
88pub struct DatabentoImbalance {
89 pub instrument_id: InstrumentId,
91 pub ref_price: Price,
93 pub cont_book_clr_price: Price,
95 pub auct_interest_clr_price: Price,
97 pub paired_qty: Quantity,
99 pub total_imbalance_qty: Quantity,
101 pub side: OrderSide,
103 pub significant_imbalance: c_char,
105 pub ts_event: UnixNanos,
107 pub ts_recv: UnixNanos,
109 pub ts_init: UnixNanos,
111}
112
113impl DatabentoImbalance {
114 #[must_use]
116 pub fn get_metadata(
117 instrument_id: &InstrumentId,
118 price_precision: u8,
119 size_precision: u8,
120 ) -> HashMap<String, String> {
121 let mut metadata = HashMap::new();
122 metadata.insert("instrument_id".to_string(), instrument_id.to_string());
123 metadata.insert("price_precision".to_string(), price_precision.to_string());
124 metadata.insert("size_precision".to_string(), size_precision.to_string());
125 metadata
126 }
127
128 #[expect(clippy::too_many_arguments)]
130 #[must_use]
131 pub const fn new(
132 instrument_id: InstrumentId,
133 ref_price: Price,
134 cont_book_clr_price: Price,
135 auct_interest_clr_price: Price,
136 paired_qty: Quantity,
137 total_imbalance_qty: Quantity,
138 side: OrderSide,
139 significant_imbalance: c_char,
140 ts_event: UnixNanos,
141 ts_recv: UnixNanos,
142 ts_init: UnixNanos,
143 ) -> Self {
144 Self {
145 instrument_id,
146 ref_price,
147 cont_book_clr_price,
148 auct_interest_clr_price,
149 paired_qty,
150 total_imbalance_qty,
151 side,
152 significant_imbalance,
153 ts_event,
154 ts_recv,
155 ts_init,
156 }
157 }
158}
159
160impl HasTsInit for DatabentoImbalance {
161 fn ts_init(&self) -> UnixNanos {
162 self.ts_init
163 }
164}
165
166impl CustomDataTrait for DatabentoImbalance {
167 fn type_name(&self) -> &'static str {
168 "DatabentoImbalance"
169 }
170
171 fn as_any(&self) -> &dyn std::any::Any {
172 self
173 }
174
175 fn ts_event(&self) -> UnixNanos {
176 self.ts_event
177 }
178
179 fn to_json(&self) -> anyhow::Result<String> {
180 Ok(serde_json::to_string(self)?)
181 }
182
183 fn clone_arc(&self) -> Arc<dyn CustomDataTrait> {
184 Arc::new(self.clone())
185 }
186
187 fn eq_arc(&self, other: &dyn CustomDataTrait) -> bool {
188 if let Some(o) = other.as_any().downcast_ref::<Self>() {
189 self == o
190 } else {
191 false
192 }
193 }
194
195 #[cfg(feature = "python")]
196 fn to_pyobject(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
197 nautilus_model::data::custom::clone_pyclass_to_pyobject(self, py)
198 }
199
200 fn type_name_static() -> &'static str {
201 "DatabentoImbalance"
202 }
203
204 fn from_json(value: serde_json::Value) -> anyhow::Result<Arc<dyn CustomDataTrait>> {
205 let parsed: Self = serde_json::from_value(value)?;
206 Ok(Arc::new(parsed))
207 }
208}
209
210#[cfg_attr(
215 feature = "python",
216 pyo3::pyclass(
217 module = "nautilus_trader.core.nautilus_pyo3.databento",
218 from_py_object
219 )
220)]
221#[cfg_attr(
222 feature = "python",
223 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.databento")
224)]
225#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
226pub struct DatabentoStatistics {
227 pub instrument_id: InstrumentId,
229 pub stat_type: DatabentoStatisticType,
231 pub update_action: DatabentoStatisticUpdateAction,
233 pub price: Option<Price>,
235 pub quantity: Option<Quantity>,
237 pub channel_id: u16,
239 pub stat_flags: u8,
241 pub sequence: u32,
243 pub ts_ref: UnixNanos,
245 pub ts_in_delta: i32,
247 pub ts_event: UnixNanos,
249 pub ts_recv: UnixNanos,
251 pub ts_init: UnixNanos,
253}
254
255impl DatabentoStatistics {
256 #[must_use]
258 pub fn get_metadata(
259 instrument_id: &InstrumentId,
260 price_precision: u8,
261 size_precision: u8,
262 ) -> HashMap<String, String> {
263 let mut metadata = HashMap::new();
264 metadata.insert("instrument_id".to_string(), instrument_id.to_string());
265 metadata.insert("price_precision".to_string(), price_precision.to_string());
266 metadata.insert("size_precision".to_string(), size_precision.to_string());
267 metadata
268 }
269
270 #[expect(clippy::too_many_arguments)]
272 #[must_use]
273 pub const fn new(
274 instrument_id: InstrumentId,
275 stat_type: DatabentoStatisticType,
276 update_action: DatabentoStatisticUpdateAction,
277 price: Option<Price>,
278 quantity: Option<Quantity>,
279 channel_id: u16,
280 stat_flags: u8,
281 sequence: u32,
282 ts_ref: UnixNanos,
283 ts_in_delta: i32,
284 ts_event: UnixNanos,
285 ts_recv: UnixNanos,
286 ts_init: UnixNanos,
287 ) -> Self {
288 Self {
289 instrument_id,
290 stat_type,
291 update_action,
292 price,
293 quantity,
294 channel_id,
295 stat_flags,
296 sequence,
297 ts_ref,
298 ts_in_delta,
299 ts_event,
300 ts_recv,
301 ts_init,
302 }
303 }
304}
305
306impl HasTsInit for DatabentoStatistics {
307 fn ts_init(&self) -> UnixNanos {
308 self.ts_init
309 }
310}
311
312impl CustomDataTrait for DatabentoStatistics {
313 fn type_name(&self) -> &'static str {
314 "DatabentoStatistics"
315 }
316
317 fn as_any(&self) -> &dyn std::any::Any {
318 self
319 }
320
321 fn ts_event(&self) -> UnixNanos {
322 self.ts_event
323 }
324
325 fn to_json(&self) -> anyhow::Result<String> {
326 Ok(serde_json::to_string(self)?)
327 }
328
329 fn clone_arc(&self) -> Arc<dyn CustomDataTrait> {
330 Arc::new(self.clone())
331 }
332
333 fn eq_arc(&self, other: &dyn CustomDataTrait) -> bool {
334 if let Some(o) = other.as_any().downcast_ref::<Self>() {
335 self == o
336 } else {
337 false
338 }
339 }
340
341 #[cfg(feature = "python")]
342 fn to_pyobject(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
343 nautilus_model::data::custom::clone_pyclass_to_pyobject(self, py)
344 }
345
346 fn type_name_static() -> &'static str {
347 "DatabentoStatistics"
348 }
349
350 fn from_json(value: serde_json::Value) -> anyhow::Result<Arc<dyn CustomDataTrait>> {
351 let parsed: Self = serde_json::from_value(value)?;
352 Ok(Arc::new(parsed))
353 }
354}