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