nautilus_model/data/
status.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 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
16//! An `InstrumentStatus` data type representing a change in an instrument market status.
17
18use std::{collections::HashMap, fmt::Display, hash::Hash};
19
20use derive_builder::Builder;
21use nautilus_core::{UnixNanos, serialization::Serializable};
22use serde::{Deserialize, Serialize};
23use ustr::Ustr;
24
25use super::GetTsInit;
26use crate::{enums::MarketStatusAction, identifiers::InstrumentId};
27
28/// Represents an event that indicates a change in an instrument market status.
29#[repr(C)]
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Builder)]
31#[serde(tag = "type")]
32#[cfg_attr(
33    feature = "python",
34    pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.model")
35)]
36pub struct InstrumentStatus {
37    /// The instrument ID for the status change.
38    pub instrument_id: InstrumentId,
39    /// The instrument market status action.
40    pub action: MarketStatusAction,
41    /// UNIX timestamp (nanoseconds) when the status event occurred.
42    pub ts_event: UnixNanos,
43    /// UNIX timestamp (nanoseconds) when the struct was initialized.
44    pub ts_init: UnixNanos,
45    /// Additional details about the cause of the status change.
46    pub reason: Option<Ustr>,
47    /// Further information about the status change (if provided).
48    pub trading_event: Option<Ustr>,
49    /// The state of trading in the instrument.
50    pub is_trading: Option<bool>,
51    /// The state of quoting in the instrument.
52    pub is_quoting: Option<bool>,
53    /// The state of short sell restrictions for the instrument (if applicable).
54    pub is_short_sell_restricted: Option<bool>,
55}
56
57impl InstrumentStatus {
58    /// Creates a new [`InstrumentStatus`] instance.
59    #[allow(clippy::too_many_arguments)]
60    pub fn new(
61        instrument_id: InstrumentId,
62        action: MarketStatusAction,
63        ts_event: UnixNanos,
64        ts_init: UnixNanos,
65        reason: Option<Ustr>,
66        trading_event: Option<Ustr>,
67        is_trading: Option<bool>,
68        is_quoting: Option<bool>,
69        is_short_sell_restricted: Option<bool>,
70    ) -> Self {
71        Self {
72            instrument_id,
73            action,
74            ts_event,
75            ts_init,
76            reason,
77            trading_event,
78            is_trading,
79            is_quoting,
80            is_short_sell_restricted,
81        }
82    }
83
84    /// Returns the metadata for the type, for use with serialization formats.
85    #[must_use]
86    pub fn get_metadata(instrument_id: &InstrumentId) -> HashMap<String, String> {
87        let mut metadata = HashMap::new();
88        metadata.insert("instrument_id".to_string(), instrument_id.to_string());
89        metadata
90    }
91}
92
93// TODO: Revisit this
94impl Display for InstrumentStatus {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(
97            f,
98            "{},{},{},{}",
99            self.instrument_id, self.action, self.ts_event, self.ts_init,
100        )
101    }
102}
103
104impl Serializable for InstrumentStatus {}
105
106impl GetTsInit for InstrumentStatus {
107    fn ts_init(&self) -> UnixNanos {
108        self.ts_init
109    }
110}
111
112////////////////////////////////////////////////////////////////////////////////
113// Tests
114////////////////////////////////////////////////////////////////////////////////
115#[cfg(test)]
116mod tests {
117    use nautilus_core::serialization::Serializable;
118    use rstest::rstest;
119
120    use super::*;
121    use crate::data::stubs::stub_instrument_status;
122
123    #[rstest]
124    fn test_to_string(stub_instrument_status: InstrumentStatus) {
125        assert_eq!(stub_instrument_status.to_string(), "MSFT.XNAS,TRADING,1,2");
126    }
127
128    #[rstest]
129    fn test_json_serialization(stub_instrument_status: InstrumentStatus) {
130        let serialized = stub_instrument_status.as_json_bytes().unwrap();
131        let deserialized = InstrumentStatus::from_json_bytes(serialized.as_ref()).unwrap();
132        assert_eq!(deserialized, stub_instrument_status);
133    }
134
135    #[rstest]
136    fn test_msgpack_serialization(stub_instrument_status: InstrumentStatus) {
137        let serialized = stub_instrument_status.as_msgpack_bytes().unwrap();
138        let deserialized = InstrumentStatus::from_msgpack_bytes(serialized.as_ref()).unwrap();
139        assert_eq!(deserialized, stub_instrument_status);
140    }
141}