nautilus_model/python/orders/
list.rs1use nautilus_core::python::IntoPyObjectNautilusExt;
17use pyo3::{basic::CompareOp, prelude::*};
18
19use crate::{
20 identifiers::{ClientOrderId, InstrumentId, OrderListId, StrategyId},
21 orders::OrderList,
22};
23
24#[pyo3_stub_gen::derive::gen_stub_pymethods]
25#[pymethods]
26impl OrderList {
27 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
28 match op {
29 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
30 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
31 _ => py.NotImplemented(),
32 }
33 }
34
35 fn __hash__(&self) -> isize {
36 self.id.inner().precomputed_hash() as isize
37 }
38
39 fn __len__(&self) -> usize {
40 self.len()
41 }
42
43 fn __repr__(&self) -> String {
44 self.to_string()
45 }
46
47 fn __str__(&self) -> String {
48 self.to_string()
49 }
50
51 #[getter]
52 #[pyo3(name = "id")]
53 fn py_id(&self) -> OrderListId {
54 self.id
55 }
56
57 #[getter]
58 #[pyo3(name = "instrument_id")]
59 fn py_instrument_id(&self) -> InstrumentId {
60 self.instrument_id
61 }
62
63 #[getter]
64 #[pyo3(name = "strategy_id")]
65 fn py_strategy_id(&self) -> StrategyId {
66 self.strategy_id
67 }
68
69 #[pyo3(name = "client_order_ids")]
71 fn py_client_order_ids(&self) -> Vec<ClientOrderId> {
72 self.client_order_ids.clone()
73 }
74
75 #[getter]
76 #[pyo3(name = "first_client_order_id")]
77 fn py_first_client_order_id(&self) -> Option<ClientOrderId> {
78 self.first().copied()
79 }
80
81 #[getter]
82 #[pyo3(name = "ts_init")]
83 fn py_ts_init(&self) -> u64 {
84 self.ts_init.as_u64()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use nautilus_core::UnixNanos;
91 use pyo3::{
92 Py, Python,
93 types::{PyAnyMethods, PyStringMethods},
94 };
95 use rstest::rstest;
96
97 use crate::{
98 identifiers::{ClientOrderId, InstrumentId, OrderListId, StrategyId},
99 orders::OrderList,
100 };
101
102 fn create_order_list(order_list_id: &str) -> OrderList {
103 OrderList::new(
104 OrderListId::from(order_list_id),
105 InstrumentId::from("AUD/USD.SIM"),
106 StrategyId::from("S-001"),
107 vec![ClientOrderId::from("O-001"), ClientOrderId::from("O-002")],
108 UnixNanos::from(42_u64),
109 )
110 }
111
112 #[rstest]
113 fn test_python_order_list_exposes_readonly_api() {
114 Python::initialize();
115 Python::attach(|py| {
116 let order_list = create_order_list("OL-001");
117 let py_order_list = Py::new(py, order_list.clone()).unwrap();
118 let bound = py_order_list.bind(py);
119
120 assert_eq!(
121 bound
122 .getattr("id")
123 .unwrap()
124 .extract::<OrderListId>()
125 .unwrap(),
126 order_list.id,
127 );
128 assert_eq!(
129 bound
130 .getattr("instrument_id")
131 .unwrap()
132 .extract::<InstrumentId>()
133 .unwrap(),
134 order_list.instrument_id,
135 );
136 assert_eq!(
137 bound
138 .getattr("strategy_id")
139 .unwrap()
140 .extract::<StrategyId>()
141 .unwrap(),
142 order_list.strategy_id,
143 );
144 assert_eq!(
145 bound.getattr("ts_init").unwrap().extract::<u64>().unwrap(),
146 order_list.ts_init.as_u64(),
147 );
148 assert_eq!(
149 bound
150 .call_method0("client_order_ids")
151 .unwrap()
152 .extract::<Vec<ClientOrderId>>()
153 .unwrap(),
154 order_list.client_order_ids,
155 );
156 assert_eq!(
157 bound
158 .getattr("first_client_order_id")
159 .unwrap()
160 .extract::<ClientOrderId>()
161 .unwrap(),
162 order_list.client_order_ids[0],
163 );
164 assert_eq!(bound.len().unwrap(), order_list.len());
165 assert_eq!(
166 bound.str().unwrap().to_str().unwrap(),
167 order_list.to_string(),
168 );
169 assert_eq!(
170 bound.repr().unwrap().to_str().unwrap(),
171 order_list.to_string(),
172 );
173 assert_eq!(
174 bound.hash().unwrap(),
175 bound.getattr("id").unwrap().hash().unwrap(),
176 );
177
178 let same = Py::new(py, order_list).unwrap();
179 assert!(
180 bound
181 .call_method1("__eq__", (same,))
182 .unwrap()
183 .extract::<bool>()
184 .unwrap(),
185 );
186
187 let different = Py::new(py, create_order_list("OL-002")).unwrap();
188 assert!(
189 !bound
190 .call_method1("__eq__", (different,))
191 .unwrap()
192 .extract::<bool>()
193 .unwrap(),
194 );
195 assert!(bound.setattr("id", OrderListId::from("OL-003")).is_err());
196 });
197 }
198}