Skip to main content

nautilus_serialization/arrow/
instrument_status.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use 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}