1use nautilus_core::{python::serialization::from_dict_pyo3, UUID4};
17use nautilus_model::{
18 enums::{
19 ContingencyType, OrderSide, OrderStatus, OrderType, TimeInForce, TrailingOffsetType,
20 TriggerType,
21 },
22 identifiers::{AccountId, ClientOrderId, InstrumentId, OrderListId, VenueOrderId},
23 types::{Price, Quantity},
24};
25use pyo3::{basic::CompareOp, prelude::*, types::PyDict};
26
27use crate::reports::order::OrderStatusReport;
28
29#[pymethods]
30impl OrderStatusReport {
31 #[new]
32 #[allow(clippy::too_many_arguments)]
33 #[pyo3(signature = (
34 account_id,
35 instrument_id,
36 venue_order_id,
37 order_side,
38 order_type,
39 time_in_force,
40 order_status,
41 quantity,
42 filled_qty,
43 ts_accepted,
44 ts_last,
45 ts_init,
46 client_order_id=None,
47 report_id=None,
48 order_list_id=None,
49 contingency_type=None,
50 expire_time=None,
51 price=None,
52 trigger_price=None,
53 trigger_type=None,
54 limit_offset=None,
55 trailing_offset=None,
56 trailing_offset_type=None,
57 avg_px=None,
58 display_qty=None,
59 post_only=false,
60 reduce_only=false,
61 cancel_reason=None,
62 ts_triggered=None,
63 ))]
64 fn py_new(
65 account_id: AccountId,
66 instrument_id: InstrumentId,
67 venue_order_id: VenueOrderId,
68 order_side: OrderSide,
69 order_type: OrderType,
70 time_in_force: TimeInForce,
71 order_status: OrderStatus,
72 quantity: Quantity,
73 filled_qty: Quantity,
74 ts_accepted: u64,
75 ts_last: u64,
76 ts_init: u64,
77 client_order_id: Option<ClientOrderId>,
78 report_id: Option<UUID4>,
79 order_list_id: Option<OrderListId>,
80 contingency_type: Option<ContingencyType>,
81 expire_time: Option<u64>,
82 price: Option<Price>,
83 trigger_price: Option<Price>,
84 trigger_type: Option<TriggerType>,
85 limit_offset: Option<Price>,
86 trailing_offset: Option<Price>,
87 trailing_offset_type: Option<TrailingOffsetType>,
88 avg_px: Option<f64>,
89 display_qty: Option<Quantity>,
90 post_only: bool,
91 reduce_only: bool,
92 cancel_reason: Option<String>,
93 ts_triggered: Option<u64>,
94 ) -> PyResult<Self> {
95 let mut report = Self::new(
96 account_id,
97 instrument_id,
98 client_order_id,
99 venue_order_id,
100 order_side,
101 order_type,
102 time_in_force,
103 order_status,
104 quantity,
105 filled_qty,
106 ts_accepted.into(),
107 ts_last.into(),
108 ts_init.into(),
109 report_id,
110 );
111
112 if let Some(id) = order_list_id {
113 report = report.with_order_list_id(id);
114 }
115 if let Some(ct) = contingency_type {
116 report = report.with_contingency_type(ct);
117 }
118 if let Some(et) = expire_time {
119 report = report.with_expire_time(et.into());
120 }
121 if let Some(p) = price {
122 report = report.with_price(p);
123 }
124 if let Some(tp) = trigger_price {
125 report = report.with_trigger_price(tp);
126 }
127 if let Some(tt) = trigger_type {
128 report = report.with_trigger_type(tt);
129 }
130 if let Some(lo) = limit_offset {
131 report = report.with_limit_offset(lo);
132 }
133 if let Some(to) = trailing_offset {
134 report = report.with_trailing_offset(to);
135 }
136 if let Some(tot) = trailing_offset_type {
137 report = report.with_trailing_offset_type(tot);
138 }
139 if let Some(ap) = avg_px {
140 report = report.with_avg_px(ap);
141 }
142 if let Some(dq) = display_qty {
143 report = report.with_display_qty(dq);
144 }
145 if post_only {
146 report = report.with_post_only(true);
147 }
148 if reduce_only {
149 report = report.with_reduce_only(true);
150 }
151 if let Some(cr) = cancel_reason {
152 report = report.with_cancel_reason(&cr);
153 }
154 if let Some(tt) = ts_triggered {
155 report = report.with_ts_triggered(tt.into());
156 }
157
158 Ok(report)
159 }
160
161 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
162 match op {
163 CompareOp::Eq => self.eq(other).into_py(py),
164 CompareOp::Ne => self.ne(other).into_py(py),
165 _ => py.NotImplemented(),
166 }
167 }
168
169 fn __repr__(&self) -> String {
170 self.to_string()
171 }
172
173 fn __str__(&self) -> String {
174 self.to_string()
175 }
176
177 #[getter]
178 #[pyo3(name = "account_id")]
179 const fn py_account_id(&self) -> AccountId {
180 self.account_id
181 }
182
183 #[getter]
184 #[pyo3(name = "instrument_id")]
185 const fn py_instrument_id(&self) -> InstrumentId {
186 self.instrument_id
187 }
188
189 #[getter]
190 #[pyo3(name = "venue_order_id")]
191 const fn py_venue_order_id(&self) -> VenueOrderId {
192 self.venue_order_id
193 }
194
195 #[getter]
196 #[pyo3(name = "order_side")]
197 const fn py_order_side(&self) -> OrderSide {
198 self.order_side
199 }
200
201 #[getter]
202 #[pyo3(name = "order_type")]
203 const fn py_order_type(&self) -> OrderType {
204 self.order_type
205 }
206
207 #[getter]
208 #[pyo3(name = "time_in_force")]
209 const fn py_time_in_force(&self) -> TimeInForce {
210 self.time_in_force
211 }
212
213 #[getter]
214 #[pyo3(name = "order_status")]
215 const fn py_order_status(&self) -> OrderStatus {
216 self.order_status
217 }
218
219 #[getter]
220 #[pyo3(name = "quantity")]
221 const fn py_quantity(&self) -> Quantity {
222 self.quantity
223 }
224
225 #[getter]
226 #[pyo3(name = "filled_qty")]
227 const fn py_filled_qty(&self) -> Quantity {
228 self.filled_qty
229 }
230
231 #[getter]
232 #[pyo3(name = "report_id")]
233 const fn py_report_id(&self) -> UUID4 {
234 self.report_id
235 }
236
237 #[getter]
238 #[pyo3(name = "ts_accepted")]
239 const fn py_ts_accepted(&self) -> u64 {
240 self.ts_accepted.as_u64()
241 }
242
243 #[getter]
244 #[pyo3(name = "ts_last")]
245 const fn py_ts_last(&self) -> u64 {
246 self.ts_last.as_u64()
247 }
248
249 #[getter]
250 #[pyo3(name = "ts_init")]
251 const fn py_ts_init(&self) -> u64 {
252 self.ts_init.as_u64()
253 }
254
255 #[getter]
256 #[pyo3(name = "client_order_id")]
257 const fn py_client_order_id(&self) -> Option<ClientOrderId> {
258 self.client_order_id
259 }
260
261 #[getter]
262 #[pyo3(name = "order_list_id")]
263 const fn py_order_list_id(&self) -> Option<OrderListId> {
264 self.order_list_id
265 }
266
267 #[getter]
268 #[pyo3(name = "contingency_type")]
269 const fn py_contingency_type(&self) -> ContingencyType {
270 self.contingency_type
271 }
272
273 #[getter]
274 #[pyo3(name = "expire_time")]
275 fn py_expire_time(&self) -> Option<u64> {
276 self.expire_time.map(|t| t.as_u64())
277 }
278
279 #[getter]
280 #[pyo3(name = "price")]
281 const fn py_price(&self) -> Option<Price> {
282 self.price
283 }
284
285 #[getter]
286 #[pyo3(name = "trigger_price")]
287 const fn py_trigger_price(&self) -> Option<Price> {
288 self.trigger_price
289 }
290
291 #[getter]
292 #[pyo3(name = "trigger_type")]
293 const fn py_trigger_type(&self) -> Option<TriggerType> {
294 self.trigger_type
295 }
296
297 #[getter]
298 #[pyo3(name = "limit_offset")]
299 const fn py_limit_offset(&self) -> Option<Price> {
300 self.limit_offset
301 }
302
303 #[getter]
304 #[pyo3(name = "trailing_offset")]
305 const fn py_trailing_offset(&self) -> Option<Price> {
306 self.trailing_offset
307 }
308
309 #[getter]
310 #[pyo3(name = "trailing_offset_type")]
311 const fn py_trailing_offset_type(&self) -> TrailingOffsetType {
312 self.trailing_offset_type
313 }
314
315 #[getter]
316 #[pyo3(name = "avg_px")]
317 const fn py_avg_px(&self) -> Option<f64> {
318 self.avg_px
319 }
320
321 #[getter]
322 #[pyo3(name = "display_qty")]
323 const fn py_display_qty(&self) -> Option<Quantity> {
324 self.display_qty
325 }
326
327 #[getter]
328 #[pyo3(name = "post_only")]
329 const fn py_post_only(&self) -> bool {
330 self.post_only
331 }
332
333 #[getter]
334 #[pyo3(name = "reduce_only")]
335 const fn py_reduce_only(&self) -> bool {
336 self.reduce_only
337 }
338
339 #[getter]
340 #[pyo3(name = "cancel_reason")]
341 fn py_cancel_reason(&self) -> Option<String> {
342 self.cancel_reason.clone()
343 }
344
345 #[getter]
346 #[pyo3(name = "ts_triggered")]
347 fn py_ts_triggered(&self) -> Option<u64> {
348 self.ts_triggered.map(|t| t.as_u64())
349 }
350
351 #[staticmethod]
352 #[pyo3(name = "from_dict")]
353 pub fn py_from_dict(py: Python<'_>, values: Py<PyDict>) -> PyResult<Self> {
354 from_dict_pyo3(py, values)
355 }
356
357 #[pyo3(name = "to_dict")]
358 pub fn py_to_dict(&self, py: Python<'_>) -> PyResult<PyObject> {
359 let dict = PyDict::new(py);
360 dict.set_item("type", stringify!(OrderStatusReport))?;
361 dict.set_item("account_id", self.account_id.to_string())?;
362 dict.set_item("instrument_id", self.instrument_id.to_string())?;
363 dict.set_item("venue_order_id", self.venue_order_id.to_string())?;
364 dict.set_item("order_side", self.order_side.to_string())?;
365 dict.set_item("order_type", self.order_type.to_string())?;
366 dict.set_item("time_in_force", self.time_in_force.to_string())?;
367 dict.set_item("order_status", self.order_status.to_string())?;
368 dict.set_item("quantity", self.quantity.to_string())?;
369 dict.set_item("filled_qty", self.filled_qty.to_string())?;
370 dict.set_item("report_id", self.report_id.to_string())?;
371 dict.set_item("ts_accepted", self.ts_accepted.as_u64())?;
372 dict.set_item("ts_last", self.ts_last.as_u64())?;
373 dict.set_item("ts_init", self.ts_init.as_u64())?;
374 dict.set_item("contingency_type", self.contingency_type.to_string())?;
375 dict.set_item(
376 "trailing_offset_type",
377 self.trailing_offset_type.to_string(),
378 )?;
379 dict.set_item("post_only", self.post_only)?;
380 dict.set_item("reduce_only", self.reduce_only)?;
381
382 match &self.client_order_id {
383 Some(id) => dict.set_item("client_order_id", id.to_string())?,
384 None => dict.set_item("client_order_id", py.None())?,
385 }
386 match &self.order_list_id {
387 Some(id) => dict.set_item("order_list_id", id.to_string())?,
388 None => dict.set_item("order_list_id", py.None())?,
389 }
390 match &self.expire_time {
391 Some(t) => dict.set_item("expire_time", t.as_u64())?,
392 None => dict.set_item("expire_time", py.None())?,
393 }
394 match &self.price {
395 Some(p) => dict.set_item("price", p.to_string())?,
396 None => dict.set_item("price", py.None())?,
397 }
398 match &self.trigger_price {
399 Some(p) => dict.set_item("trigger_price", p.to_string())?,
400 None => dict.set_item("trigger_price", py.None())?,
401 }
402 match &self.trigger_type {
403 Some(t) => dict.set_item("trigger_type", t.to_string())?,
404 None => dict.set_item("trigger_type", py.None())?,
405 }
406 match &self.limit_offset {
407 Some(o) => dict.set_item("limit_offset", o.to_string())?,
408 None => dict.set_item("limit_offset", py.None())?,
409 }
410 match &self.trailing_offset {
411 Some(o) => dict.set_item("trailing_offset", o.to_string())?,
412 None => dict.set_item("trailing_offset", py.None())?,
413 }
414 match &self.avg_px {
415 Some(p) => dict.set_item("avg_px", p)?,
416 None => dict.set_item("avg_px", py.None())?,
417 }
418 match &self.display_qty {
419 Some(q) => dict.set_item("display_qty", q.to_string())?,
420 None => dict.set_item("display_qty", py.None())?,
421 }
422 match &self.cancel_reason {
423 Some(r) => dict.set_item("cancel_reason", r)?,
424 None => dict.set_item("cancel_reason", py.None())?,
425 }
426 match &self.ts_triggered {
427 Some(t) => dict.set_item("ts_triggered", t.as_u64())?,
428 None => dict.set_item("ts_triggered", py.None())?,
429 }
430
431 Ok(dict.into())
432 }
433}