Skip to main content

nautilus_model/python/reports/
mass_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 indexmap::IndexMap;
17use nautilus_core::{
18    UUID4,
19    python::{IntoPyObjectNautilusExt, serialization::from_dict_pyo3},
20};
21use pyo3::{basic::CompareOp, prelude::*, types::PyDict};
22
23use crate::{
24    identifiers::{AccountId, ClientId, InstrumentId, Venue, VenueOrderId},
25    reports::{
26        fill::FillReport, mass_status::ExecutionMassStatus, order::OrderStatusReport,
27        position::PositionStatusReport,
28    },
29};
30
31#[pymethods]
32#[pyo3_stub_gen::derive::gen_stub_pymethods]
33impl ExecutionMassStatus {
34    /// Represents an execution mass status report for an execution client - including
35    /// status of all orders, trades for those orders and open positions.
36    #[new]
37    #[pyo3(signature = (client_id, account_id, venue, ts_init, report_id=None))]
38    fn py_new(
39        client_id: ClientId,
40        account_id: AccountId,
41        venue: Venue,
42        ts_init: u64,
43        report_id: Option<UUID4>,
44    ) -> Self {
45        Self::new(client_id, account_id, venue, ts_init.into(), report_id)
46    }
47
48    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
49        match op {
50            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
51            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
52            _ => py.NotImplemented(),
53        }
54    }
55
56    fn __repr__(&self) -> String {
57        self.to_string()
58    }
59
60    fn __str__(&self) -> String {
61        self.to_string()
62    }
63
64    #[getter]
65    #[pyo3(name = "client_id")]
66    const fn py_client_id(&self) -> ClientId {
67        self.client_id
68    }
69
70    #[getter]
71    #[pyo3(name = "account_id")]
72    const fn py_account_id(&self) -> AccountId {
73        self.account_id
74    }
75
76    #[getter]
77    #[pyo3(name = "venue")]
78    const fn py_venue(&self) -> Venue {
79        self.venue
80    }
81
82    #[getter]
83    #[pyo3(name = "report_id")]
84    const fn py_report_id(&self) -> UUID4 {
85        self.report_id
86    }
87
88    #[getter]
89    #[pyo3(name = "ts_init")]
90    const fn py_ts_init(&self) -> u64 {
91        self.ts_init.as_u64()
92    }
93
94    /// Get a copy of the order reports map.
95    #[getter]
96    #[pyo3(name = "order_reports")]
97    fn py_order_reports(&self) -> IndexMap<VenueOrderId, OrderStatusReport> {
98        self.order_reports()
99    }
100
101    /// Get a copy of the fill reports map.
102    #[getter]
103    #[pyo3(name = "fill_reports")]
104    fn py_fill_reports(&self) -> IndexMap<VenueOrderId, Vec<FillReport>> {
105        self.fill_reports()
106    }
107
108    /// Get a copy of the position reports map.
109    #[getter]
110    #[pyo3(name = "position_reports")]
111    fn py_position_reports(&self) -> IndexMap<InstrumentId, Vec<PositionStatusReport>> {
112        self.position_reports()
113    }
114
115    /// Add order reports to the mass status.
116    #[pyo3(name = "add_order_reports")]
117    fn py_add_order_reports(&mut self, reports: Vec<OrderStatusReport>) {
118        self.add_order_reports(reports);
119    }
120
121    /// Add fill reports to the mass status.
122    #[pyo3(name = "add_fill_reports")]
123    fn py_add_fill_reports(&mut self, reports: Vec<FillReport>) {
124        self.add_fill_reports(reports);
125    }
126
127    /// Add position reports to the mass status.
128    #[pyo3(name = "add_position_reports")]
129    fn py_add_position_reports(&mut self, reports: Vec<PositionStatusReport>) {
130        self.add_position_reports(reports);
131    }
132
133    /// Creates an `ExecutionMassStatus` from a Python dictionary.
134    ///
135    /// # Errors
136    ///
137    /// Returns a Python exception if conversion from dict fails.
138    #[staticmethod]
139    #[pyo3(name = "from_dict")]
140    pub fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
141        from_dict_pyo3(py, values)
142    }
143
144    #[pyo3(name = "to_dict")]
145    fn py_to_dict(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
146        let dict = PyDict::new(py);
147        dict.set_item("type", stringify!(ExecutionMassStatus))?;
148        dict.set_item("client_id", self.client_id.to_string())?;
149        dict.set_item("account_id", self.account_id.to_string())?;
150        dict.set_item("venue", self.venue.to_string())?;
151        dict.set_item("report_id", self.report_id.to_string())?;
152        dict.set_item("ts_init", self.ts_init.as_u64())?;
153
154        let order_reports_dict = PyDict::new(py);
155        for (key, value) in &self.order_reports() {
156            order_reports_dict.set_item(key.to_string(), value.py_to_dict(py)?)?;
157        }
158        dict.set_item("order_reports", order_reports_dict)?;
159
160        let fill_reports_dict = PyDict::new(py);
161        for (key, value) in &self.fill_reports() {
162            let reports: PyResult<Vec<_>> = value.iter().map(|r| r.py_to_dict(py)).collect();
163            fill_reports_dict.set_item(key.to_string(), reports?)?;
164        }
165        dict.set_item("fill_reports", fill_reports_dict)?;
166
167        let position_reports_dict = PyDict::new(py);
168        for (key, value) in &self.position_reports() {
169            let reports: PyResult<Vec<_>> = value.iter().map(|r| r.py_to_dict(py)).collect();
170            position_reports_dict.set_item(key.to_string(), reports?)?;
171        }
172        dict.set_item("position_reports", position_reports_dict)?;
173
174        Ok(dict.into())
175    }
176}