1use indexmap::IndexMap;
17use nautilus_core::{
18 UUID4, UnixNanos,
19 python::{IntoPyObjectNautilusExt, serialization::from_dict_pyo3},
20};
21use pyo3::{
22 basic::CompareOp,
23 prelude::*,
24 types::{PyDict, PyList},
25};
26use rust_decimal::Decimal;
27use ustr::Ustr;
28
29use crate::{
30 enums::{ContingencyType, OrderSide, OrderType, TimeInForce, TrailingOffsetType, TriggerType},
31 events::OrderInitialized,
32 identifiers::{
33 ClientOrderId, ExecAlgorithmId, InstrumentId, OrderListId, StrategyId, TraderId,
34 },
35 orders::base::str_indexmap_to_ustr,
36 types::{Price, Quantity},
37};
38
39#[pymethods]
40impl OrderInitialized {
41 #[allow(clippy::too_many_arguments)]
42 #[new]
43 #[pyo3(signature = (trader_id, strategy_id, instrument_id, client_order_id, order_side, order_type, quantity, time_in_force, post_only, reduce_only, quote_quantity, reconciliation, event_id, ts_event, ts_init, price=None, trigger_price=None, trigger_type=None, limit_offset=None, trailing_offset=None, trailing_offset_type=None, expire_time=None, display_qty=None, emulation_trigger=None, trigger_instrument_id=None, contingency_type=None, order_list_id=None, linked_order_ids=None, parent_order_id=None, exec_algorithm_id=None, exec_algorithm_params=None, exec_spawn_id=None, tags=None))]
44 fn py_new(
45 trader_id: TraderId,
46 strategy_id: StrategyId,
47 instrument_id: InstrumentId,
48 client_order_id: ClientOrderId,
49 order_side: OrderSide,
50 order_type: OrderType,
51 quantity: Quantity,
52 time_in_force: TimeInForce,
53 post_only: bool,
54 reduce_only: bool,
55 quote_quantity: bool,
56 reconciliation: bool,
57 event_id: UUID4,
58 ts_event: u64,
59 ts_init: u64,
60 price: Option<Price>,
61 trigger_price: Option<Price>,
62 trigger_type: Option<TriggerType>,
63 limit_offset: Option<Decimal>,
64 trailing_offset: Option<Decimal>,
65 trailing_offset_type: Option<TrailingOffsetType>,
66 expire_time: Option<u64>,
67 display_qty: Option<Quantity>,
68 emulation_trigger: Option<TriggerType>,
69 trigger_instrument_id: Option<InstrumentId>,
70 contingency_type: Option<ContingencyType>,
71 order_list_id: Option<OrderListId>,
72 linked_order_ids: Option<Vec<ClientOrderId>>,
73 parent_order_id: Option<ClientOrderId>,
74 exec_algorithm_id: Option<ExecAlgorithmId>,
75 exec_algorithm_params: Option<IndexMap<String, String>>,
76 exec_spawn_id: Option<ClientOrderId>,
77 tags: Option<Vec<String>>,
78 ) -> Self {
79 Self::new(
80 trader_id,
81 strategy_id,
82 instrument_id,
83 client_order_id,
84 order_side,
85 order_type,
86 quantity,
87 time_in_force,
88 post_only,
89 reduce_only,
90 quote_quantity,
91 reconciliation,
92 event_id,
93 ts_event.into(),
94 ts_init.into(),
95 price,
96 trigger_price,
97 trigger_type,
98 limit_offset,
99 trailing_offset,
100 trailing_offset_type,
101 expire_time.map(UnixNanos::from),
102 display_qty,
103 emulation_trigger,
104 trigger_instrument_id,
105 contingency_type,
106 order_list_id,
107 linked_order_ids,
108 parent_order_id,
109 exec_algorithm_id,
110 exec_algorithm_params.map(str_indexmap_to_ustr),
111 exec_spawn_id,
112 tags.map(|vec| vec.iter().map(|s| Ustr::from(s)).collect()),
113 )
114 }
115
116 fn __richcmp__(&self, other: &Self, op: CompareOp, py: Python<'_>) -> Py<PyAny> {
117 match op {
118 CompareOp::Eq => self.eq(other).into_py_any_unwrap(py),
119 CompareOp::Ne => self.ne(other).into_py_any_unwrap(py),
120 _ => py.NotImplemented(),
121 }
122 }
123
124 fn __repr__(&self) -> String {
125 format!("{:?}", self)
126 }
127
128 fn __str__(&self) -> String {
129 self.to_string()
130 }
131
132 #[getter]
133 #[pyo3(name = "order_type")]
134 fn py_order_type(&self) -> OrderType {
135 self.order_type
136 }
137
138 #[staticmethod]
139 #[pyo3(name = "from_dict")]
140 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!(OrderInitiliazed))?;
148 dict.set_item("trader_id", self.trader_id.to_string())?;
149 dict.set_item("strategy_id", self.strategy_id.to_string())?;
150 dict.set_item("instrument_id", self.instrument_id.to_string())?;
151 dict.set_item("client_order_id", self.client_order_id.to_string())?;
152 dict.set_item("order_side", self.order_side.to_string())?;
153 dict.set_item("order_type", self.order_type.to_string())?;
154 dict.set_item("quantity", self.quantity.to_string())?;
155 dict.set_item("time_in_force", self.time_in_force.to_string())?;
156 dict.set_item("post_only", self.post_only)?;
157 dict.set_item("reduce_only", self.reduce_only)?;
158 dict.set_item("quote_quantity", self.quote_quantity)?;
159 dict.set_item("reconciliation", self.reconciliation)?;
160 let options = PyDict::new(py);
162 if self.order_type == OrderType::StopMarket {
163 options.set_item("trigger_type", self.trigger_type.map(|x| x.to_string()))?;
164 options.set_item("trigger_price", self.trigger_price.map(|x| x.to_string()))?;
165 options.set_item("expire_time_ns", self.expire_time.map(|x| x.to_string()))?;
166 }
167 dict.set_item("options", options)?;
168 dict.set_item("event_id", self.event_id.to_string())?;
169 dict.set_item("ts_event", self.ts_event.as_u64())?;
170 dict.set_item("ts_init", self.ts_init.as_u64())?;
171 match self.price {
172 Some(price) => dict.set_item("price", price.to_string())?,
173 None => dict.set_item("price", py.None())?,
174 }
175 match self.trigger_price {
176 Some(trigger_price) => dict.set_item("trigger_price", trigger_price.to_string())?,
177 None => dict.set_item("trigger_price", py.None())?,
178 }
179 match self.trigger_type {
180 Some(trigger_type) => dict.set_item("trigger_type", trigger_type.to_string())?,
181 None => dict.set_item("trigger_type", py.None())?,
182 }
183 match self.limit_offset {
184 Some(limit_offset) => dict.set_item("limit_offset", limit_offset.to_string())?,
185 None => dict.set_item("limit_offset", py.None())?,
186 }
187 match self.trailing_offset {
188 Some(trailing_offset) => {
189 dict.set_item("trailing_offset", trailing_offset.to_string())?;
190 }
191 None => dict.set_item("trailing_offset", py.None())?,
192 }
193 match self.trailing_offset_type {
194 Some(trailing_offset_type) => {
195 dict.set_item("trailing_offset_type", trailing_offset_type.to_string())?;
196 }
197 None => dict.set_item("trailing_offset_type", py.None())?,
198 }
199 match self.expire_time {
200 Some(expire_time) => dict.set_item("expire_time", expire_time.as_u64())?,
201 None => dict.set_item("expire_time", py.None())?,
202 }
203 match self.display_qty {
204 Some(display_qty) => dict.set_item("display_qty", display_qty.to_string())?,
205 None => dict.set_item("display_qty", py.None())?,
206 }
207 match self.emulation_trigger {
208 Some(emulation_trigger) => {
209 dict.set_item("emulation_trigger", emulation_trigger.to_string())?;
210 }
211 None => dict.set_item("emulation_trigger", py.None())?,
212 }
213 match self.trigger_instrument_id {
214 Some(trigger_instrument_id) => {
215 dict.set_item("trigger_instrument_id", trigger_instrument_id.to_string())?;
216 }
217 None => dict.set_item("trigger_instrument_id", py.None())?,
218 }
219 match self.contingency_type {
220 Some(contingency_type) => {
221 dict.set_item("contingency_type", contingency_type.to_string())?;
222 }
223 None => dict.set_item("contingency_type", py.None())?,
224 }
225 match self.order_list_id {
226 Some(order_list_id) => dict.set_item("order_list_id", order_list_id.to_string())?,
227 None => dict.set_item("order_list_id", py.None())?,
228 }
229 match &self.linked_order_ids {
230 Some(linked_order_ids) => {
231 let py_linked_order_ids = PyList::empty(py);
232 for linked_order_id in linked_order_ids {
233 py_linked_order_ids.append(linked_order_id.to_string())?;
234 }
235 dict.set_item("linked_order_ids", py_linked_order_ids)?;
236 }
237 None => dict.set_item("linked_order_ids", py.None())?,
238 }
239 match self.parent_order_id {
240 Some(parent_order_id) => {
241 dict.set_item("parent_order_id", parent_order_id.to_string())?;
242 }
243 None => dict.set_item("parent_order_id", py.None())?,
244 }
245 match self.exec_algorithm_id {
246 Some(exec_algorithm_id) => {
247 dict.set_item("exec_algorithm_id", exec_algorithm_id.to_string())?;
248 }
249 None => dict.set_item("exec_algorithm_id", py.None())?,
250 }
251 match &self.exec_algorithm_params {
252 Some(exec_algorithm_params) => {
253 let py_exec_algorithm_params = PyDict::new(py);
254 for (key, value) in exec_algorithm_params {
255 py_exec_algorithm_params.set_item(key.to_string(), value.to_string())?;
256 }
257 dict.set_item("exec_algorithm_params", py_exec_algorithm_params)?;
258 }
259 None => dict.set_item("exec_algorithm_params", py.None())?,
260 }
261 match self.exec_spawn_id {
262 Some(exec_spawn_id) => dict.set_item("exec_spawn_id", exec_spawn_id.to_string())?,
263 None => dict.set_item("exec_spawn_id", py.None())?,
264 }
265 match &self.tags {
266 Some(tags) => dict.set_item(
267 "tags",
268 tags.iter().map(|x| x.to_string()).collect::<Vec<String>>(),
269 )?,
270 None => dict.set_item("tags", py.None())?,
271 }
272 Ok(dict.into())
273 }
274}