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