nautilus_model/python/reports/
mass_status.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Posei Systems Pty Ltd. All rights reserved.
3//  https://poseitrader.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::{IntoPyObjectPoseiExt, 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]
32impl ExecutionMassStatus {
33    #[new]
34    #[pyo3(signature = (client_id, account_id, venue, ts_init, report_id=None))]
35    fn py_new(
36        client_id: ClientId,
37        account_id: AccountId,
38        venue: Venue,
39        ts_init: u64,
40        report_id: Option<UUID4>,
41    ) -> PyResult<Self> {
42        Ok(Self::new(
43            client_id,
44            account_id,
45            venue,
46            ts_init.into(),
47            report_id,
48        ))
49    }
50
51    fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
52        match op {
53            CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
54            CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
55            _ => py.NotImplemented(),
56        }
57    }
58
59    fn __repr__(&self) -> String {
60        self.to_string()
61    }
62
63    fn __str__(&self) -> String {
64        self.to_string()
65    }
66
67    #[getter]
68    #[pyo3(name = "client_id")]
69    const fn py_client_id(&self) -> ClientId {
70        self.client_id
71    }
72
73    #[getter]
74    #[pyo3(name = "account_id")]
75    const fn py_account_id(&self) -> AccountId {
76        self.account_id
77    }
78
79    #[getter]
80    #[pyo3(name = "venue")]
81    const fn py_venue(&self) -> Venue {
82        self.venue
83    }
84
85    #[getter]
86    #[pyo3(name = "report_id")]
87    const fn py_report_id(&self) -> UUID4 {
88        self.report_id
89    }
90
91    #[getter]
92    #[pyo3(name = "ts_init")]
93    const fn py_ts_init(&self) -> u64 {
94        self.ts_init.as_u64()
95    }
96
97    #[getter]
98    #[pyo3(name = "order_reports")]
99    fn py_order_reports(&self) -> PyResult<IndexMap<VenueOrderId, OrderStatusReport>> {
100        Ok(self.order_reports())
101    }
102
103    #[getter]
104    #[pyo3(name = "fill_reports")]
105    fn py_fill_reports(&self) -> PyResult<IndexMap<VenueOrderId, Vec<FillReport>>> {
106        Ok(self.fill_reports())
107    }
108
109    #[getter]
110    #[pyo3(name = "position_reports")]
111    fn py_position_reports(&self) -> PyResult<IndexMap<InstrumentId, Vec<PositionStatusReport>>> {
112        Ok(self.position_reports())
113    }
114
115    #[pyo3(name = "add_order_reports")]
116    fn py_add_order_reports(&mut self, reports: Vec<OrderStatusReport>) -> PyResult<()> {
117        self.add_order_reports(reports);
118        Ok(())
119    }
120
121    #[pyo3(name = "add_fill_reports")]
122    fn py_add_fill_reports(&mut self, reports: Vec<FillReport>) -> PyResult<()> {
123        self.add_fill_reports(reports);
124        Ok(())
125    }
126
127    #[pyo3(name = "add_position_reports")]
128    fn py_add_position_reports(&mut self, reports: Vec<PositionStatusReport>) -> PyResult<()> {
129        self.add_position_reports(reports);
130        Ok(())
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<PyObject> {
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}