dbn/v1/methods.rs
1use std::os::raw::c_char;
2
3use crate::{
4 pretty::px_to_f64,
5 record::{c_chars_to_str, str_to_c_chars, ts_to_dt},
6 rtype, Error, InstrumentClass, MatchAlgorithm, RecordHeader, Result, StatType,
7 StatUpdateAction,
8};
9
10use super::*;
11
12impl ErrorMsg {
13 /// Creates a new `ErrorMsg`. `msg` will be truncated if it's too long.
14 pub fn new(ts_event: u64, msg: &str) -> Self {
15 let mut error = Self {
16 hd: RecordHeader::new::<Self>(rtype::ERROR, 0, 0, ts_event),
17 ..Default::default()
18 };
19 // leave at least one null byte
20 for (i, byte) in msg.as_bytes().iter().take(error.err.len() - 1).enumerate() {
21 error.err[i] = *byte as c_char;
22 }
23 error
24 }
25
26 /// Parses the error message into a `&str`.
27 ///
28 /// # Errors
29 /// This function returns an error if `err` contains invalid UTF-8.
30 pub fn err(&self) -> crate::Result<&str> {
31 c_chars_to_str(&self.err)
32 }
33}
34
35impl InstrumentDefMsg {
36 /// Parses the capture-server-received timestamp into a datetime.
37 /// Returns `None` if `ts_recv` contains the sentinel for a null timestamp.
38 pub fn ts_recv(&self) -> Option<time::OffsetDateTime> {
39 ts_to_dt(self.ts_recv)
40 }
41
42 /// Converts the minimum constant tick to a floating point.
43 ///
44 /// `UNDEF_PRICE` will be converted to NaN.
45 ///
46 /// <div class="warning">
47 /// This may introduce floating-point error.
48 /// </div>
49 pub fn min_price_increment_f64(&self) -> f64 {
50 px_to_f64(self.min_price_increment)
51 }
52
53 /// Converts the display factor to a floating point.
54 ///
55 /// `UNDEF_PRICE` will be converted to NaN.
56 ///
57 /// <div class="warning">
58 /// This may introduce floating-point error.
59 /// </div>
60 pub fn display_factor_f64(&self) -> f64 {
61 px_to_f64(self.display_factor)
62 }
63
64 /// Parses the last eligible trade time into a datetime.
65 /// Returns `None` if `expiration` contains the sentinel for a null timestamp.
66 pub fn expiration(&self) -> Option<time::OffsetDateTime> {
67 ts_to_dt(self.expiration)
68 }
69
70 /// Parses the time of instrument activation into a datetime.
71 /// Returns `None` if `activation` contains the sentinel for a null timestamp.
72 pub fn activation(&self) -> Option<time::OffsetDateTime> {
73 ts_to_dt(self.activation)
74 }
75
76 /// Converts the high limit price to a floating point.
77 ///
78 /// `UNDEF_PRICE` will be converted to NaN.
79 ///
80 /// <div class="warning">
81 /// This may introduce floating-point error.
82 /// </div>
83 pub fn high_limit_price_f64(&self) -> f64 {
84 px_to_f64(self.high_limit_price)
85 }
86
87 /// Converts the low limit price to a floating point.
88 ///
89 /// `UNDEF_PRICE` will be converted to NaN.
90 ///
91 /// <div class="warning">
92 /// This may introduce floating-point error.
93 /// </div>
94 pub fn low_limit_price_f64(&self) -> f64 {
95 px_to_f64(self.low_limit_price)
96 }
97
98 /// Converts the differential value for price banding to a floating point.
99 ///
100 /// `UNDEF_PRICE` will be converted to NaN.
101 ///
102 /// <div class="warning">
103 /// This may introduce floating-point error.
104 /// </div>
105 pub fn max_price_variation_f64(&self) -> f64 {
106 px_to_f64(self.max_price_variation)
107 }
108
109 /// Converts the trading session settlement price to a floating point.
110 ///
111 /// `UNDEF_PRICE` will be converted to NaN.
112 ///
113 /// <div class="warning">
114 /// This may introduce floating-point error.
115 /// </div>
116 pub fn trading_reference_price_f64(&self) -> f64 {
117 px_to_f64(self.trading_reference_price)
118 }
119
120 /// Converts the contract size for each instrument to a floating point.
121 ///
122 /// `UNDEF_PRICE` will be converted to NaN.
123 ///
124 /// <div class="warning">
125 /// This may introduce floating-point error.
126 /// </div>
127 pub fn unit_of_measure_qty_f64(&self) -> f64 {
128 px_to_f64(self.unit_of_measure_qty)
129 }
130
131 /// Converts the min price increment amount to a floating point.
132 ///
133 /// `UNDEF_PRICE` will be converted to NaN.
134 ///
135 /// <div class="warning">
136 /// This may introduce floating-point error.
137 /// </div>
138 pub fn min_price_increment_amount_f64(&self) -> f64 {
139 px_to_f64(self.min_price_increment_amount)
140 }
141
142 /// Converts the price ratio to a floating point.
143 ///
144 /// `UNDEF_PRICE` will be converted to NaN.
145 ///
146 /// <div class="warning">
147 /// This may introduce floating-point error.
148 /// </div>
149 pub fn price_ratio_f64(&self) -> f64 {
150 px_to_f64(self.price_ratio)
151 }
152
153 /// Parses the currency into a `&str`.
154 ///
155 /// # Errors
156 /// This function returns an error if `currency` contains invalid UTF-8.
157 pub fn currency(&self) -> crate::Result<&str> {
158 c_chars_to_str(&self.currency)
159 }
160
161 /// Parses the currency used for settlement into a `&str`.
162 ///
163 /// # Errors
164 /// This function returns an error if `settl_currency` contains invalid UTF-8.
165 pub fn settl_currency(&self) -> crate::Result<&str> {
166 c_chars_to_str(&self.settl_currency)
167 }
168
169 /// Parses the strategy type of the spread into a `&str`.
170 ///
171 /// # Errors
172 /// This function returns an error if `secsubtype` contains invalid UTF-8.
173 pub fn secsubtype(&self) -> crate::Result<&str> {
174 c_chars_to_str(&self.secsubtype)
175 }
176
177 /// Parses the raw symbol into a `&str`.
178 ///
179 /// # Errors
180 /// This function returns an error if `raw_symbol` contains invalid UTF-8.
181 pub fn raw_symbol(&self) -> crate::Result<&str> {
182 c_chars_to_str(&self.raw_symbol)
183 }
184
185 /// Parses the security group code into a `&str`.
186 ///
187 /// # Errors
188 /// This function returns an error if `group` contains invalid UTF-8.
189 pub fn group(&self) -> crate::Result<&str> {
190 c_chars_to_str(&self.group)
191 }
192
193 /// Parses the exchange into a `&str`.
194 ///
195 /// # Errors
196 /// This function returns an error if `exchange` contains invalid UTF-8.
197 pub fn exchange(&self) -> crate::Result<&str> {
198 c_chars_to_str(&self.exchange)
199 }
200
201 /// Parses the asset into a `&str`.
202 ///
203 /// # Errors
204 /// This function returns an error if `asset` contains invalid UTF-8.
205 pub fn asset(&self) -> crate::Result<&str> {
206 c_chars_to_str(&self.asset)
207 }
208
209 /// Parses the CFI code into a `&str`.
210 ///
211 /// # Errors
212 /// This function returns an error if `cfi` contains invalid UTF-8.
213 pub fn cfi(&self) -> crate::Result<&str> {
214 c_chars_to_str(&self.cfi)
215 }
216
217 /// Parses the security type into a `&str`.
218 ///
219 /// # Errors
220 /// This function returns an error if `security_type` contains invalid UTF-8.
221 pub fn security_type(&self) -> crate::Result<&str> {
222 c_chars_to_str(&self.security_type)
223 }
224
225 /// Parses the unit of measure into a `&str`.
226 ///
227 /// # Errors
228 /// This function returns an error if `unit_of_measure` contains invalid UTF-8.
229 pub fn unit_of_measure(&self) -> crate::Result<&str> {
230 c_chars_to_str(&self.unit_of_measure)
231 }
232
233 /// Parses the underlying into a `&str`.
234 ///
235 /// # Errors
236 /// This function returns an error if `underlying` contains invalid UTF-8.
237 pub fn underlying(&self) -> crate::Result<&str> {
238 c_chars_to_str(&self.underlying)
239 }
240
241 /// Parses the strike price currency into a `&str`.
242 ///
243 /// # Errors
244 /// This function returns an error if `strike_price_currency` contains invalid UTF-8.
245 pub fn strike_price_currency(&self) -> crate::Result<&str> {
246 c_chars_to_str(&self.strike_price_currency)
247 }
248
249 /// Parses the instrument class into an enum.
250 ///
251 /// # Errors
252 /// This function returns an error if the `instrument_class` field does not
253 /// contain a valid [`InstrumentClass`].
254 pub fn instrument_class(&self) -> crate::Result<InstrumentClass> {
255 InstrumentClass::try_from(self.instrument_class as u8).map_err(|_| {
256 Error::conversion::<InstrumentClass>(format!("{:#04X}", self.instrument_class as u8))
257 })
258 }
259
260 /// Converts the strike price to a floating point.
261 ///
262 /// `UNDEF_PRICE` will be converted to NaN.
263 ///
264 /// <div class="warning">
265 /// This may introduce floating-point error.
266 /// </div>
267 pub fn strike_price_f64(&self) -> f64 {
268 px_to_f64(self.strike_price)
269 }
270
271 /// Parses the match algorithm into an enum.
272 ///
273 /// # Errors
274 /// This function returns an error if the `match_algorithm` field does not
275 /// contain a valid [`MatchAlgorithm`].
276 pub fn match_algorithm(&self) -> crate::Result<MatchAlgorithm> {
277 MatchAlgorithm::try_from(self.match_algorithm as u8).map_err(|_| {
278 Error::conversion::<MatchAlgorithm>(format!("{:#04X}", self.match_algorithm as u8))
279 })
280 }
281}
282
283impl StatMsg {
284 /// Parses the capture-server-received timestamp into a datetime.
285 /// Returns `None` if `ts_recv` contains the sentinel for a null timestamp.
286 pub fn ts_recv(&self) -> Option<time::OffsetDateTime> {
287 ts_to_dt(self.ts_recv)
288 }
289
290 /// Parses the reference timestamp of the statistic value into a datetime.
291 /// Returns `None` if `ts_ref` contains the sentinel for a null timestamp.
292 pub fn ts_ref(&self) -> Option<time::OffsetDateTime> {
293 ts_to_dt(self.ts_ref)
294 }
295
296 /// Converts the value for price statistics to a floating point.
297 ///
298 /// `UNDEF_PRICE` will be converted to NaN.
299 ///
300 /// <div class="warning">
301 /// This may introduce floating-point error.
302 /// </div>
303 pub fn price_f64(&self) -> f64 {
304 px_to_f64(self.price)
305 }
306
307 /// Parses the difference between `ts_recv` and the matching-engine-sending timestamp into a duration.
308 pub fn ts_in_delta(&self) -> time::Duration {
309 time::Duration::new(0, self.ts_in_delta)
310 }
311
312 /// Parses the type of statistic value into an enum.
313 ///
314 /// # Errors
315 /// This function returns an error if the `stat_type` field does not
316 /// contain a valid [`StatType`].
317 pub fn stat_type(&self) -> crate::Result<StatType> {
318 StatType::try_from(self.stat_type)
319 .map_err(|_| Error::conversion::<StatType>(format!("{:#04X}", self.stat_type)))
320 }
321
322 /// Parses the update action into an enum.
323 ///
324 /// # Errors
325 /// This function returns an error if the `update_action` field does not
326 /// contain a valid [`StatUpdateAction`].
327 pub fn update_action(&self) -> crate::Result<StatUpdateAction> {
328 StatUpdateAction::try_from(self.update_action).map_err(|_| {
329 Error::conversion::<StatUpdateAction>(format!("{:#04X}", self.update_action))
330 })
331 }
332}
333
334impl SymbolMappingMsg {
335 /// Creates a new `SymbolMappingMsg`.
336 ///
337 /// # Errors
338 /// This function returns an error if `stype_in_symbol` or `stype_out_symbol`
339 /// contain more than maximum number of 21 characters.
340 pub fn new(
341 instrument_id: u32,
342 ts_event: u64,
343
344 stype_in_symbol: &str,
345
346 stype_out_symbol: &str,
347 start_ts: u64,
348 end_ts: u64,
349 ) -> crate::Result<Self> {
350 Ok(Self {
351 // symbol mappings aren't publisher-specific
352 hd: RecordHeader::new::<Self>(rtype::SYMBOL_MAPPING, 0, instrument_id, ts_event),
353 stype_in_symbol: str_to_c_chars(stype_in_symbol)?,
354 stype_out_symbol: str_to_c_chars(stype_out_symbol)?,
355 _dummy: Default::default(),
356 start_ts,
357 end_ts,
358 })
359 }
360
361 /// Parses the input symbol into a `&str`.
362 ///
363 /// # Errors
364 /// This function returns an error if `stype_in_symbol` contains invalid UTF-8.
365 pub fn stype_in_symbol(&self) -> crate::Result<&str> {
366 c_chars_to_str(&self.stype_in_symbol)
367 }
368
369 /// Parses the output symbol into a `&str`.
370 ///
371 /// # Errors
372 /// This function returns an error if `stype_out_symbol` contains invalid UTF-8.
373 pub fn stype_out_symbol(&self) -> crate::Result<&str> {
374 c_chars_to_str(&self.stype_out_symbol)
375 }
376
377 /// Parses the start of the mapping interval into a datetime.
378 /// Returns `None` if `start_ts` contains the sentinel for a null timestamp.
379 pub fn start_ts(&self) -> Option<time::OffsetDateTime> {
380 ts_to_dt(self.start_ts)
381 }
382
383 /// Parses the end of the mapping interval into a datetime.
384 /// Returns `None` if `end_ts` contains the sentinel for a null timestamp.
385 pub fn end_ts(&self) -> Option<time::OffsetDateTime> {
386 ts_to_dt(self.end_ts)
387 }
388}
389
390impl SystemMsg {
391 /// Creates a new `SystemMsg`.
392 ///
393 /// # Errors
394 /// This function returns an error if `msg` is too long.
395 pub fn new(ts_event: u64, msg: &str) -> Result<Self> {
396 Ok(Self {
397 hd: RecordHeader::new::<Self>(rtype::SYSTEM, 0, 0, ts_event),
398 msg: str_to_c_chars(msg)?,
399 })
400 }
401
402 /// Creates a new heartbeat `SystemMsg`.
403 pub fn heartbeat(ts_event: u64) -> Self {
404 Self {
405 hd: RecordHeader::new::<Self>(rtype::SYSTEM, 0, 0, ts_event),
406 msg: str_to_c_chars(crate::SystemMsg::HEARTBEAT).unwrap(),
407 }
408 }
409
410 /// Checks whether the message is a heartbeat from the gateway.
411 pub fn is_heartbeat(&self) -> bool {
412 self.msg()
413 .map(|msg| msg == crate::SystemMsg::HEARTBEAT)
414 .unwrap_or_default()
415 }
416
417 /// Parses the message from the Databento gateway into a `&str`.
418 ///
419 /// # Errors
420 /// This function returns an error if `msg` contains invalid UTF-8.
421 pub fn msg(&self) -> crate::Result<&str> {
422 c_chars_to_str(&self.msg)
423 }
424}