Skip to main content

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}