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(module = "nautilus_trader.adapters.databento", from_py_object)
52)]
53#[cfg_attr(
54 feature = "python",
55 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.databento")
56)]
57#[derive(Clone, Debug, PartialEq, Eq, Hash, Deserialize)]
58pub struct DatabentoPublisher {
59 pub publisher_id: PublisherId,
61 pub dataset: dbn::Dataset,
63 pub venue: dbn::Venue,
65 pub description: String,
67}
68
69#[cfg_attr(
74 feature = "python",
75 pyo3::pyclass(module = "nautilus_trader.adapters.databento", from_py_object)
76)]
77#[cfg_attr(
78 feature = "python",
79 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.databento")
80)]
81#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
82pub struct DatabentoImbalance {
83 pub instrument_id: InstrumentId,
85 pub ref_price: Price,
87 pub cont_book_clr_price: Price,
89 pub auct_interest_clr_price: Price,
91 pub paired_qty: Quantity,
93 pub total_imbalance_qty: Quantity,
95 #[serde(with = "nautilus_model::enums::serde_option_order_side")]
97 pub side: Option<OrderSide>,
98 pub significant_imbalance: c_char,
100 pub ts_event: UnixNanos,
102 pub ts_recv: UnixNanos,
104 pub ts_init: UnixNanos,
106}
107
108impl DatabentoImbalance {
109 #[must_use]
111 pub fn get_metadata(
112 instrument_id: &InstrumentId,
113 price_precision: u8,
114 size_precision: u8,
115 ) -> HashMap<String, String> {
116 let mut metadata = HashMap::new();
117 metadata.insert("instrument_id".to_string(), instrument_id.to_string());
118 metadata.insert("price_precision".to_string(), price_precision.to_string());
119 metadata.insert("size_precision".to_string(), size_precision.to_string());
120 metadata
121 }
122
123 #[expect(clippy::too_many_arguments)]
125 #[must_use]
126 pub const fn new(
127 instrument_id: InstrumentId,
128 ref_price: Price,
129 cont_book_clr_price: Price,
130 auct_interest_clr_price: Price,
131 paired_qty: Quantity,
132 total_imbalance_qty: Quantity,
133 side: Option<OrderSide>,
134 significant_imbalance: c_char,
135 ts_event: UnixNanos,
136 ts_recv: UnixNanos,
137 ts_init: UnixNanos,
138 ) -> Self {
139 Self {
140 instrument_id,
141 ref_price,
142 cont_book_clr_price,
143 auct_interest_clr_price,
144 paired_qty,
145 total_imbalance_qty,
146 side,
147 significant_imbalance,
148 ts_event,
149 ts_recv,
150 ts_init,
151 }
152 }
153}
154
155impl HasTsInit for DatabentoImbalance {
156 fn ts_init(&self) -> UnixNanos {
157 self.ts_init
158 }
159}
160
161impl CustomDataTrait for DatabentoImbalance {
162 fn type_name(&self) -> &'static str {
163 "DatabentoImbalance"
164 }
165
166 fn as_any(&self) -> &dyn std::any::Any {
167 self
168 }
169
170 fn ts_event(&self) -> UnixNanos {
171 self.ts_event
172 }
173
174 fn to_json(&self) -> anyhow::Result<String> {
175 Ok(serde_json::to_string(self)?)
176 }
177
178 fn clone_arc(&self) -> Arc<dyn CustomDataTrait> {
179 Arc::new(self.clone())
180 }
181
182 fn eq_arc(&self, other: &dyn CustomDataTrait) -> bool {
183 if let Some(o) = other.as_any().downcast_ref::<Self>() {
184 self == o
185 } else {
186 false
187 }
188 }
189
190 #[cfg(feature = "python")]
191 fn to_pyobject(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
192 nautilus_model::data::custom::clone_pyclass_to_pyobject(self, py)
193 }
194
195 fn type_name_static() -> &'static str {
196 "DatabentoImbalance"
197 }
198
199 fn from_json(value: serde_json::Value) -> anyhow::Result<Arc<dyn CustomDataTrait>> {
200 let parsed: Self = serde_json::from_value(value)?;
201 Ok(Arc::new(parsed))
202 }
203}
204
205#[cfg_attr(
210 feature = "python",
211 pyo3::pyclass(module = "nautilus_trader.adapters.databento", from_py_object)
212)]
213#[cfg_attr(
214 feature = "python",
215 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.databento")
216)]
217#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
218pub struct DatabentoStatistics {
219 pub instrument_id: InstrumentId,
221 pub stat_type: DatabentoStatisticType,
223 pub update_action: DatabentoStatisticUpdateAction,
225 pub price: Option<Price>,
227 pub quantity: Option<Quantity>,
229 pub channel_id: u16,
231 pub stat_flags: u8,
233 pub sequence: u32,
235 pub ts_ref: UnixNanos,
237 pub ts_in_delta: i32,
239 pub ts_event: UnixNanos,
241 pub ts_recv: UnixNanos,
243 pub ts_init: UnixNanos,
245}
246
247impl DatabentoStatistics {
248 #[must_use]
250 pub fn get_metadata(
251 instrument_id: &InstrumentId,
252 price_precision: u8,
253 size_precision: u8,
254 ) -> HashMap<String, String> {
255 let mut metadata = HashMap::new();
256 metadata.insert("instrument_id".to_string(), instrument_id.to_string());
257 metadata.insert("price_precision".to_string(), price_precision.to_string());
258 metadata.insert("size_precision".to_string(), size_precision.to_string());
259 metadata
260 }
261
262 #[expect(clippy::too_many_arguments)]
264 #[must_use]
265 pub const fn new(
266 instrument_id: InstrumentId,
267 stat_type: DatabentoStatisticType,
268 update_action: DatabentoStatisticUpdateAction,
269 price: Option<Price>,
270 quantity: Option<Quantity>,
271 channel_id: u16,
272 stat_flags: u8,
273 sequence: u32,
274 ts_ref: UnixNanos,
275 ts_in_delta: i32,
276 ts_event: UnixNanos,
277 ts_recv: UnixNanos,
278 ts_init: UnixNanos,
279 ) -> Self {
280 Self {
281 instrument_id,
282 stat_type,
283 update_action,
284 price,
285 quantity,
286 channel_id,
287 stat_flags,
288 sequence,
289 ts_ref,
290 ts_in_delta,
291 ts_event,
292 ts_recv,
293 ts_init,
294 }
295 }
296}
297
298impl HasTsInit for DatabentoStatistics {
299 fn ts_init(&self) -> UnixNanos {
300 self.ts_init
301 }
302}
303
304impl CustomDataTrait for DatabentoStatistics {
305 fn type_name(&self) -> &'static str {
306 "DatabentoStatistics"
307 }
308
309 fn as_any(&self) -> &dyn std::any::Any {
310 self
311 }
312
313 fn ts_event(&self) -> UnixNanos {
314 self.ts_event
315 }
316
317 fn to_json(&self) -> anyhow::Result<String> {
318 Ok(serde_json::to_string(self)?)
319 }
320
321 fn clone_arc(&self) -> Arc<dyn CustomDataTrait> {
322 Arc::new(self.clone())
323 }
324
325 fn eq_arc(&self, other: &dyn CustomDataTrait) -> bool {
326 if let Some(o) = other.as_any().downcast_ref::<Self>() {
327 self == o
328 } else {
329 false
330 }
331 }
332
333 #[cfg(feature = "python")]
334 fn to_pyobject(&self, py: pyo3::Python<'_>) -> pyo3::PyResult<pyo3::Py<pyo3::PyAny>> {
335 nautilus_model::data::custom::clone_pyclass_to_pyobject(self, py)
336 }
337
338 fn type_name_static() -> &'static str {
339 "DatabentoStatistics"
340 }
341
342 fn from_json(value: serde_json::Value) -> anyhow::Result<Arc<dyn CustomDataTrait>> {
343 let parsed: Self = serde_json::from_value(value)?;
344 Ok(Arc::new(parsed))
345 }
346}