1use std::{cell::RefCell, rc::Rc};
19
20use indexmap::IndexMap;
21use nautilus_core::{UnixNanos, python::to_pyvalue_err};
22use nautilus_model::{
23 enums::{ContingencyType, OrderSide, OrderType, TimeInForce, TrailingOffsetType, TriggerType},
24 identifiers::{
25 ClientOrderId, ExecAlgorithmId, InstrumentId, OrderListId, StrategyId, TraderId,
26 },
27 orders::{OrderAny, str_indexmap_to_ustr},
28 python::orders::order_any_to_pyobject,
29 types::{Price, Quantity},
30};
31use pyo3::{prelude::*, types::PyList};
32use rust_decimal::Decimal;
33use ustr::Ustr;
34
35use crate::{factories::OrderFactory, python::clock::PyClock};
36
37#[allow(non_camel_case_types)]
39#[pyo3::pyclass(
40 module = "nautilus_trader.core.nautilus_pyo3.common",
41 name = "OrderFactory",
42 unsendable,
43 from_py_object
44)]
45#[pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.common")]
46#[derive(Debug, Clone)]
47pub struct PyOrderFactory(Rc<RefCell<OrderFactory>>);
48
49impl PyOrderFactory {
50 #[must_use]
52 pub fn from_rc(rc: Rc<RefCell<OrderFactory>>) -> Self {
53 Self(rc)
54 }
55
56 #[must_use]
58 pub fn order_factory_rc(&self) -> Rc<RefCell<OrderFactory>> {
59 self.0.clone()
60 }
61}
62
63#[pymethods]
64#[pyo3_stub_gen::derive::gen_stub_pymethods]
65#[expect(
66 clippy::too_many_arguments,
67 reason = "factory methods mirror the Python order factory API"
68)]
69impl PyOrderFactory {
70 #[new]
71 #[pyo3(signature = (
72 trader_id,
73 strategy_id,
74 clock,
75 use_uuid_client_order_ids=false,
76 use_hyphens_in_client_order_ids=true
77 ))]
78 #[allow(
79 clippy::needless_pass_by_value,
80 reason = "PyO3 extracts pyclass constructor arguments by value"
81 )]
82 fn py_new(
83 trader_id: TraderId,
84 strategy_id: StrategyId,
85 clock: PyClock,
86 use_uuid_client_order_ids: bool,
87 use_hyphens_in_client_order_ids: bool,
88 ) -> Self {
89 Self(Rc::new(RefCell::new(OrderFactory::new(
90 trader_id,
91 strategy_id,
92 None,
93 None,
94 clock.clock_rc(),
95 use_uuid_client_order_ids,
96 use_hyphens_in_client_order_ids,
97 ))))
98 }
99
100 #[pyo3(name = "get_client_order_id_count")]
101 fn py_get_client_order_id_count(&self) -> usize {
102 self.0.borrow().client_order_id_count()
103 }
104
105 #[pyo3(name = "get_order_list_id_count")]
106 fn py_get_order_list_id_count(&self) -> usize {
107 self.0.borrow().order_list_id_count()
108 }
109
110 #[pyo3(name = "generate_client_order_id")]
111 fn py_generate_client_order_id(&mut self) -> ClientOrderId {
112 self.0.borrow_mut().generate_client_order_id()
113 }
114
115 #[pyo3(name = "generate_order_list_id")]
116 fn py_generate_order_list_id(&mut self) -> OrderListId {
117 self.0.borrow_mut().generate_order_list_id()
118 }
119
120 #[pyo3(name = "reset")]
121 fn py_reset(&mut self) {
122 self.0.borrow_mut().reset_factory();
123 }
124
125 #[pyo3(name = "market", signature = (
126 instrument_id,
127 order_side,
128 quantity,
129 time_in_force=None,
130 reduce_only=None,
131 quote_quantity=None,
132 exec_algorithm_id=None,
133 exec_algorithm_params=None,
134 tags=None,
135 client_order_id=None
136 ))]
137 fn py_market(
138 &mut self,
139 py: Python<'_>,
140 instrument_id: InstrumentId,
141 order_side: OrderSide,
142 quantity: Quantity,
143 time_in_force: Option<TimeInForce>,
144 reduce_only: Option<bool>,
145 quote_quantity: Option<bool>,
146 exec_algorithm_id: Option<ExecAlgorithmId>,
147 exec_algorithm_params: Option<IndexMap<String, String>>,
148 tags: Option<Vec<String>>,
149 client_order_id: Option<ClientOrderId>,
150 ) -> PyResult<Py<PyAny>> {
151 py_order_from_factory(py, || {
152 self.0.borrow_mut().try_market(
153 instrument_id,
154 order_side,
155 quantity,
156 time_in_force,
157 reduce_only,
158 quote_quantity,
159 exec_algorithm_id,
160 exec_algorithm_params.map(str_indexmap_to_ustr),
161 tags.map(strings_to_ustrs),
162 client_order_id,
163 )
164 })
165 }
166
167 #[pyo3(name = "limit", signature = (
168 instrument_id,
169 order_side,
170 quantity,
171 price,
172 time_in_force=None,
173 expire_time=None,
174 post_only=None,
175 reduce_only=None,
176 quote_quantity=None,
177 display_qty=None,
178 emulation_trigger=None,
179 trigger_instrument_id=None,
180 exec_algorithm_id=None,
181 exec_algorithm_params=None,
182 tags=None,
183 client_order_id=None
184 ))]
185 fn py_limit(
186 &mut self,
187 py: Python<'_>,
188 instrument_id: InstrumentId,
189 order_side: OrderSide,
190 quantity: Quantity,
191 price: Price,
192 time_in_force: Option<TimeInForce>,
193 expire_time: Option<u64>,
194 post_only: Option<bool>,
195 reduce_only: Option<bool>,
196 quote_quantity: Option<bool>,
197 display_qty: Option<Quantity>,
198 emulation_trigger: Option<TriggerType>,
199 trigger_instrument_id: Option<InstrumentId>,
200 exec_algorithm_id: Option<ExecAlgorithmId>,
201 exec_algorithm_params: Option<IndexMap<String, String>>,
202 tags: Option<Vec<String>>,
203 client_order_id: Option<ClientOrderId>,
204 ) -> PyResult<Py<PyAny>> {
205 py_order_from_factory(py, || {
206 self.0.borrow_mut().try_limit(
207 instrument_id,
208 order_side,
209 quantity,
210 price,
211 time_in_force,
212 expire_time.map(UnixNanos::from),
213 post_only,
214 reduce_only,
215 quote_quantity,
216 display_qty,
217 emulation_trigger,
218 trigger_instrument_id,
219 exec_algorithm_id,
220 exec_algorithm_params.map(str_indexmap_to_ustr),
221 tags.map(strings_to_ustrs),
222 client_order_id,
223 )
224 })
225 }
226
227 #[pyo3(name = "stop_market", signature = (
228 instrument_id,
229 order_side,
230 quantity,
231 trigger_price,
232 trigger_type=None,
233 time_in_force=None,
234 expire_time=None,
235 reduce_only=None,
236 quote_quantity=None,
237 display_qty=None,
238 emulation_trigger=None,
239 trigger_instrument_id=None,
240 exec_algorithm_id=None,
241 exec_algorithm_params=None,
242 tags=None,
243 client_order_id=None
244 ))]
245 fn py_stop_market(
246 &mut self,
247 py: Python<'_>,
248 instrument_id: InstrumentId,
249 order_side: OrderSide,
250 quantity: Quantity,
251 trigger_price: Price,
252 trigger_type: Option<TriggerType>,
253 time_in_force: Option<TimeInForce>,
254 expire_time: Option<u64>,
255 reduce_only: Option<bool>,
256 quote_quantity: Option<bool>,
257 display_qty: Option<Quantity>,
258 emulation_trigger: Option<TriggerType>,
259 trigger_instrument_id: Option<InstrumentId>,
260 exec_algorithm_id: Option<ExecAlgorithmId>,
261 exec_algorithm_params: Option<IndexMap<String, String>>,
262 tags: Option<Vec<String>>,
263 client_order_id: Option<ClientOrderId>,
264 ) -> PyResult<Py<PyAny>> {
265 py_order_from_factory(py, || {
266 self.0.borrow_mut().try_stop_market(
267 instrument_id,
268 order_side,
269 quantity,
270 trigger_price,
271 trigger_type,
272 time_in_force,
273 expire_time.map(UnixNanos::from),
274 reduce_only,
275 quote_quantity,
276 display_qty,
277 emulation_trigger,
278 trigger_instrument_id,
279 exec_algorithm_id,
280 exec_algorithm_params.map(str_indexmap_to_ustr),
281 tags.map(strings_to_ustrs),
282 client_order_id,
283 )
284 })
285 }
286
287 #[pyo3(name = "stop_limit", signature = (
288 instrument_id,
289 order_side,
290 quantity,
291 price,
292 trigger_price,
293 trigger_type=None,
294 time_in_force=None,
295 expire_time=None,
296 post_only=None,
297 reduce_only=None,
298 quote_quantity=None,
299 display_qty=None,
300 emulation_trigger=None,
301 trigger_instrument_id=None,
302 exec_algorithm_id=None,
303 exec_algorithm_params=None,
304 tags=None,
305 client_order_id=None
306 ))]
307 fn py_stop_limit(
308 &mut self,
309 py: Python<'_>,
310 instrument_id: InstrumentId,
311 order_side: OrderSide,
312 quantity: Quantity,
313 price: Price,
314 trigger_price: Price,
315 trigger_type: Option<TriggerType>,
316 time_in_force: Option<TimeInForce>,
317 expire_time: Option<u64>,
318 post_only: Option<bool>,
319 reduce_only: Option<bool>,
320 quote_quantity: Option<bool>,
321 display_qty: Option<Quantity>,
322 emulation_trigger: Option<TriggerType>,
323 trigger_instrument_id: Option<InstrumentId>,
324 exec_algorithm_id: Option<ExecAlgorithmId>,
325 exec_algorithm_params: Option<IndexMap<String, String>>,
326 tags: Option<Vec<String>>,
327 client_order_id: Option<ClientOrderId>,
328 ) -> PyResult<Py<PyAny>> {
329 py_order_from_factory(py, || {
330 self.0.borrow_mut().try_stop_limit(
331 instrument_id,
332 order_side,
333 quantity,
334 price,
335 trigger_price,
336 trigger_type,
337 time_in_force,
338 expire_time.map(UnixNanos::from),
339 post_only,
340 reduce_only,
341 quote_quantity,
342 display_qty,
343 emulation_trigger,
344 trigger_instrument_id,
345 exec_algorithm_id,
346 exec_algorithm_params.map(str_indexmap_to_ustr),
347 tags.map(strings_to_ustrs),
348 client_order_id,
349 )
350 })
351 }
352
353 #[pyo3(name = "market_to_limit", signature = (
354 instrument_id,
355 order_side,
356 quantity,
357 time_in_force=None,
358 expire_time=None,
359 reduce_only=None,
360 quote_quantity=None,
361 display_qty=None,
362 exec_algorithm_id=None,
363 exec_algorithm_params=None,
364 tags=None,
365 client_order_id=None
366 ))]
367 fn py_market_to_limit(
368 &mut self,
369 py: Python<'_>,
370 instrument_id: InstrumentId,
371 order_side: OrderSide,
372 quantity: Quantity,
373 time_in_force: Option<TimeInForce>,
374 expire_time: Option<u64>,
375 reduce_only: Option<bool>,
376 quote_quantity: Option<bool>,
377 display_qty: Option<Quantity>,
378 exec_algorithm_id: Option<ExecAlgorithmId>,
379 exec_algorithm_params: Option<IndexMap<String, String>>,
380 tags: Option<Vec<String>>,
381 client_order_id: Option<ClientOrderId>,
382 ) -> PyResult<Py<PyAny>> {
383 py_order_from_factory(py, || {
384 self.0.borrow_mut().try_market_to_limit(
385 instrument_id,
386 order_side,
387 quantity,
388 time_in_force,
389 expire_time.map(UnixNanos::from),
390 reduce_only,
391 quote_quantity,
392 display_qty,
393 exec_algorithm_id,
394 exec_algorithm_params.map(str_indexmap_to_ustr),
395 tags.map(strings_to_ustrs),
396 client_order_id,
397 )
398 })
399 }
400
401 #[pyo3(name = "market_if_touched", signature = (
402 instrument_id,
403 order_side,
404 quantity,
405 trigger_price,
406 trigger_type=None,
407 time_in_force=None,
408 expire_time=None,
409 reduce_only=None,
410 quote_quantity=None,
411 emulation_trigger=None,
412 trigger_instrument_id=None,
413 exec_algorithm_id=None,
414 exec_algorithm_params=None,
415 tags=None,
416 client_order_id=None
417 ))]
418 fn py_market_if_touched(
419 &mut self,
420 py: Python<'_>,
421 instrument_id: InstrumentId,
422 order_side: OrderSide,
423 quantity: Quantity,
424 trigger_price: Price,
425 trigger_type: Option<TriggerType>,
426 time_in_force: Option<TimeInForce>,
427 expire_time: Option<u64>,
428 reduce_only: Option<bool>,
429 quote_quantity: Option<bool>,
430 emulation_trigger: Option<TriggerType>,
431 trigger_instrument_id: Option<InstrumentId>,
432 exec_algorithm_id: Option<ExecAlgorithmId>,
433 exec_algorithm_params: Option<IndexMap<String, String>>,
434 tags: Option<Vec<String>>,
435 client_order_id: Option<ClientOrderId>,
436 ) -> PyResult<Py<PyAny>> {
437 py_order_from_factory(py, || {
438 self.0.borrow_mut().try_market_if_touched(
439 instrument_id,
440 order_side,
441 quantity,
442 trigger_price,
443 trigger_type,
444 time_in_force,
445 expire_time.map(UnixNanos::from),
446 reduce_only,
447 quote_quantity,
448 emulation_trigger,
449 trigger_instrument_id,
450 exec_algorithm_id,
451 exec_algorithm_params.map(str_indexmap_to_ustr),
452 tags.map(strings_to_ustrs),
453 client_order_id,
454 )
455 })
456 }
457
458 #[pyo3(name = "limit_if_touched", signature = (
459 instrument_id,
460 order_side,
461 quantity,
462 price,
463 trigger_price,
464 trigger_type=None,
465 time_in_force=None,
466 expire_time=None,
467 post_only=None,
468 reduce_only=None,
469 quote_quantity=None,
470 display_qty=None,
471 emulation_trigger=None,
472 trigger_instrument_id=None,
473 exec_algorithm_id=None,
474 exec_algorithm_params=None,
475 tags=None,
476 client_order_id=None
477 ))]
478 fn py_limit_if_touched(
479 &mut self,
480 py: Python<'_>,
481 instrument_id: InstrumentId,
482 order_side: OrderSide,
483 quantity: Quantity,
484 price: Price,
485 trigger_price: Price,
486 trigger_type: Option<TriggerType>,
487 time_in_force: Option<TimeInForce>,
488 expire_time: Option<u64>,
489 post_only: Option<bool>,
490 reduce_only: Option<bool>,
491 quote_quantity: Option<bool>,
492 display_qty: Option<Quantity>,
493 emulation_trigger: Option<TriggerType>,
494 trigger_instrument_id: Option<InstrumentId>,
495 exec_algorithm_id: Option<ExecAlgorithmId>,
496 exec_algorithm_params: Option<IndexMap<String, String>>,
497 tags: Option<Vec<String>>,
498 client_order_id: Option<ClientOrderId>,
499 ) -> PyResult<Py<PyAny>> {
500 py_order_from_factory(py, || {
501 self.0.borrow_mut().try_limit_if_touched(
502 instrument_id,
503 order_side,
504 quantity,
505 price,
506 trigger_price,
507 trigger_type,
508 time_in_force,
509 expire_time.map(UnixNanos::from),
510 post_only,
511 reduce_only,
512 quote_quantity,
513 display_qty,
514 emulation_trigger,
515 trigger_instrument_id,
516 exec_algorithm_id,
517 exec_algorithm_params.map(str_indexmap_to_ustr),
518 tags.map(strings_to_ustrs),
519 client_order_id,
520 )
521 })
522 }
523
524 #[pyo3(name = "trailing_stop_market", signature = (
525 instrument_id,
526 order_side,
527 quantity,
528 trailing_offset,
529 trailing_offset_type=None,
530 activation_price=None,
531 trigger_price=None,
532 trigger_type=None,
533 time_in_force=None,
534 expire_time=None,
535 reduce_only=None,
536 quote_quantity=None,
537 display_qty=None,
538 emulation_trigger=None,
539 trigger_instrument_id=None,
540 exec_algorithm_id=None,
541 exec_algorithm_params=None,
542 tags=None,
543 client_order_id=None
544 ))]
545 fn py_trailing_stop_market(
546 &mut self,
547 py: Python<'_>,
548 instrument_id: InstrumentId,
549 order_side: OrderSide,
550 quantity: Quantity,
551 trailing_offset: Decimal,
552 trailing_offset_type: Option<TrailingOffsetType>,
553 activation_price: Option<Price>,
554 trigger_price: Option<Price>,
555 trigger_type: Option<TriggerType>,
556 time_in_force: Option<TimeInForce>,
557 expire_time: Option<u64>,
558 reduce_only: Option<bool>,
559 quote_quantity: Option<bool>,
560 display_qty: Option<Quantity>,
561 emulation_trigger: Option<TriggerType>,
562 trigger_instrument_id: Option<InstrumentId>,
563 exec_algorithm_id: Option<ExecAlgorithmId>,
564 exec_algorithm_params: Option<IndexMap<String, String>>,
565 tags: Option<Vec<String>>,
566 client_order_id: Option<ClientOrderId>,
567 ) -> PyResult<Py<PyAny>> {
568 py_order_from_factory(py, || {
569 self.0.borrow_mut().try_trailing_stop_market(
570 instrument_id,
571 order_side,
572 quantity,
573 trailing_offset,
574 trailing_offset_type,
575 activation_price,
576 trigger_price,
577 trigger_type,
578 time_in_force,
579 expire_time.map(UnixNanos::from),
580 reduce_only,
581 quote_quantity,
582 display_qty,
583 emulation_trigger,
584 trigger_instrument_id,
585 exec_algorithm_id,
586 exec_algorithm_params.map(str_indexmap_to_ustr),
587 tags.map(strings_to_ustrs),
588 client_order_id,
589 )
590 })
591 }
592
593 #[pyo3(name = "trailing_stop_limit", signature = (
594 instrument_id,
595 order_side,
596 quantity,
597 price,
598 limit_offset,
599 trailing_offset,
600 trailing_offset_type=None,
601 activation_price=None,
602 trigger_price=None,
603 trigger_type=None,
604 time_in_force=None,
605 expire_time=None,
606 post_only=None,
607 reduce_only=None,
608 quote_quantity=None,
609 display_qty=None,
610 emulation_trigger=None,
611 trigger_instrument_id=None,
612 exec_algorithm_id=None,
613 exec_algorithm_params=None,
614 tags=None,
615 client_order_id=None
616 ))]
617 fn py_trailing_stop_limit(
618 &mut self,
619 py: Python<'_>,
620 instrument_id: InstrumentId,
621 order_side: OrderSide,
622 quantity: Quantity,
623 price: Price,
624 limit_offset: Decimal,
625 trailing_offset: Decimal,
626 trailing_offset_type: Option<TrailingOffsetType>,
627 activation_price: Option<Price>,
628 trigger_price: Option<Price>,
629 trigger_type: Option<TriggerType>,
630 time_in_force: Option<TimeInForce>,
631 expire_time: Option<u64>,
632 post_only: Option<bool>,
633 reduce_only: Option<bool>,
634 quote_quantity: Option<bool>,
635 display_qty: Option<Quantity>,
636 emulation_trigger: Option<TriggerType>,
637 trigger_instrument_id: Option<InstrumentId>,
638 exec_algorithm_id: Option<ExecAlgorithmId>,
639 exec_algorithm_params: Option<IndexMap<String, String>>,
640 tags: Option<Vec<String>>,
641 client_order_id: Option<ClientOrderId>,
642 ) -> PyResult<Py<PyAny>> {
643 py_order_from_factory(py, || {
644 self.0.borrow_mut().try_trailing_stop_limit(
645 instrument_id,
646 order_side,
647 quantity,
648 price,
649 limit_offset,
650 trailing_offset,
651 trailing_offset_type,
652 activation_price,
653 trigger_price,
654 trigger_type,
655 time_in_force,
656 expire_time.map(UnixNanos::from),
657 post_only,
658 reduce_only,
659 quote_quantity,
660 display_qty,
661 emulation_trigger,
662 trigger_instrument_id,
663 exec_algorithm_id,
664 exec_algorithm_params.map(str_indexmap_to_ustr),
665 tags.map(strings_to_ustrs),
666 client_order_id,
667 )
668 })
669 }
670
671 #[pyo3(name = "bracket", signature = (
672 instrument_id,
673 order_side,
674 quantity,
675 quote_quantity=false,
676 emulation_trigger=None,
677 trigger_instrument_id=None,
678 contingency_type=ContingencyType::Ouo,
679 entry_order_type=OrderType::Market,
680 entry_price=None,
681 entry_trigger_price=None,
682 expire_time=None,
683 time_in_force=TimeInForce::Gtc,
684 entry_post_only=false,
685 entry_exec_algorithm_id=None,
686 entry_exec_algorithm_params=None,
687 entry_tags=None,
688 entry_client_order_id=None,
689 tp_order_type=OrderType::Limit,
690 tp_price=None,
691 tp_trigger_price=None,
692 tp_trigger_type=TriggerType::Default,
693 tp_activation_price=None,
694 tp_trailing_offset=None,
695 tp_trailing_offset_type=TrailingOffsetType::Price,
696 tp_limit_offset=None,
697 tp_time_in_force=TimeInForce::Gtc,
698 tp_post_only=true,
699 tp_exec_algorithm_id=None,
700 tp_exec_algorithm_params=None,
701 tp_tags=None,
702 tp_client_order_id=None,
703 sl_order_type=OrderType::StopMarket,
704 sl_trigger_price=None,
705 sl_trigger_type=TriggerType::Default,
706 sl_activation_price=None,
707 sl_trailing_offset=None,
708 sl_trailing_offset_type=TrailingOffsetType::Price,
709 sl_time_in_force=TimeInForce::Gtc,
710 sl_exec_algorithm_id=None,
711 sl_exec_algorithm_params=None,
712 sl_tags=None,
713 sl_client_order_id=None
714 ))]
715 fn py_bracket(
716 &mut self,
717 py: Python<'_>,
718 instrument_id: InstrumentId,
719 order_side: OrderSide,
720 quantity: Quantity,
721 quote_quantity: bool,
722 emulation_trigger: Option<TriggerType>,
723 trigger_instrument_id: Option<InstrumentId>,
724 contingency_type: ContingencyType,
725 entry_order_type: OrderType,
726 entry_price: Option<Price>,
727 entry_trigger_price: Option<Price>,
728 expire_time: Option<u64>,
729 time_in_force: TimeInForce,
730 entry_post_only: bool,
731 entry_exec_algorithm_id: Option<ExecAlgorithmId>,
732 entry_exec_algorithm_params: Option<IndexMap<String, String>>,
733 entry_tags: Option<Vec<String>>,
734 entry_client_order_id: Option<ClientOrderId>,
735 tp_order_type: OrderType,
736 tp_price: Option<Price>,
737 tp_trigger_price: Option<Price>,
738 tp_trigger_type: TriggerType,
739 tp_activation_price: Option<Price>,
740 tp_trailing_offset: Option<Decimal>,
741 tp_trailing_offset_type: TrailingOffsetType,
742 tp_limit_offset: Option<Decimal>,
743 tp_time_in_force: TimeInForce,
744 tp_post_only: bool,
745 tp_exec_algorithm_id: Option<ExecAlgorithmId>,
746 tp_exec_algorithm_params: Option<IndexMap<String, String>>,
747 tp_tags: Option<Vec<String>>,
748 tp_client_order_id: Option<ClientOrderId>,
749 sl_order_type: OrderType,
750 sl_trigger_price: Option<Price>,
751 sl_trigger_type: TriggerType,
752 sl_activation_price: Option<Price>,
753 sl_trailing_offset: Option<Decimal>,
754 sl_trailing_offset_type: TrailingOffsetType,
755 sl_time_in_force: TimeInForce,
756 sl_exec_algorithm_id: Option<ExecAlgorithmId>,
757 sl_exec_algorithm_params: Option<IndexMap<String, String>>,
758 sl_tags: Option<Vec<String>>,
759 sl_client_order_id: Option<ClientOrderId>,
760 ) -> PyResult<Py<PyList>> {
761 let orders = py_orders_from_factory(|| {
762 self.0
763 .borrow_mut()
764 .try_bracket()
765 .instrument_id(instrument_id)
766 .order_side(order_side)
767 .quantity(quantity)
768 .quote_quantity(quote_quantity)
769 .maybe_emulation_trigger(emulation_trigger)
770 .maybe_trigger_instrument_id(trigger_instrument_id)
771 .contingency_type(contingency_type)
772 .entry_order_type(entry_order_type)
773 .maybe_entry_price(entry_price)
774 .maybe_entry_trigger_price(entry_trigger_price)
775 .maybe_expire_time(expire_time.map(UnixNanos::from))
776 .time_in_force(time_in_force)
777 .entry_post_only(entry_post_only)
778 .maybe_entry_exec_algorithm_id(entry_exec_algorithm_id)
779 .maybe_entry_exec_algorithm_params(
780 entry_exec_algorithm_params.map(str_indexmap_to_ustr),
781 )
782 .maybe_entry_tags(entry_tags.map(strings_to_ustrs))
783 .maybe_entry_client_order_id(entry_client_order_id)
784 .tp_order_type(tp_order_type)
785 .maybe_tp_price(tp_price)
786 .maybe_tp_trigger_price(tp_trigger_price)
787 .tp_trigger_type(tp_trigger_type)
788 .maybe_tp_activation_price(tp_activation_price)
789 .maybe_tp_trailing_offset(tp_trailing_offset)
790 .tp_trailing_offset_type(tp_trailing_offset_type)
791 .maybe_tp_limit_offset(tp_limit_offset)
792 .tp_time_in_force(tp_time_in_force)
793 .tp_post_only(tp_post_only)
794 .maybe_tp_exec_algorithm_id(tp_exec_algorithm_id)
795 .maybe_tp_exec_algorithm_params(tp_exec_algorithm_params.map(str_indexmap_to_ustr))
796 .maybe_tp_tags(tp_tags.map(strings_to_ustrs))
797 .maybe_tp_client_order_id(tp_client_order_id)
798 .sl_order_type(sl_order_type)
799 .maybe_sl_trigger_price(sl_trigger_price)
800 .sl_trigger_type(sl_trigger_type)
801 .maybe_sl_activation_price(sl_activation_price)
802 .maybe_sl_trailing_offset(sl_trailing_offset)
803 .sl_trailing_offset_type(sl_trailing_offset_type)
804 .sl_time_in_force(sl_time_in_force)
805 .maybe_sl_exec_algorithm_id(sl_exec_algorithm_id)
806 .maybe_sl_exec_algorithm_params(sl_exec_algorithm_params.map(str_indexmap_to_ustr))
807 .maybe_sl_tags(sl_tags.map(strings_to_ustrs))
808 .maybe_sl_client_order_id(sl_client_order_id)
809 .call()
810 })?;
811 let py_orders = orders
812 .into_iter()
813 .map(|order| order_any_to_pyobject(py, order))
814 .collect::<PyResult<Vec<_>>>()?;
815 Ok(PyList::new(py, py_orders)?.unbind())
816 }
817}
818
819fn py_order_from_factory<F>(py: Python<'_>, create: F) -> PyResult<Py<PyAny>>
820where
821 F: FnOnce() -> anyhow::Result<OrderAny>,
822{
823 let order = create().map_err(to_pyvalue_err)?;
824 order_any_to_pyobject(py, order)
825}
826
827fn py_orders_from_factory<F>(create: F) -> PyResult<Vec<OrderAny>>
828where
829 F: FnOnce() -> anyhow::Result<Vec<OrderAny>>,
830{
831 create().map_err(to_pyvalue_err)
832}
833
834fn strings_to_ustrs(values: Vec<String>) -> Vec<Ustr> {
835 values
836 .into_iter()
837 .map(|value| Ustr::from(value.as_str()))
838 .collect()
839}