nautilus_serialization/arrow/
instrument_status.rs1use std::collections::HashMap;
17
18use arrow::record_batch::RecordBatch;
19use nautilus_model::data::{Data, InstrumentStatus};
20
21use super::{
22 DecodeDataFromRecordBatch, DecodeTypedFromRecordBatch, EncodingError,
23 json::{JsonFieldSpec, impl_json_arrow},
24};
25
26const INSTRUMENT_STATUS_FIELDS: &[JsonFieldSpec] = &[
27 JsonFieldSpec::utf8("instrument_id", false),
28 JsonFieldSpec::utf8("action", false),
29 JsonFieldSpec::u64("ts_event", false),
30 JsonFieldSpec::u64("ts_init", false),
31 JsonFieldSpec::utf8("reason", true),
32 JsonFieldSpec::utf8("trading_event", true),
33 JsonFieldSpec::boolean("is_trading", true),
34 JsonFieldSpec::boolean("is_quoting", true),
35 JsonFieldSpec::boolean("is_short_sell_restricted", true),
36];
37
38impl_json_arrow!(instrument InstrumentStatus, "InstrumentStatus", INSTRUMENT_STATUS_FIELDS);
39
40impl DecodeDataFromRecordBatch for InstrumentStatus {
41 fn decode_data_batch(
42 metadata: &HashMap<String, String>,
43 record_batch: RecordBatch,
44 ) -> Result<Vec<Data>, EncodingError> {
45 let items: Vec<Self> = Self::decode_typed_batch(metadata, record_batch)?;
46 Ok(items.into_iter().map(Data::from).collect())
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use nautilus_model::{enums::MarketStatusAction, identifiers::InstrumentId};
53 use rstest::rstest;
54 use ustr::Ustr;
55
56 use super::*;
57 use crate::arrow::{EncodeToRecordBatch, KEY_INSTRUMENT_ID};
58
59 #[rstest]
60 fn test_encode_decode_round_trip() {
61 let instrument_id = InstrumentId::from("AAPL.XNAS");
62 let metadata = HashMap::from([(KEY_INSTRUMENT_ID.to_string(), instrument_id.to_string())]);
63
64 let status1 = InstrumentStatus::new(
65 instrument_id,
66 MarketStatusAction::Trading,
67 1_000_000_000.into(),
68 1_000_000_001.into(),
69 Some(Ustr::from("Normal trading")),
70 Some(Ustr::from("MARKET_OPEN")),
71 Some(true),
72 Some(true),
73 Some(false),
74 );
75
76 let status2 = InstrumentStatus::new(
77 instrument_id,
78 MarketStatusAction::Halt,
79 2_000_000_000.into(),
80 2_000_000_001.into(),
81 None,
82 None,
83 None,
84 None,
85 None,
86 );
87
88 let original = vec![status1, status2];
89 let record_batch = InstrumentStatus::encode_batch(&metadata, &original).unwrap();
90 let decoded: Vec<Data> =
91 InstrumentStatus::decode_data_batch(&metadata, record_batch).unwrap();
92
93 assert_eq!(decoded.len(), original.len());
94 for (orig, dec) in original.iter().zip(decoded.iter()) {
95 match dec {
96 Data::InstrumentStatus(s) => assert_eq!(s, orig),
97 other => panic!("expected Data::InstrumentStatus, was {other:?}"),
98 }
99 }
100 }
101}