1use std::{cell::RefCell, rc::Rc};
19
20use bytes::Bytes;
21use nautilus_core::python::to_pyvalue_err;
22#[cfg(feature = "defi")]
23use nautilus_model::defi::{Pool, PoolProfiler};
24use nautilus_model::{
25 data::{
26 Bar, BarType, FundingRateUpdate, InstrumentStatus, QuoteTick, TradeTick,
27 prices::{IndexPriceUpdate, MarkPriceUpdate},
28 },
29 enums::{AggregationSource, OmsType, OrderSide, PositionSide, PriceType},
30 identifiers::{
31 AccountId, ClientId, ClientOrderId, ComponentId, ExecAlgorithmId, InstrumentId,
32 OrderListId, PositionId, StrategyId, Venue, VenueOrderId,
33 },
34 instruments::SyntheticInstrument,
35 orderbook::{OrderBook, own::OwnOrderBook},
36 orders::OrderList,
37 position::Position,
38 python::{
39 account::account_any_to_pyobject,
40 instruments::{instrument_any_to_pyobject, pyobject_to_instrument_any},
41 orders::{order_any_to_pyobject, pyobject_to_order_any},
42 },
43 types::{Currency, Money, Price, Quantity},
44};
45use pyo3::prelude::*;
46use rust_decimal::prelude::ToPrimitive;
47
48use crate::{
49 cache::{Cache, CacheConfig},
50 enums::SerializationEncoding,
51 python::config_error_to_pyvalue_err,
52};
53
54#[allow(non_camel_case_types)]
59#[pyo3::pyclass(
60 module = "nautilus_trader.core.nautilus_pyo3.common",
61 name = "Cache",
62 unsendable,
63 from_py_object
64)]
65#[pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.common")]
66#[derive(Debug, Clone)]
67pub struct PyCache(Rc<RefCell<Cache>>);
68
69impl PyCache {
70 #[must_use]
72 pub fn from_rc(rc: Rc<RefCell<Cache>>) -> Self {
73 Self(rc)
74 }
75
76 #[must_use]
78 pub fn cache_rc(&self) -> Rc<RefCell<Cache>> {
79 self.0.clone()
80 }
81}
82
83#[pymethods]
84#[pyo3_stub_gen::derive::gen_stub_pymethods]
85impl PyCache {
86 #[new]
87 #[pyo3(signature = (config=None))]
88 fn py_new(config: Option<CacheConfig>) -> Self {
89 Self(Rc::new(RefCell::new(Cache::new(config, None))))
90 }
91
92 #[pyo3(name = "reset")]
93 fn py_reset(&mut self) {
94 self.0.borrow_mut().reset();
95 }
96
97 #[pyo3(name = "dispose")]
98 fn py_dispose(&mut self) {
99 self.0.borrow_mut().dispose();
100 }
101
102 #[pyo3(name = "purge_closed_orders", signature = (ts_now, buffer_secs=0))]
103 fn py_purge_closed_orders(&mut self, ts_now: u64, buffer_secs: u64) {
104 self.0
105 .borrow_mut()
106 .purge_closed_orders(ts_now.into(), buffer_secs);
107 }
108
109 #[pyo3(name = "purge_closed_positions", signature = (ts_now, buffer_secs=0))]
110 fn py_purge_closed_positions(&mut self, ts_now: u64, buffer_secs: u64) {
111 self.0
112 .borrow_mut()
113 .purge_closed_positions(ts_now.into(), buffer_secs);
114 }
115
116 #[pyo3(name = "purge_order")]
117 fn py_purge_order(&mut self, client_order_id: ClientOrderId) {
118 self.0.borrow_mut().purge_order(client_order_id);
119 }
120
121 #[pyo3(name = "purge_position")]
122 fn py_purge_position(&mut self, position_id: PositionId) {
123 self.0.borrow_mut().purge_position(position_id);
124 }
125
126 #[pyo3(name = "purge_instrument")]
127 fn py_purge_instrument(&mut self, instrument_id: InstrumentId) {
128 self.0.borrow_mut().purge_instrument(instrument_id);
129 }
130
131 #[pyo3(name = "purge_account_events", signature = (ts_now, lookback_secs=0))]
132 fn py_purge_account_events(&mut self, ts_now: u64, lookback_secs: u64) {
133 self.0
134 .borrow_mut()
135 .purge_account_events(ts_now.into(), lookback_secs);
136 }
137
138 #[pyo3(name = "get")]
139 fn py_get(&self, key: &str) -> PyResult<Option<Vec<u8>>> {
140 match self.0.borrow().get(key).map_err(to_pyvalue_err)? {
141 Some(bytes) => Ok(Some(bytes.to_vec())),
142 None => Ok(None),
143 }
144 }
145
146 #[pyo3(name = "add")]
147 fn py_add_general(&mut self, key: &str, value: Vec<u8>) -> PyResult<()> {
148 self.0
149 .borrow_mut()
150 .add(key, Bytes::from(value))
151 .map_err(to_pyvalue_err)
152 }
153
154 #[pyo3(name = "quote", signature = (instrument_id, index=0))]
155 fn py_quote(&self, instrument_id: InstrumentId, index: usize) -> Option<QuoteTick> {
156 self.0
157 .borrow()
158 .quote_at_index(&instrument_id, index)
159 .copied()
160 }
161
162 #[pyo3(name = "trade", signature = (instrument_id, index=0))]
163 fn py_trade(&self, instrument_id: InstrumentId, index: usize) -> Option<TradeTick> {
164 self.0
165 .borrow()
166 .trade_at_index(&instrument_id, index)
167 .copied()
168 }
169
170 #[pyo3(name = "bar", signature = (bar_type, index=0))]
171 fn py_bar(&self, bar_type: BarType, index: usize) -> Option<Bar> {
172 self.0.borrow().bar_at_index(&bar_type, index).copied()
173 }
174
175 #[pyo3(name = "quotes")]
176 fn py_quotes(&self, instrument_id: InstrumentId) -> Option<Vec<QuoteTick>> {
177 self.0.borrow().quotes(&instrument_id)
178 }
179
180 #[pyo3(name = "trades")]
181 fn py_trades(&self, instrument_id: InstrumentId) -> Option<Vec<TradeTick>> {
182 self.0.borrow().trades(&instrument_id)
183 }
184
185 #[pyo3(name = "bars")]
186 fn py_bars(&self, bar_type: BarType) -> Option<Vec<Bar>> {
187 self.0.borrow().bars(&bar_type)
188 }
189
190 #[pyo3(name = "bar_types", signature = (aggregation_source, instrument_id=None, price_type=None))]
191 fn py_bar_types(
192 &self,
193 aggregation_source: AggregationSource,
194 instrument_id: Option<InstrumentId>,
195 price_type: Option<PriceType>,
196 ) -> Vec<BarType> {
197 self.0
198 .borrow()
199 .bar_types(
200 instrument_id.as_ref(),
201 price_type.as_ref(),
202 aggregation_source,
203 )
204 .into_iter()
205 .copied()
206 .collect()
207 }
208
209 #[pyo3(name = "mark_price")]
210 fn py_mark_price(&self, instrument_id: InstrumentId) -> Option<MarkPriceUpdate> {
211 self.0.borrow().mark_price(&instrument_id).copied()
212 }
213
214 #[pyo3(name = "mark_prices")]
215 fn py_mark_prices(&self, instrument_id: InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
216 self.0.borrow().mark_prices(&instrument_id)
217 }
218
219 #[pyo3(name = "index_price")]
220 fn py_index_price(&self, instrument_id: InstrumentId) -> Option<IndexPriceUpdate> {
221 self.0.borrow().index_price(&instrument_id).copied()
222 }
223
224 #[pyo3(name = "index_prices")]
225 fn py_index_prices(&self, instrument_id: InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
226 self.0.borrow().index_prices(&instrument_id)
227 }
228
229 #[pyo3(name = "funding_rate")]
230 fn py_funding_rate(&self, instrument_id: InstrumentId) -> Option<FundingRateUpdate> {
231 self.0.borrow().funding_rate(&instrument_id).copied()
232 }
233
234 #[pyo3(name = "instrument_status")]
235 fn py_instrument_status(&self, instrument_id: InstrumentId) -> Option<InstrumentStatus> {
236 self.0.borrow().instrument_status(&instrument_id).copied()
237 }
238
239 #[pyo3(name = "instrument_statuses")]
240 fn py_instrument_statuses(&self, instrument_id: InstrumentId) -> Option<Vec<InstrumentStatus>> {
241 self.0.borrow().instrument_statuses(&instrument_id)
242 }
243
244 #[pyo3(name = "price")]
245 fn py_price(&self, instrument_id: InstrumentId, price_type: PriceType) -> Option<Price> {
246 self.0.borrow().price(&instrument_id, price_type)
247 }
248
249 #[pyo3(name = "order_book")]
250 fn py_order_book(&self, instrument_id: InstrumentId) -> Option<OrderBook> {
251 self.0.borrow().order_book(&instrument_id).cloned()
252 }
253
254 #[pyo3(name = "has_order_book")]
255 fn py_has_order_book(&self, instrument_id: InstrumentId) -> bool {
256 self.0.borrow().has_order_book(&instrument_id)
257 }
258
259 #[pyo3(name = "book_update_count")]
260 fn py_book_update_count(&self, instrument_id: InstrumentId) -> usize {
261 self.0.borrow().book_update_count(&instrument_id)
262 }
263
264 #[pyo3(name = "has_quote_ticks")]
265 fn py_has_quote_ticks(&self, instrument_id: InstrumentId) -> bool {
266 self.0.borrow().has_quote_ticks(&instrument_id)
267 }
268
269 #[pyo3(name = "has_trade_ticks")]
270 fn py_has_trade_ticks(&self, instrument_id: InstrumentId) -> bool {
271 self.0.borrow().has_trade_ticks(&instrument_id)
272 }
273
274 #[pyo3(name = "has_bars")]
275 fn py_has_bars(&self, bar_type: BarType) -> bool {
276 self.0.borrow().has_bars(&bar_type)
277 }
278
279 #[pyo3(name = "quote_count")]
280 fn py_quote_count(&self, instrument_id: InstrumentId) -> usize {
281 self.0.borrow().quote_count(&instrument_id)
282 }
283
284 #[pyo3(name = "trade_count")]
285 fn py_trade_count(&self, instrument_id: InstrumentId) -> usize {
286 self.0.borrow().trade_count(&instrument_id)
287 }
288
289 #[pyo3(name = "bar_count")]
290 fn py_bar_count(&self, bar_type: BarType) -> usize {
291 self.0.borrow().bar_count(&bar_type)
292 }
293
294 #[pyo3(name = "get_xrate")]
295 fn py_get_xrate(
296 &self,
297 venue: Venue,
298 from_currency: Currency,
299 to_currency: Currency,
300 price_type: PriceType,
301 ) -> Option<f64> {
302 self.0
303 .borrow()
304 .get_xrate(venue, from_currency, to_currency, price_type)
305 .and_then(|rate| rate.to_f64())
306 }
307
308 #[pyo3(name = "get_mark_xrate")]
309 fn py_get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
310 self.0.borrow().get_mark_xrate(from_currency, to_currency)
311 }
312
313 #[pyo3(name = "own_order_book")]
314 fn py_own_order_book(&self, instrument_id: InstrumentId) -> Option<OwnOrderBook> {
315 self.0.borrow().own_order_book(&instrument_id).cloned()
316 }
317
318 #[pyo3(name = "instrument")]
319 fn py_instrument(
320 &self,
321 py: Python,
322 instrument_id: InstrumentId,
323 ) -> PyResult<Option<Py<PyAny>>> {
324 let cache = self.0.borrow();
325 match cache.instrument(&instrument_id) {
326 Some(instrument) => Ok(Some(instrument_any_to_pyobject(py, instrument.clone())?)),
327 None => Ok(None),
328 }
329 }
330
331 #[pyo3(name = "instrument_ids", signature = (venue=None))]
332 fn py_instrument_ids(&self, venue: Option<Venue>) -> Vec<InstrumentId> {
333 self.0
334 .borrow()
335 .instrument_ids(venue.as_ref())
336 .into_iter()
337 .copied()
338 .collect()
339 }
340
341 #[pyo3(name = "instruments", signature = (venue=None))]
342 fn py_instruments(&self, py: Python, venue: Option<Venue>) -> PyResult<Vec<Py<PyAny>>> {
343 let cache = self.0.borrow();
344 let mut py_instruments = Vec::new();
345
346 match venue {
347 Some(venue) => {
348 for instrument in cache.instruments(&venue, None) {
349 py_instruments.push(instrument_any_to_pyobject(py, (*instrument).clone())?);
350 }
351 }
352 None => {
353 for instrument_id in cache.instrument_ids(None) {
354 if let Some(instrument) = cache.instrument(instrument_id) {
355 py_instruments.push(instrument_any_to_pyobject(py, instrument.clone())?);
356 }
357 }
358 }
359 }
360 Ok(py_instruments)
361 }
362
363 #[pyo3(name = "synthetic")]
364 fn py_synthetic(&self, instrument_id: InstrumentId) -> Option<SyntheticInstrument> {
365 self.0.borrow().synthetic(&instrument_id).cloned()
366 }
367
368 #[pyo3(name = "synthetic_ids")]
369 fn py_synthetic_ids(&self) -> Vec<InstrumentId> {
370 self.0
371 .borrow()
372 .synthetic_ids()
373 .into_iter()
374 .copied()
375 .collect()
376 }
377
378 #[pyo3(name = "account")]
379 fn py_account(&self, py: Python, account_id: AccountId) -> PyResult<Option<Py<PyAny>>> {
380 let cache = self.0.borrow();
381 match cache.account(&account_id) {
382 Some(account) => Ok(Some(account_any_to_pyobject(py, account.clone())?)),
383 None => Ok(None),
384 }
385 }
386
387 #[pyo3(name = "account_for_venue")]
388 fn py_account_for_venue(&self, py: Python, venue: Venue) -> PyResult<Option<Py<PyAny>>> {
389 let cache = self.0.borrow();
390 match cache.account_for_venue(&venue) {
391 Some(account) => Ok(Some(account_any_to_pyobject(py, account.clone())?)),
392 None => Ok(None),
393 }
394 }
395
396 #[pyo3(name = "account_id")]
397 fn py_account_id(&self, venue: Venue) -> Option<AccountId> {
398 self.0.borrow().account_id(&venue).copied()
399 }
400
401 #[pyo3(name = "client_order_ids", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
402 fn py_client_order_ids(
403 &self,
404 venue: Option<Venue>,
405 instrument_id: Option<InstrumentId>,
406 strategy_id: Option<StrategyId>,
407 account_id: Option<AccountId>,
408 ) -> Vec<ClientOrderId> {
409 self.0
410 .borrow()
411 .client_order_ids(
412 venue.as_ref(),
413 instrument_id.as_ref(),
414 strategy_id.as_ref(),
415 account_id.as_ref(),
416 )
417 .into_iter()
418 .collect()
419 }
420
421 #[pyo3(name = "client_order_ids_open", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
422 fn py_client_order_ids_open(
423 &self,
424 venue: Option<Venue>,
425 instrument_id: Option<InstrumentId>,
426 strategy_id: Option<StrategyId>,
427 account_id: Option<AccountId>,
428 ) -> Vec<ClientOrderId> {
429 self.0
430 .borrow()
431 .client_order_ids_open(
432 venue.as_ref(),
433 instrument_id.as_ref(),
434 strategy_id.as_ref(),
435 account_id.as_ref(),
436 )
437 .into_iter()
438 .collect()
439 }
440
441 #[pyo3(name = "client_order_ids_closed", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
442 fn py_client_order_ids_closed(
443 &self,
444 venue: Option<Venue>,
445 instrument_id: Option<InstrumentId>,
446 strategy_id: Option<StrategyId>,
447 account_id: Option<AccountId>,
448 ) -> Vec<ClientOrderId> {
449 self.0
450 .borrow()
451 .client_order_ids_closed(
452 venue.as_ref(),
453 instrument_id.as_ref(),
454 strategy_id.as_ref(),
455 account_id.as_ref(),
456 )
457 .into_iter()
458 .collect()
459 }
460
461 #[pyo3(name = "client_order_ids_emulated", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
462 fn py_client_order_ids_emulated(
463 &self,
464 venue: Option<Venue>,
465 instrument_id: Option<InstrumentId>,
466 strategy_id: Option<StrategyId>,
467 account_id: Option<AccountId>,
468 ) -> Vec<ClientOrderId> {
469 self.0
470 .borrow()
471 .client_order_ids_emulated(
472 venue.as_ref(),
473 instrument_id.as_ref(),
474 strategy_id.as_ref(),
475 account_id.as_ref(),
476 )
477 .into_iter()
478 .collect()
479 }
480
481 #[pyo3(name = "client_order_ids_inflight", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
482 fn py_client_order_ids_inflight(
483 &self,
484 venue: Option<Venue>,
485 instrument_id: Option<InstrumentId>,
486 strategy_id: Option<StrategyId>,
487 account_id: Option<AccountId>,
488 ) -> Vec<ClientOrderId> {
489 self.0
490 .borrow()
491 .client_order_ids_inflight(
492 venue.as_ref(),
493 instrument_id.as_ref(),
494 strategy_id.as_ref(),
495 account_id.as_ref(),
496 )
497 .into_iter()
498 .collect()
499 }
500
501 #[pyo3(name = "position_ids", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
502 fn py_position_ids(
503 &self,
504 venue: Option<Venue>,
505 instrument_id: Option<InstrumentId>,
506 strategy_id: Option<StrategyId>,
507 account_id: Option<AccountId>,
508 ) -> Vec<PositionId> {
509 self.0
510 .borrow()
511 .position_ids(
512 venue.as_ref(),
513 instrument_id.as_ref(),
514 strategy_id.as_ref(),
515 account_id.as_ref(),
516 )
517 .into_iter()
518 .collect()
519 }
520
521 #[pyo3(name = "position_open_ids", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
522 fn py_position_open_ids(
523 &self,
524 venue: Option<Venue>,
525 instrument_id: Option<InstrumentId>,
526 strategy_id: Option<StrategyId>,
527 account_id: Option<AccountId>,
528 ) -> Vec<PositionId> {
529 self.0
530 .borrow()
531 .position_open_ids(
532 venue.as_ref(),
533 instrument_id.as_ref(),
534 strategy_id.as_ref(),
535 account_id.as_ref(),
536 )
537 .into_iter()
538 .collect()
539 }
540
541 #[pyo3(name = "position_closed_ids", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
542 fn py_position_closed_ids(
543 &self,
544 venue: Option<Venue>,
545 instrument_id: Option<InstrumentId>,
546 strategy_id: Option<StrategyId>,
547 account_id: Option<AccountId>,
548 ) -> Vec<PositionId> {
549 self.0
550 .borrow()
551 .position_closed_ids(
552 venue.as_ref(),
553 instrument_id.as_ref(),
554 strategy_id.as_ref(),
555 account_id.as_ref(),
556 )
557 .into_iter()
558 .collect()
559 }
560
561 #[pyo3(name = "actor_ids")]
562 fn py_actor_ids(&self) -> Vec<ComponentId> {
563 self.0.borrow().actor_ids().into_iter().collect()
564 }
565
566 #[pyo3(name = "strategy_ids")]
567 fn py_strategy_ids(&self) -> Vec<StrategyId> {
568 self.0.borrow().strategy_ids().into_iter().collect()
569 }
570
571 #[pyo3(name = "exec_algorithm_ids")]
572 fn py_exec_algorithm_ids(&self) -> Vec<ExecAlgorithmId> {
573 self.0.borrow().exec_algorithm_ids().into_iter().collect()
574 }
575
576 #[pyo3(name = "order")]
577 fn py_order(&self, py: Python, client_order_id: ClientOrderId) -> PyResult<Option<Py<PyAny>>> {
578 let cache = self.0.borrow();
579 match cache.order(&client_order_id) {
580 Some(order) => Ok(Some(order_any_to_pyobject(py, order.clone())?)),
581 None => Ok(None),
582 }
583 }
584
585 #[pyo3(name = "client_order_id")]
586 fn py_client_order_id(&self, venue_order_id: VenueOrderId) -> Option<ClientOrderId> {
587 self.0.borrow().client_order_id(&venue_order_id).copied()
588 }
589
590 #[pyo3(name = "venue_order_id")]
591 fn py_venue_order_id(&self, client_order_id: ClientOrderId) -> Option<VenueOrderId> {
592 self.0.borrow().venue_order_id(&client_order_id).copied()
593 }
594
595 #[pyo3(name = "client_id")]
596 fn py_client_id(&self, client_order_id: ClientOrderId) -> Option<ClientId> {
597 self.0.borrow().client_id(&client_order_id).copied()
598 }
599
600 #[pyo3(name = "orders", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
601 fn py_orders(
602 &self,
603 py: Python,
604 venue: Option<Venue>,
605 instrument_id: Option<InstrumentId>,
606 strategy_id: Option<StrategyId>,
607 account_id: Option<AccountId>,
608 side: Option<OrderSide>,
609 ) -> PyResult<Vec<Py<PyAny>>> {
610 let cache = self.0.borrow();
611 cache
612 .orders(
613 venue.as_ref(),
614 instrument_id.as_ref(),
615 strategy_id.as_ref(),
616 account_id.as_ref(),
617 side,
618 )
619 .into_iter()
620 .map(|o| order_any_to_pyobject(py, o.clone()))
621 .collect()
622 }
623
624 #[pyo3(name = "orders_open", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
625 fn py_orders_open(
626 &self,
627 py: Python,
628 venue: Option<Venue>,
629 instrument_id: Option<InstrumentId>,
630 strategy_id: Option<StrategyId>,
631 account_id: Option<AccountId>,
632 side: Option<OrderSide>,
633 ) -> PyResult<Vec<Py<PyAny>>> {
634 let cache = self.0.borrow();
635 cache
636 .orders_open(
637 venue.as_ref(),
638 instrument_id.as_ref(),
639 strategy_id.as_ref(),
640 account_id.as_ref(),
641 side,
642 )
643 .into_iter()
644 .map(|o| order_any_to_pyobject(py, o.clone()))
645 .collect()
646 }
647
648 #[pyo3(name = "orders_closed", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
649 fn py_orders_closed(
650 &self,
651 py: Python,
652 venue: Option<Venue>,
653 instrument_id: Option<InstrumentId>,
654 strategy_id: Option<StrategyId>,
655 account_id: Option<AccountId>,
656 side: Option<OrderSide>,
657 ) -> PyResult<Vec<Py<PyAny>>> {
658 let cache = self.0.borrow();
659 cache
660 .orders_closed(
661 venue.as_ref(),
662 instrument_id.as_ref(),
663 strategy_id.as_ref(),
664 account_id.as_ref(),
665 side,
666 )
667 .into_iter()
668 .map(|o| order_any_to_pyobject(py, o.clone()))
669 .collect()
670 }
671
672 #[pyo3(name = "orders_emulated", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
673 fn py_orders_emulated(
674 &self,
675 py: Python,
676 venue: Option<Venue>,
677 instrument_id: Option<InstrumentId>,
678 strategy_id: Option<StrategyId>,
679 account_id: Option<AccountId>,
680 side: Option<OrderSide>,
681 ) -> PyResult<Vec<Py<PyAny>>> {
682 let cache = self.0.borrow();
683 cache
684 .orders_emulated(
685 venue.as_ref(),
686 instrument_id.as_ref(),
687 strategy_id.as_ref(),
688 account_id.as_ref(),
689 side,
690 )
691 .into_iter()
692 .map(|o| order_any_to_pyobject(py, o.clone()))
693 .collect()
694 }
695
696 #[pyo3(name = "orders_inflight", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
697 fn py_orders_inflight(
698 &self,
699 py: Python,
700 venue: Option<Venue>,
701 instrument_id: Option<InstrumentId>,
702 strategy_id: Option<StrategyId>,
703 account_id: Option<AccountId>,
704 side: Option<OrderSide>,
705 ) -> PyResult<Vec<Py<PyAny>>> {
706 let cache = self.0.borrow();
707 cache
708 .orders_inflight(
709 venue.as_ref(),
710 instrument_id.as_ref(),
711 strategy_id.as_ref(),
712 account_id.as_ref(),
713 side,
714 )
715 .into_iter()
716 .map(|o| order_any_to_pyobject(py, o.clone()))
717 .collect()
718 }
719
720 #[pyo3(name = "orders_for_position")]
721 fn py_orders_for_position(
722 &self,
723 py: Python,
724 position_id: PositionId,
725 ) -> PyResult<Vec<Py<PyAny>>> {
726 let cache = self.0.borrow();
727 cache
728 .orders_for_position(&position_id)
729 .into_iter()
730 .map(|o| order_any_to_pyobject(py, o.clone()))
731 .collect()
732 }
733
734 #[pyo3(name = "order_exists")]
735 fn py_order_exists(&self, client_order_id: ClientOrderId) -> bool {
736 self.0.borrow().order_exists(&client_order_id)
737 }
738
739 #[pyo3(name = "is_order_open")]
740 fn py_is_order_open(&self, client_order_id: ClientOrderId) -> bool {
741 self.0.borrow().is_order_open(&client_order_id)
742 }
743
744 #[pyo3(name = "is_order_closed")]
745 fn py_is_order_closed(&self, client_order_id: ClientOrderId) -> bool {
746 self.0.borrow().is_order_closed(&client_order_id)
747 }
748
749 #[pyo3(name = "is_order_emulated")]
750 fn py_is_order_emulated(&self, client_order_id: ClientOrderId) -> bool {
751 self.0.borrow().is_order_emulated(&client_order_id)
752 }
753
754 #[pyo3(name = "is_order_inflight")]
755 fn py_is_order_inflight(&self, client_order_id: ClientOrderId) -> bool {
756 self.0.borrow().is_order_inflight(&client_order_id)
757 }
758
759 #[pyo3(name = "is_order_pending_cancel_local")]
760 fn py_is_order_pending_cancel_local(&self, client_order_id: ClientOrderId) -> bool {
761 self.0
762 .borrow()
763 .is_order_pending_cancel_local(&client_order_id)
764 }
765
766 #[pyo3(name = "orders_open_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
767 fn py_orders_open_count(
768 &self,
769 venue: Option<Venue>,
770 instrument_id: Option<InstrumentId>,
771 strategy_id: Option<StrategyId>,
772 account_id: Option<AccountId>,
773 side: Option<OrderSide>,
774 ) -> usize {
775 self.0.borrow().orders_open_count(
776 venue.as_ref(),
777 instrument_id.as_ref(),
778 strategy_id.as_ref(),
779 account_id.as_ref(),
780 side,
781 )
782 }
783
784 #[pyo3(name = "orders_closed_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
785 fn py_orders_closed_count(
786 &self,
787 venue: Option<Venue>,
788 instrument_id: Option<InstrumentId>,
789 strategy_id: Option<StrategyId>,
790 account_id: Option<AccountId>,
791 side: Option<OrderSide>,
792 ) -> usize {
793 self.0.borrow().orders_closed_count(
794 venue.as_ref(),
795 instrument_id.as_ref(),
796 strategy_id.as_ref(),
797 account_id.as_ref(),
798 side,
799 )
800 }
801
802 #[pyo3(name = "orders_emulated_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
803 fn py_orders_emulated_count(
804 &self,
805 venue: Option<Venue>,
806 instrument_id: Option<InstrumentId>,
807 strategy_id: Option<StrategyId>,
808 account_id: Option<AccountId>,
809 side: Option<OrderSide>,
810 ) -> usize {
811 self.0.borrow().orders_emulated_count(
812 venue.as_ref(),
813 instrument_id.as_ref(),
814 strategy_id.as_ref(),
815 account_id.as_ref(),
816 side,
817 )
818 }
819
820 #[pyo3(name = "orders_inflight_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
821 fn py_orders_inflight_count(
822 &self,
823 venue: Option<Venue>,
824 instrument_id: Option<InstrumentId>,
825 strategy_id: Option<StrategyId>,
826 account_id: Option<AccountId>,
827 side: Option<OrderSide>,
828 ) -> usize {
829 self.0.borrow().orders_inflight_count(
830 venue.as_ref(),
831 instrument_id.as_ref(),
832 strategy_id.as_ref(),
833 account_id.as_ref(),
834 side,
835 )
836 }
837
838 #[pyo3(name = "orders_total_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
839 fn py_orders_total_count(
840 &self,
841 venue: Option<Venue>,
842 instrument_id: Option<InstrumentId>,
843 strategy_id: Option<StrategyId>,
844 account_id: Option<AccountId>,
845 side: Option<OrderSide>,
846 ) -> usize {
847 self.0.borrow().orders_total_count(
848 venue.as_ref(),
849 instrument_id.as_ref(),
850 strategy_id.as_ref(),
851 account_id.as_ref(),
852 side,
853 )
854 }
855
856 #[pyo3(name = "order_list")]
857 fn py_order_list(&self, py: Python, order_list_id: OrderListId) -> PyResult<Option<Py<PyAny>>> {
858 let cache = self.0.borrow();
859 match cache.order_list(&order_list_id) {
860 Some(order_list) => Ok(Some(order_list.clone().into_pyobject(py)?.into())),
861 None => Ok(None),
862 }
863 }
864
865 #[pyo3(name = "order_lists", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None))]
866 fn py_order_lists(
867 &self,
868 py: Python,
869 venue: Option<Venue>,
870 instrument_id: Option<InstrumentId>,
871 strategy_id: Option<StrategyId>,
872 account_id: Option<AccountId>,
873 ) -> PyResult<Vec<Py<PyAny>>> {
874 let cache = self.0.borrow();
875 cache
876 .order_lists(
877 venue.as_ref(),
878 instrument_id.as_ref(),
879 strategy_id.as_ref(),
880 account_id.as_ref(),
881 )
882 .into_iter()
883 .map(|ol| Ok(ol.clone().into_pyobject(py)?.into()))
884 .collect()
885 }
886
887 #[pyo3(name = "order_list_exists")]
888 fn py_order_list_exists(&self, order_list_id: OrderListId) -> bool {
889 self.0.borrow().order_list_exists(&order_list_id)
890 }
891
892 #[pyo3(name = "orders_for_exec_algorithm", signature = (exec_algorithm_id, venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
893 #[expect(clippy::too_many_arguments)]
894 fn py_orders_for_exec_algorithm(
895 &self,
896 py: Python,
897 exec_algorithm_id: ExecAlgorithmId,
898 venue: Option<Venue>,
899 instrument_id: Option<InstrumentId>,
900 strategy_id: Option<StrategyId>,
901 account_id: Option<AccountId>,
902 side: Option<OrderSide>,
903 ) -> PyResult<Vec<Py<PyAny>>> {
904 let cache = self.0.borrow();
905 cache
906 .orders_for_exec_algorithm(
907 &exec_algorithm_id,
908 venue.as_ref(),
909 instrument_id.as_ref(),
910 strategy_id.as_ref(),
911 account_id.as_ref(),
912 side,
913 )
914 .into_iter()
915 .map(|o| order_any_to_pyobject(py, o.clone()))
916 .collect()
917 }
918
919 #[pyo3(name = "orders_for_exec_spawn")]
920 fn py_orders_for_exec_spawn(
921 &self,
922 py: Python,
923 exec_spawn_id: ClientOrderId,
924 ) -> PyResult<Vec<Py<PyAny>>> {
925 let cache = self.0.borrow();
926 cache
927 .orders_for_exec_spawn(&exec_spawn_id)
928 .into_iter()
929 .map(|o| order_any_to_pyobject(py, o.clone()))
930 .collect()
931 }
932
933 #[pyo3(name = "exec_spawn_total_quantity")]
934 fn py_exec_spawn_total_quantity(
935 &self,
936 exec_spawn_id: ClientOrderId,
937 active_only: bool,
938 ) -> Option<Quantity> {
939 self.0
940 .borrow()
941 .exec_spawn_total_quantity(&exec_spawn_id, active_only)
942 }
943
944 #[pyo3(name = "exec_spawn_total_filled_qty")]
945 fn py_exec_spawn_total_filled_qty(
946 &self,
947 exec_spawn_id: ClientOrderId,
948 active_only: bool,
949 ) -> Option<Quantity> {
950 self.0
951 .borrow()
952 .exec_spawn_total_filled_qty(&exec_spawn_id, active_only)
953 }
954
955 #[pyo3(name = "exec_spawn_total_leaves_qty")]
956 fn py_exec_spawn_total_leaves_qty(
957 &self,
958 exec_spawn_id: ClientOrderId,
959 active_only: bool,
960 ) -> Option<Quantity> {
961 self.0
962 .borrow()
963 .exec_spawn_total_leaves_qty(&exec_spawn_id, active_only)
964 }
965
966 #[pyo3(name = "position")]
967 fn py_position(&self, py: Python, position_id: PositionId) -> PyResult<Option<Py<PyAny>>> {
968 let cache = self.0.borrow();
969 match cache.position(&position_id) {
970 Some(position) => Ok(Some(position.clone().into_pyobject(py)?.into())),
971 None => Ok(None),
972 }
973 }
974
975 #[pyo3(name = "position_for_order")]
976 fn py_position_for_order(
977 &self,
978 py: Python,
979 client_order_id: ClientOrderId,
980 ) -> PyResult<Option<Py<PyAny>>> {
981 let cache = self.0.borrow();
982 match cache.position_for_order(&client_order_id) {
983 Some(position) => Ok(Some(position.clone().into_pyobject(py)?.into())),
984 None => Ok(None),
985 }
986 }
987
988 #[pyo3(name = "position_id")]
989 fn py_position_id(&self, client_order_id: ClientOrderId) -> Option<PositionId> {
990 self.0.borrow().position_id(&client_order_id).copied()
991 }
992
993 #[pyo3(name = "positions", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
994 fn py_positions(
995 &self,
996 py: Python,
997 venue: Option<Venue>,
998 instrument_id: Option<InstrumentId>,
999 strategy_id: Option<StrategyId>,
1000 account_id: Option<AccountId>,
1001 side: Option<PositionSide>,
1002 ) -> PyResult<Vec<Py<PyAny>>> {
1003 let cache = self.0.borrow();
1004 cache
1005 .positions(
1006 venue.as_ref(),
1007 instrument_id.as_ref(),
1008 strategy_id.as_ref(),
1009 account_id.as_ref(),
1010 side,
1011 )
1012 .into_iter()
1013 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
1014 .collect()
1015 }
1016
1017 #[pyo3(name = "positions_open", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
1018 fn py_positions_open(
1019 &self,
1020 py: Python,
1021 venue: Option<Venue>,
1022 instrument_id: Option<InstrumentId>,
1023 strategy_id: Option<StrategyId>,
1024 account_id: Option<AccountId>,
1025 side: Option<PositionSide>,
1026 ) -> PyResult<Vec<Py<PyAny>>> {
1027 let cache = self.0.borrow();
1028 cache
1029 .positions_open(
1030 venue.as_ref(),
1031 instrument_id.as_ref(),
1032 strategy_id.as_ref(),
1033 account_id.as_ref(),
1034 side,
1035 )
1036 .into_iter()
1037 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
1038 .collect()
1039 }
1040
1041 #[pyo3(name = "positions_closed", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
1042 fn py_positions_closed(
1043 &self,
1044 py: Python,
1045 venue: Option<Venue>,
1046 instrument_id: Option<InstrumentId>,
1047 strategy_id: Option<StrategyId>,
1048 account_id: Option<AccountId>,
1049 side: Option<PositionSide>,
1050 ) -> PyResult<Vec<Py<PyAny>>> {
1051 let cache = self.0.borrow();
1052 cache
1053 .positions_closed(
1054 venue.as_ref(),
1055 instrument_id.as_ref(),
1056 strategy_id.as_ref(),
1057 account_id.as_ref(),
1058 side,
1059 )
1060 .into_iter()
1061 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
1062 .collect()
1063 }
1064
1065 #[pyo3(name = "position_exists")]
1066 fn py_position_exists(&self, position_id: PositionId) -> bool {
1067 self.0.borrow().position_exists(&position_id)
1068 }
1069
1070 #[pyo3(name = "is_position_open")]
1071 fn py_is_position_open(&self, position_id: PositionId) -> bool {
1072 self.0.borrow().is_position_open(&position_id)
1073 }
1074
1075 #[pyo3(name = "is_position_closed")]
1076 fn py_is_position_closed(&self, position_id: PositionId) -> bool {
1077 self.0.borrow().is_position_closed(&position_id)
1078 }
1079
1080 #[pyo3(name = "positions_open_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
1081 fn py_positions_open_count(
1082 &self,
1083 venue: Option<Venue>,
1084 instrument_id: Option<InstrumentId>,
1085 strategy_id: Option<StrategyId>,
1086 account_id: Option<AccountId>,
1087 side: Option<PositionSide>,
1088 ) -> usize {
1089 self.0.borrow().positions_open_count(
1090 venue.as_ref(),
1091 instrument_id.as_ref(),
1092 strategy_id.as_ref(),
1093 account_id.as_ref(),
1094 side,
1095 )
1096 }
1097
1098 #[pyo3(name = "positions_closed_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
1099 fn py_positions_closed_count(
1100 &self,
1101 venue: Option<Venue>,
1102 instrument_id: Option<InstrumentId>,
1103 strategy_id: Option<StrategyId>,
1104 account_id: Option<AccountId>,
1105 side: Option<PositionSide>,
1106 ) -> usize {
1107 self.0.borrow().positions_closed_count(
1108 venue.as_ref(),
1109 instrument_id.as_ref(),
1110 strategy_id.as_ref(),
1111 account_id.as_ref(),
1112 side,
1113 )
1114 }
1115
1116 #[pyo3(name = "positions_total_count", signature = (venue=None, instrument_id=None, strategy_id=None, account_id=None, side=None))]
1117 fn py_positions_total_count(
1118 &self,
1119 venue: Option<Venue>,
1120 instrument_id: Option<InstrumentId>,
1121 strategy_id: Option<StrategyId>,
1122 account_id: Option<AccountId>,
1123 side: Option<PositionSide>,
1124 ) -> usize {
1125 self.0.borrow().positions_total_count(
1126 venue.as_ref(),
1127 instrument_id.as_ref(),
1128 strategy_id.as_ref(),
1129 account_id.as_ref(),
1130 side,
1131 )
1132 }
1133
1134 #[pyo3(name = "strategy_id_for_order")]
1135 fn py_strategy_id_for_order(&self, client_order_id: ClientOrderId) -> Option<StrategyId> {
1136 self.0
1137 .borrow()
1138 .strategy_id_for_order(&client_order_id)
1139 .copied()
1140 }
1141
1142 #[pyo3(name = "strategy_id_for_position")]
1143 fn py_strategy_id_for_position(&self, position_id: PositionId) -> Option<StrategyId> {
1144 self.0
1145 .borrow()
1146 .strategy_id_for_position(&position_id)
1147 .copied()
1148 }
1149
1150 #[pyo3(name = "position_snapshot_bytes")]
1151 fn py_position_snapshot_bytes(&self, position_id: PositionId) -> Option<Vec<Vec<u8>>> {
1152 self.0.borrow().position_snapshot_bytes(&position_id)
1153 }
1154
1155 #[pyo3(name = "snapshot_position")]
1156 #[expect(clippy::needless_pass_by_value)]
1157 fn py_snapshot_position(&self, py: Python, position: Py<PyAny>) -> PyResult<()> {
1158 let position_obj = position.extract::<Position>(py)?;
1159 self.0
1160 .borrow_mut()
1161 .snapshot_position(&position_obj)
1162 .map(|_| ())
1163 .map_err(to_pyvalue_err)
1164 }
1165
1166 #[pyo3(name = "position_snapshots", signature = (position_id=None, account_id=None))]
1167 fn py_position_snapshots(
1168 &self,
1169 py: Python,
1170 position_id: Option<PositionId>,
1171 account_id: Option<AccountId>,
1172 ) -> PyResult<Vec<Py<PyAny>>> {
1173 let cache = self.0.borrow();
1174 cache
1175 .position_snapshots(position_id.as_ref(), account_id.as_ref())
1176 .into_iter()
1177 .map(|p| Ok(p.into_pyobject(py)?.into()))
1178 .collect()
1179 }
1180}
1181
1182#[cfg(feature = "defi")]
1183#[pymethods]
1184#[pyo3_stub_gen::derive::gen_stub_pymethods]
1185impl PyCache {
1186 #[pyo3(name = "pool")]
1187 fn py_pool(&self, instrument_id: InstrumentId) -> Option<Pool> {
1188 self.0
1189 .try_borrow()
1190 .ok()
1191 .and_then(|cache| cache.pool(&instrument_id).cloned())
1192 }
1193
1194 #[pyo3(name = "pool_profiler")]
1195 fn py_pool_profiler(&self, instrument_id: InstrumentId) -> Option<PoolProfiler> {
1196 self.0
1197 .try_borrow()
1198 .ok()
1199 .and_then(|cache| cache.pool_profiler(&instrument_id).cloned())
1200 }
1201}
1202
1203#[pymethods]
1204#[pyo3_stub_gen::derive::gen_stub_pymethods]
1205impl CacheConfig {
1206 #[new]
1208 #[expect(clippy::too_many_arguments)]
1209 #[pyo3(signature = (
1210 encoding=None,
1211 timestamps_as_iso8601=None,
1212 buffer_interval_ms=None,
1213 bulk_read_batch_size=None,
1214 use_trader_prefix=None,
1215 use_instance_id=None,
1216 flush_on_start=None,
1217 drop_instruments_on_reset=None,
1218 tick_capacity=None,
1219 bar_capacity=None,
1220 save_market_data=None,
1221 persist_account_events=None,
1222 ))]
1223 fn py_new(
1224 encoding: Option<SerializationEncoding>,
1225 timestamps_as_iso8601: Option<bool>,
1226 buffer_interval_ms: Option<usize>,
1227 bulk_read_batch_size: Option<usize>,
1228 use_trader_prefix: Option<bool>,
1229 use_instance_id: Option<bool>,
1230 flush_on_start: Option<bool>,
1231 drop_instruments_on_reset: Option<bool>,
1232 tick_capacity: Option<usize>,
1233 bar_capacity: Option<usize>,
1234 save_market_data: Option<bool>,
1235 persist_account_events: Option<bool>,
1236 ) -> PyResult<Self> {
1237 let config = Self {
1238 encoding: encoding.unwrap_or_default(),
1239 timestamps_as_iso8601: timestamps_as_iso8601.unwrap_or(false),
1240 buffer_interval_ms,
1241 bulk_read_batch_size,
1242 use_trader_prefix: use_trader_prefix.unwrap_or(true),
1243 use_instance_id: use_instance_id.unwrap_or(false),
1244 flush_on_start: flush_on_start.unwrap_or(false),
1245 drop_instruments_on_reset: drop_instruments_on_reset.unwrap_or(true),
1246 tick_capacity: tick_capacity.unwrap_or(10_000),
1247 bar_capacity: bar_capacity.unwrap_or(10_000),
1248 persist_account_events: persist_account_events.unwrap_or(true),
1249 save_market_data: save_market_data.unwrap_or(false),
1250 };
1251 config.validate().map_err(config_error_to_pyvalue_err)?;
1252 Ok(config)
1253 }
1254
1255 fn __str__(&self) -> String {
1256 format!("{self:?}")
1257 }
1258
1259 fn __repr__(&self) -> String {
1260 format!("{self:?}")
1261 }
1262
1263 #[getter]
1264 fn encoding(&self) -> SerializationEncoding {
1265 self.encoding
1266 }
1267
1268 #[getter]
1269 fn timestamps_as_iso8601(&self) -> bool {
1270 self.timestamps_as_iso8601
1271 }
1272
1273 #[getter]
1274 fn buffer_interval_ms(&self) -> Option<usize> {
1275 self.buffer_interval_ms
1276 }
1277
1278 #[getter]
1279 fn bulk_read_batch_size(&self) -> Option<usize> {
1280 self.bulk_read_batch_size
1281 }
1282
1283 #[getter]
1284 fn use_trader_prefix(&self) -> bool {
1285 self.use_trader_prefix
1286 }
1287
1288 #[getter]
1289 fn use_instance_id(&self) -> bool {
1290 self.use_instance_id
1291 }
1292
1293 #[getter]
1294 fn flush_on_start(&self) -> bool {
1295 self.flush_on_start
1296 }
1297
1298 #[getter]
1299 fn drop_instruments_on_reset(&self) -> bool {
1300 self.drop_instruments_on_reset
1301 }
1302
1303 #[getter]
1304 fn tick_capacity(&self) -> usize {
1305 self.tick_capacity
1306 }
1307
1308 #[getter]
1309 fn bar_capacity(&self) -> usize {
1310 self.bar_capacity
1311 }
1312
1313 #[getter]
1314 fn persist_account_events(&self) -> bool {
1315 self.persist_account_events
1316 }
1317
1318 #[getter]
1319 fn save_market_data(&self) -> bool {
1320 self.save_market_data
1321 }
1322}
1323
1324#[pymethods]
1325impl Cache {
1326 #[new]
1328 fn py_new(config: Option<CacheConfig>) -> Self {
1329 Self::new(config, None)
1330 }
1331
1332 fn __repr__(&self) -> String {
1333 format!("{self:?}")
1334 }
1335
1336 #[pyo3(name = "reset")]
1342 fn py_reset(&mut self) {
1343 self.reset();
1344 }
1345
1346 #[pyo3(name = "dispose")]
1350 fn py_dispose(&mut self) {
1351 self.dispose();
1352 }
1353
1354 #[pyo3(name = "purge_closed_orders", signature = (ts_now, buffer_secs=0))]
1360 fn py_purge_closed_orders(&mut self, ts_now: u64, buffer_secs: u64) {
1361 self.purge_closed_orders(ts_now.into(), buffer_secs);
1362 }
1363
1364 #[pyo3(name = "purge_closed_positions", signature = (ts_now, buffer_secs=0))]
1366 fn py_purge_closed_positions(&mut self, ts_now: u64, buffer_secs: u64) {
1367 self.purge_closed_positions(ts_now.into(), buffer_secs);
1368 }
1369
1370 #[pyo3(name = "purge_order")]
1374 fn py_purge_order(&mut self, client_order_id: ClientOrderId) {
1375 self.purge_order(client_order_id);
1376 }
1377
1378 #[pyo3(name = "purge_position")]
1382 fn py_purge_position(&mut self, position_id: PositionId) {
1383 self.purge_position(position_id);
1384 }
1385
1386 #[pyo3(name = "purge_instrument")]
1391 fn py_purge_instrument(&mut self, instrument_id: InstrumentId) {
1392 self.purge_instrument(instrument_id);
1393 }
1394
1395 #[pyo3(name = "purge_account_events", signature = (ts_now, lookback_secs=0))]
1400 fn py_purge_account_events(&mut self, ts_now: u64, lookback_secs: u64) {
1401 self.purge_account_events(ts_now.into(), lookback_secs);
1402 }
1403
1404 #[pyo3(name = "add_currency")]
1410 fn py_add_currency(&mut self, currency: Currency) -> PyResult<()> {
1411 self.add_currency(currency).map_err(to_pyvalue_err)
1412 }
1413
1414 #[pyo3(name = "add_instrument")]
1420 fn py_add_instrument(&mut self, py: Python, instrument: Py<PyAny>) -> PyResult<()> {
1421 let instrument_any = pyobject_to_instrument_any(py, instrument)?;
1422 self.add_instrument(instrument_any).map_err(to_pyvalue_err)
1423 }
1424
1425 #[pyo3(name = "instrument")]
1427 fn py_instrument(
1428 &self,
1429 py: Python,
1430 instrument_id: InstrumentId,
1431 ) -> PyResult<Option<Py<PyAny>>> {
1432 match self.instrument(&instrument_id) {
1433 Some(instrument) => Ok(Some(instrument_any_to_pyobject(py, instrument.clone())?)),
1434 None => Ok(None),
1435 }
1436 }
1437
1438 #[pyo3(name = "instrument_ids")]
1440 fn py_instrument_ids(&self, venue: Option<Venue>) -> Vec<InstrumentId> {
1441 self.instrument_ids(venue.as_ref())
1442 .into_iter()
1443 .copied()
1444 .collect()
1445 }
1446
1447 #[pyo3(name = "instruments")]
1449 fn py_instruments(&self, py: Python, venue: Option<Venue>) -> PyResult<Vec<Py<PyAny>>> {
1450 let mut py_instruments = Vec::new();
1451
1452 if let Some(venue) = venue {
1453 let instruments = self.instruments(&venue, None);
1454 for instrument in instruments {
1455 py_instruments.push(instrument_any_to_pyobject(py, (*instrument).clone())?);
1456 }
1457 } else {
1458 let instrument_ids = self.instrument_ids(None);
1459 for instrument_id in instrument_ids {
1460 if let Some(instrument) = self.instrument(instrument_id) {
1461 py_instruments.push(instrument_any_to_pyobject(py, instrument.clone())?);
1462 }
1463 }
1464 }
1465
1466 Ok(py_instruments)
1467 }
1468
1469 #[pyo3(name = "add_order")]
1477 fn py_add_order(
1478 &mut self,
1479 py: Python,
1480 order: Py<PyAny>,
1481 position_id: Option<PositionId>,
1482 client_id: Option<ClientId>,
1483 replace_existing: Option<bool>,
1484 ) -> PyResult<()> {
1485 let order_any = pyobject_to_order_any(py, order)?;
1486 self.add_order(
1487 order_any,
1488 position_id,
1489 client_id,
1490 replace_existing.unwrap_or(false),
1491 )
1492 .map_err(to_pyvalue_err)
1493 }
1494
1495 #[pyo3(name = "order")]
1499 fn py_order(&self, py: Python, client_order_id: ClientOrderId) -> PyResult<Option<Py<PyAny>>> {
1500 match self.order(&client_order_id) {
1501 Some(order) => Ok(Some(order_any_to_pyobject(py, order.clone())?)),
1502 None => Ok(None),
1503 }
1504 }
1505
1506 #[pyo3(name = "order_exists")]
1508 fn py_order_exists(&self, client_order_id: ClientOrderId) -> bool {
1509 self.order_exists(&client_order_id)
1510 }
1511
1512 #[pyo3(name = "is_order_open")]
1514 fn py_is_order_open(&self, client_order_id: ClientOrderId) -> bool {
1515 self.is_order_open(&client_order_id)
1516 }
1517
1518 #[pyo3(name = "is_order_closed")]
1520 fn py_is_order_closed(&self, client_order_id: ClientOrderId) -> bool {
1521 self.is_order_closed(&client_order_id)
1522 }
1523
1524 #[pyo3(name = "is_order_active_local")]
1529 fn py_is_order_active_local(&self, client_order_id: ClientOrderId) -> bool {
1530 self.is_order_active_local(&client_order_id)
1531 }
1532
1533 #[pyo3(name = "orders_active_local")]
1537 fn py_orders_active_local(
1538 &self,
1539 py: Python,
1540 venue: Option<Venue>,
1541 instrument_id: Option<InstrumentId>,
1542 strategy_id: Option<StrategyId>,
1543 account_id: Option<AccountId>,
1544 side: Option<OrderSide>,
1545 ) -> PyResult<Vec<Py<PyAny>>> {
1546 self.orders_active_local(
1547 venue.as_ref(),
1548 instrument_id.as_ref(),
1549 strategy_id.as_ref(),
1550 account_id.as_ref(),
1551 side,
1552 )
1553 .into_iter()
1554 .map(|order| order_any_to_pyobject(py, order.clone()))
1555 .collect()
1556 }
1557
1558 #[pyo3(name = "orders_active_local_count")]
1563 fn py_orders_active_local_count(
1564 &self,
1565 venue: Option<Venue>,
1566 instrument_id: Option<InstrumentId>,
1567 strategy_id: Option<StrategyId>,
1568 account_id: Option<AccountId>,
1569 side: Option<OrderSide>,
1570 ) -> usize {
1571 self.orders_active_local_count(
1572 venue.as_ref(),
1573 instrument_id.as_ref(),
1574 strategy_id.as_ref(),
1575 account_id.as_ref(),
1576 side,
1577 )
1578 }
1579
1580 #[pyo3(name = "orders_open_count")]
1582 fn py_orders_open_count(
1583 &self,
1584 venue: Option<Venue>,
1585 instrument_id: Option<InstrumentId>,
1586 strategy_id: Option<StrategyId>,
1587 account_id: Option<AccountId>,
1588 side: Option<OrderSide>,
1589 ) -> usize {
1590 self.orders_open_count(
1591 venue.as_ref(),
1592 instrument_id.as_ref(),
1593 strategy_id.as_ref(),
1594 account_id.as_ref(),
1595 side,
1596 )
1597 }
1598
1599 #[pyo3(name = "orders_closed_count")]
1601 fn py_orders_closed_count(
1602 &self,
1603 venue: Option<Venue>,
1604 instrument_id: Option<InstrumentId>,
1605 strategy_id: Option<StrategyId>,
1606 account_id: Option<AccountId>,
1607 side: Option<OrderSide>,
1608 ) -> usize {
1609 self.orders_closed_count(
1610 venue.as_ref(),
1611 instrument_id.as_ref(),
1612 strategy_id.as_ref(),
1613 account_id.as_ref(),
1614 side,
1615 )
1616 }
1617
1618 #[pyo3(name = "orders_total_count")]
1620 fn py_orders_total_count(
1621 &self,
1622 venue: Option<Venue>,
1623 instrument_id: Option<InstrumentId>,
1624 strategy_id: Option<StrategyId>,
1625 account_id: Option<AccountId>,
1626 side: Option<OrderSide>,
1627 ) -> usize {
1628 self.orders_total_count(
1629 venue.as_ref(),
1630 instrument_id.as_ref(),
1631 strategy_id.as_ref(),
1632 account_id.as_ref(),
1633 side,
1634 )
1635 }
1636
1637 #[pyo3(name = "add_position")]
1639 #[expect(clippy::needless_pass_by_value)]
1640 fn py_add_position(
1641 &mut self,
1642 py: Python,
1643 position: Py<PyAny>,
1644 oms_type: OmsType,
1645 ) -> PyResult<()> {
1646 let position_obj = position.extract::<Position>(py)?;
1647 self.add_position(&position_obj, oms_type)
1648 .map_err(to_pyvalue_err)
1649 }
1650
1651 #[pyo3(name = "snapshot_position")]
1658 #[expect(clippy::needless_pass_by_value)]
1659 fn py_snapshot_position(&mut self, py: Python, position: Py<PyAny>) -> PyResult<()> {
1660 let position_obj = position.extract::<Position>(py)?;
1661 self.snapshot_position(&position_obj)
1662 .map(|_| ())
1663 .map_err(to_pyvalue_err)
1664 }
1665
1666 #[pyo3(name = "position")]
1670 fn py_position(&self, py: Python, position_id: PositionId) -> PyResult<Option<Py<PyAny>>> {
1671 match self.position(&position_id) {
1672 Some(position) => Ok(Some(position.clone().into_pyobject(py)?.into())),
1673 None => Ok(None),
1674 }
1675 }
1676
1677 #[pyo3(name = "position_exists")]
1679 fn py_position_exists(&self, position_id: PositionId) -> bool {
1680 self.position_exists(&position_id)
1681 }
1682
1683 #[pyo3(name = "is_position_open")]
1685 fn py_is_position_open(&self, position_id: PositionId) -> bool {
1686 self.is_position_open(&position_id)
1687 }
1688
1689 #[pyo3(name = "is_position_closed")]
1691 fn py_is_position_closed(&self, position_id: PositionId) -> bool {
1692 self.is_position_closed(&position_id)
1693 }
1694
1695 #[pyo3(name = "positions_open_count")]
1697 fn py_positions_open_count(
1698 &self,
1699 venue: Option<Venue>,
1700 instrument_id: Option<InstrumentId>,
1701 strategy_id: Option<StrategyId>,
1702 account_id: Option<AccountId>,
1703 side: Option<PositionSide>,
1704 ) -> usize {
1705 self.positions_open_count(
1706 venue.as_ref(),
1707 instrument_id.as_ref(),
1708 strategy_id.as_ref(),
1709 account_id.as_ref(),
1710 side,
1711 )
1712 }
1713
1714 #[pyo3(name = "positions_closed_count")]
1716 fn py_positions_closed_count(
1717 &self,
1718 venue: Option<Venue>,
1719 instrument_id: Option<InstrumentId>,
1720 strategy_id: Option<StrategyId>,
1721 account_id: Option<AccountId>,
1722 side: Option<PositionSide>,
1723 ) -> usize {
1724 self.positions_closed_count(
1725 venue.as_ref(),
1726 instrument_id.as_ref(),
1727 strategy_id.as_ref(),
1728 account_id.as_ref(),
1729 side,
1730 )
1731 }
1732
1733 #[pyo3(name = "positions_total_count")]
1735 fn py_positions_total_count(
1736 &self,
1737 venue: Option<Venue>,
1738 instrument_id: Option<InstrumentId>,
1739 strategy_id: Option<StrategyId>,
1740 account_id: Option<AccountId>,
1741 side: Option<PositionSide>,
1742 ) -> usize {
1743 self.positions_total_count(
1744 venue.as_ref(),
1745 instrument_id.as_ref(),
1746 strategy_id.as_ref(),
1747 account_id.as_ref(),
1748 side,
1749 )
1750 }
1751
1752 #[pyo3(name = "add_quote")]
1758 fn py_add_quote(&mut self, quote: QuoteTick) -> PyResult<()> {
1759 self.add_quote(quote).map_err(to_pyvalue_err)
1760 }
1761
1762 #[pyo3(name = "add_trade")]
1768 fn py_add_trade(&mut self, trade: TradeTick) -> PyResult<()> {
1769 self.add_trade(trade).map_err(to_pyvalue_err)
1770 }
1771
1772 #[pyo3(name = "add_bar")]
1778 fn py_add_bar(&mut self, bar: Bar) -> PyResult<()> {
1779 self.add_bar(bar).map_err(to_pyvalue_err)
1780 }
1781
1782 #[pyo3(name = "quote")]
1784 fn py_quote(&self, instrument_id: InstrumentId) -> Option<QuoteTick> {
1785 self.quote(&instrument_id).copied()
1786 }
1787
1788 #[pyo3(name = "trade")]
1790 fn py_trade(&self, instrument_id: InstrumentId) -> Option<TradeTick> {
1791 self.trade(&instrument_id).copied()
1792 }
1793
1794 #[pyo3(name = "bar")]
1796 fn py_bar(&self, bar_type: BarType) -> Option<Bar> {
1797 self.bar(&bar_type).copied()
1798 }
1799
1800 #[pyo3(name = "quotes")]
1802 fn py_quotes(&self, instrument_id: InstrumentId) -> Option<Vec<QuoteTick>> {
1803 self.quotes(&instrument_id)
1804 }
1805
1806 #[pyo3(name = "trades")]
1808 fn py_trades(&self, instrument_id: InstrumentId) -> Option<Vec<TradeTick>> {
1809 self.trades(&instrument_id)
1810 }
1811
1812 #[pyo3(name = "bars")]
1814 fn py_bars(&self, bar_type: BarType) -> Option<Vec<Bar>> {
1815 self.bars(&bar_type)
1816 }
1817
1818 #[pyo3(name = "has_quote_ticks")]
1820 fn py_has_quote_ticks(&self, instrument_id: InstrumentId) -> bool {
1821 self.has_quote_ticks(&instrument_id)
1822 }
1823
1824 #[pyo3(name = "has_trade_ticks")]
1826 fn py_has_trade_ticks(&self, instrument_id: InstrumentId) -> bool {
1827 self.has_trade_ticks(&instrument_id)
1828 }
1829
1830 #[pyo3(name = "has_bars")]
1832 fn py_has_bars(&self, bar_type: BarType) -> bool {
1833 self.has_bars(&bar_type)
1834 }
1835
1836 #[pyo3(name = "quote_count")]
1838 fn py_quote_count(&self, instrument_id: InstrumentId) -> usize {
1839 self.quote_count(&instrument_id)
1840 }
1841
1842 #[pyo3(name = "trade_count")]
1844 fn py_trade_count(&self, instrument_id: InstrumentId) -> usize {
1845 self.trade_count(&instrument_id)
1846 }
1847
1848 #[pyo3(name = "bar_count")]
1850 fn py_bar_count(&self, bar_type: BarType) -> usize {
1851 self.bar_count(&bar_type)
1852 }
1853
1854 #[pyo3(name = "mark_price")]
1856 fn py_mark_price(&self, instrument_id: InstrumentId) -> Option<MarkPriceUpdate> {
1857 self.mark_price(&instrument_id).copied()
1858 }
1859
1860 #[pyo3(name = "mark_prices")]
1862 fn py_mark_prices(&self, instrument_id: InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
1863 self.mark_prices(&instrument_id)
1864 }
1865
1866 #[pyo3(name = "index_price")]
1868 fn py_index_price(&self, instrument_id: InstrumentId) -> Option<IndexPriceUpdate> {
1869 self.index_price(&instrument_id).copied()
1870 }
1871
1872 #[pyo3(name = "index_prices")]
1874 fn py_index_prices(&self, instrument_id: InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
1875 self.index_prices(&instrument_id)
1876 }
1877
1878 #[pyo3(name = "funding_rate")]
1880 fn py_funding_rate(&self, instrument_id: InstrumentId) -> Option<FundingRateUpdate> {
1881 self.funding_rate(&instrument_id).copied()
1882 }
1883
1884 #[pyo3(name = "instrument_status")]
1886 fn py_instrument_status(&self, instrument_id: InstrumentId) -> Option<InstrumentStatus> {
1887 self.instrument_status(&instrument_id).copied()
1888 }
1889
1890 #[pyo3(name = "instrument_statuses")]
1892 fn py_instrument_statuses(&self, instrument_id: InstrumentId) -> Option<Vec<InstrumentStatus>> {
1893 self.instrument_statuses(&instrument_id)
1894 }
1895
1896 #[pyo3(name = "order_book")]
1898 fn py_order_book(&self, instrument_id: InstrumentId) -> Option<OrderBook> {
1899 self.order_book(&instrument_id).cloned()
1900 }
1901
1902 #[pyo3(name = "has_order_book")]
1904 fn py_has_order_book(&self, instrument_id: InstrumentId) -> bool {
1905 self.has_order_book(&instrument_id)
1906 }
1907
1908 #[pyo3(name = "book_update_count")]
1910 fn py_book_update_count(&self, instrument_id: InstrumentId) -> usize {
1911 self.book_update_count(&instrument_id)
1912 }
1913
1914 #[pyo3(name = "synthetic")]
1916 fn py_synthetic(&self, instrument_id: InstrumentId) -> Option<SyntheticInstrument> {
1917 self.synthetic(&instrument_id).cloned()
1918 }
1919
1920 #[pyo3(name = "synthetic_ids")]
1922 fn py_synthetic_ids(&self) -> Vec<InstrumentId> {
1923 self.synthetic_ids().into_iter().copied().collect()
1924 }
1925
1926 #[pyo3(name = "client_order_ids")]
1928 fn py_client_order_ids(
1929 &self,
1930 venue: Option<Venue>,
1931 instrument_id: Option<InstrumentId>,
1932 strategy_id: Option<StrategyId>,
1933 account_id: Option<AccountId>,
1934 ) -> Vec<ClientOrderId> {
1935 self.client_order_ids(
1936 venue.as_ref(),
1937 instrument_id.as_ref(),
1938 strategy_id.as_ref(),
1939 account_id.as_ref(),
1940 )
1941 .into_iter()
1942 .collect()
1943 }
1944
1945 #[pyo3(name = "client_order_ids_open")]
1947 fn py_client_order_ids_open(
1948 &self,
1949 venue: Option<Venue>,
1950 instrument_id: Option<InstrumentId>,
1951 strategy_id: Option<StrategyId>,
1952 account_id: Option<AccountId>,
1953 ) -> Vec<ClientOrderId> {
1954 self.client_order_ids_open(
1955 venue.as_ref(),
1956 instrument_id.as_ref(),
1957 strategy_id.as_ref(),
1958 account_id.as_ref(),
1959 )
1960 .into_iter()
1961 .collect()
1962 }
1963
1964 #[pyo3(name = "client_order_ids_closed")]
1966 fn py_client_order_ids_closed(
1967 &self,
1968 venue: Option<Venue>,
1969 instrument_id: Option<InstrumentId>,
1970 strategy_id: Option<StrategyId>,
1971 account_id: Option<AccountId>,
1972 ) -> Vec<ClientOrderId> {
1973 self.client_order_ids_closed(
1974 venue.as_ref(),
1975 instrument_id.as_ref(),
1976 strategy_id.as_ref(),
1977 account_id.as_ref(),
1978 )
1979 .into_iter()
1980 .collect()
1981 }
1982
1983 #[pyo3(name = "client_order_ids_emulated")]
1985 fn py_client_order_ids_emulated(
1986 &self,
1987 venue: Option<Venue>,
1988 instrument_id: Option<InstrumentId>,
1989 strategy_id: Option<StrategyId>,
1990 account_id: Option<AccountId>,
1991 ) -> Vec<ClientOrderId> {
1992 self.client_order_ids_emulated(
1993 venue.as_ref(),
1994 instrument_id.as_ref(),
1995 strategy_id.as_ref(),
1996 account_id.as_ref(),
1997 )
1998 .into_iter()
1999 .collect()
2000 }
2001
2002 #[pyo3(name = "client_order_ids_inflight")]
2004 fn py_client_order_ids_inflight(
2005 &self,
2006 venue: Option<Venue>,
2007 instrument_id: Option<InstrumentId>,
2008 strategy_id: Option<StrategyId>,
2009 account_id: Option<AccountId>,
2010 ) -> Vec<ClientOrderId> {
2011 self.client_order_ids_inflight(
2012 venue.as_ref(),
2013 instrument_id.as_ref(),
2014 strategy_id.as_ref(),
2015 account_id.as_ref(),
2016 )
2017 .into_iter()
2018 .collect()
2019 }
2020
2021 #[pyo3(name = "position_ids")]
2023 fn py_position_ids(
2024 &self,
2025 venue: Option<Venue>,
2026 instrument_id: Option<InstrumentId>,
2027 strategy_id: Option<StrategyId>,
2028 account_id: Option<AccountId>,
2029 ) -> Vec<PositionId> {
2030 self.position_ids(
2031 venue.as_ref(),
2032 instrument_id.as_ref(),
2033 strategy_id.as_ref(),
2034 account_id.as_ref(),
2035 )
2036 .into_iter()
2037 .collect()
2038 }
2039
2040 #[pyo3(name = "position_open_ids")]
2042 fn py_position_open_ids(
2043 &self,
2044 venue: Option<Venue>,
2045 instrument_id: Option<InstrumentId>,
2046 strategy_id: Option<StrategyId>,
2047 account_id: Option<AccountId>,
2048 ) -> Vec<PositionId> {
2049 self.position_open_ids(
2050 venue.as_ref(),
2051 instrument_id.as_ref(),
2052 strategy_id.as_ref(),
2053 account_id.as_ref(),
2054 )
2055 .into_iter()
2056 .collect()
2057 }
2058
2059 #[pyo3(name = "position_closed_ids")]
2061 fn py_position_closed_ids(
2062 &self,
2063 venue: Option<Venue>,
2064 instrument_id: Option<InstrumentId>,
2065 strategy_id: Option<StrategyId>,
2066 account_id: Option<AccountId>,
2067 ) -> Vec<PositionId> {
2068 self.position_closed_ids(
2069 venue.as_ref(),
2070 instrument_id.as_ref(),
2071 strategy_id.as_ref(),
2072 account_id.as_ref(),
2073 )
2074 .into_iter()
2075 .collect()
2076 }
2077
2078 #[pyo3(name = "actor_ids")]
2080 fn py_actor_ids(&self) -> Vec<ComponentId> {
2081 self.actor_ids().into_iter().collect()
2082 }
2083
2084 #[pyo3(name = "strategy_ids")]
2086 fn py_strategy_ids(&self) -> Vec<StrategyId> {
2087 self.strategy_ids().into_iter().collect()
2088 }
2089
2090 #[pyo3(name = "exec_algorithm_ids")]
2092 fn py_exec_algorithm_ids(&self) -> Vec<ExecAlgorithmId> {
2093 self.exec_algorithm_ids().into_iter().collect()
2094 }
2095
2096 #[pyo3(name = "client_order_id")]
2098 fn py_client_order_id(&self, venue_order_id: VenueOrderId) -> Option<ClientOrderId> {
2099 self.client_order_id(&venue_order_id).copied()
2100 }
2101
2102 #[pyo3(name = "venue_order_id")]
2104 fn py_venue_order_id(&self, client_order_id: ClientOrderId) -> Option<VenueOrderId> {
2105 self.venue_order_id(&client_order_id).copied()
2106 }
2107
2108 #[pyo3(name = "client_id")]
2110 fn py_client_id(&self, client_order_id: ClientOrderId) -> Option<ClientId> {
2111 self.client_id(&client_order_id).copied()
2112 }
2113
2114 #[pyo3(name = "orders")]
2118 fn py_orders(
2119 &self,
2120 py: Python,
2121 venue: Option<Venue>,
2122 instrument_id: Option<InstrumentId>,
2123 strategy_id: Option<StrategyId>,
2124 account_id: Option<AccountId>,
2125 side: Option<OrderSide>,
2126 ) -> PyResult<Vec<Py<PyAny>>> {
2127 self.orders(
2128 venue.as_ref(),
2129 instrument_id.as_ref(),
2130 strategy_id.as_ref(),
2131 account_id.as_ref(),
2132 side,
2133 )
2134 .into_iter()
2135 .map(|o| order_any_to_pyobject(py, o.clone()))
2136 .collect()
2137 }
2138
2139 #[pyo3(name = "orders_open")]
2143 fn py_orders_open(
2144 &self,
2145 py: Python,
2146 venue: Option<Venue>,
2147 instrument_id: Option<InstrumentId>,
2148 strategy_id: Option<StrategyId>,
2149 account_id: Option<AccountId>,
2150 side: Option<OrderSide>,
2151 ) -> PyResult<Vec<Py<PyAny>>> {
2152 self.orders_open(
2153 venue.as_ref(),
2154 instrument_id.as_ref(),
2155 strategy_id.as_ref(),
2156 account_id.as_ref(),
2157 side,
2158 )
2159 .into_iter()
2160 .map(|o| order_any_to_pyobject(py, o.clone()))
2161 .collect()
2162 }
2163
2164 #[pyo3(name = "orders_closed")]
2168 fn py_orders_closed(
2169 &self,
2170 py: Python,
2171 venue: Option<Venue>,
2172 instrument_id: Option<InstrumentId>,
2173 strategy_id: Option<StrategyId>,
2174 account_id: Option<AccountId>,
2175 side: Option<OrderSide>,
2176 ) -> PyResult<Vec<Py<PyAny>>> {
2177 self.orders_closed(
2178 venue.as_ref(),
2179 instrument_id.as_ref(),
2180 strategy_id.as_ref(),
2181 account_id.as_ref(),
2182 side,
2183 )
2184 .into_iter()
2185 .map(|o| order_any_to_pyobject(py, o.clone()))
2186 .collect()
2187 }
2188
2189 #[pyo3(name = "orders_emulated")]
2193 fn py_orders_emulated(
2194 &self,
2195 py: Python,
2196 venue: Option<Venue>,
2197 instrument_id: Option<InstrumentId>,
2198 strategy_id: Option<StrategyId>,
2199 account_id: Option<AccountId>,
2200 side: Option<OrderSide>,
2201 ) -> PyResult<Vec<Py<PyAny>>> {
2202 self.orders_emulated(
2203 venue.as_ref(),
2204 instrument_id.as_ref(),
2205 strategy_id.as_ref(),
2206 account_id.as_ref(),
2207 side,
2208 )
2209 .into_iter()
2210 .map(|o| order_any_to_pyobject(py, o.clone()))
2211 .collect()
2212 }
2213
2214 #[pyo3(name = "orders_inflight")]
2218 fn py_orders_inflight(
2219 &self,
2220 py: Python,
2221 venue: Option<Venue>,
2222 instrument_id: Option<InstrumentId>,
2223 strategy_id: Option<StrategyId>,
2224 account_id: Option<AccountId>,
2225 side: Option<OrderSide>,
2226 ) -> PyResult<Vec<Py<PyAny>>> {
2227 self.orders_inflight(
2228 venue.as_ref(),
2229 instrument_id.as_ref(),
2230 strategy_id.as_ref(),
2231 account_id.as_ref(),
2232 side,
2233 )
2234 .into_iter()
2235 .map(|o| order_any_to_pyobject(py, o.clone()))
2236 .collect()
2237 }
2238
2239 #[pyo3(name = "orders_for_position")]
2241 fn py_orders_for_position(
2242 &self,
2243 py: Python,
2244 position_id: PositionId,
2245 ) -> PyResult<Vec<Py<PyAny>>> {
2246 self.orders_for_position(&position_id)
2247 .into_iter()
2248 .map(|o| order_any_to_pyobject(py, o.clone()))
2249 .collect()
2250 }
2251
2252 #[pyo3(name = "is_order_emulated")]
2254 fn py_is_order_emulated(&self, client_order_id: ClientOrderId) -> bool {
2255 self.is_order_emulated(&client_order_id)
2256 }
2257
2258 #[pyo3(name = "is_order_inflight")]
2260 fn py_is_order_inflight(&self, client_order_id: ClientOrderId) -> bool {
2261 self.is_order_inflight(&client_order_id)
2262 }
2263
2264 #[pyo3(name = "is_order_pending_cancel_local")]
2266 fn py_is_order_pending_cancel_local(&self, client_order_id: ClientOrderId) -> bool {
2267 self.is_order_pending_cancel_local(&client_order_id)
2268 }
2269
2270 #[pyo3(name = "orders_emulated_count")]
2272 fn py_orders_emulated_count(
2273 &self,
2274 venue: Option<Venue>,
2275 instrument_id: Option<InstrumentId>,
2276 strategy_id: Option<StrategyId>,
2277 account_id: Option<AccountId>,
2278 side: Option<OrderSide>,
2279 ) -> usize {
2280 self.orders_emulated_count(
2281 venue.as_ref(),
2282 instrument_id.as_ref(),
2283 strategy_id.as_ref(),
2284 account_id.as_ref(),
2285 side,
2286 )
2287 }
2288
2289 #[pyo3(name = "orders_inflight_count")]
2291 fn py_orders_inflight_count(
2292 &self,
2293 venue: Option<Venue>,
2294 instrument_id: Option<InstrumentId>,
2295 strategy_id: Option<StrategyId>,
2296 account_id: Option<AccountId>,
2297 side: Option<OrderSide>,
2298 ) -> usize {
2299 self.orders_inflight_count(
2300 venue.as_ref(),
2301 instrument_id.as_ref(),
2302 strategy_id.as_ref(),
2303 account_id.as_ref(),
2304 side,
2305 )
2306 }
2307
2308 #[pyo3(name = "order_list")]
2310 fn py_order_list(&self, order_list_id: OrderListId) -> Option<OrderList> {
2311 self.order_list(&order_list_id).cloned()
2312 }
2313
2314 #[pyo3(name = "order_lists")]
2316 fn py_order_lists(
2317 &self,
2318 venue: Option<Venue>,
2319 instrument_id: Option<InstrumentId>,
2320 strategy_id: Option<StrategyId>,
2321 account_id: Option<AccountId>,
2322 ) -> Vec<OrderList> {
2323 self.order_lists(
2324 venue.as_ref(),
2325 instrument_id.as_ref(),
2326 strategy_id.as_ref(),
2327 account_id.as_ref(),
2328 )
2329 .into_iter()
2330 .cloned()
2331 .collect()
2332 }
2333
2334 #[pyo3(name = "order_list_exists")]
2336 fn py_order_list_exists(&self, order_list_id: OrderListId) -> bool {
2337 self.order_list_exists(&order_list_id)
2338 }
2339
2340 #[pyo3(name = "orders_for_exec_algorithm")]
2343 #[expect(clippy::too_many_arguments)]
2344 fn py_orders_for_exec_algorithm(
2345 &self,
2346 py: Python,
2347 exec_algorithm_id: ExecAlgorithmId,
2348 venue: Option<Venue>,
2349 instrument_id: Option<InstrumentId>,
2350 strategy_id: Option<StrategyId>,
2351 account_id: Option<AccountId>,
2352 side: Option<OrderSide>,
2353 ) -> PyResult<Vec<Py<PyAny>>> {
2354 self.orders_for_exec_algorithm(
2355 &exec_algorithm_id,
2356 venue.as_ref(),
2357 instrument_id.as_ref(),
2358 strategy_id.as_ref(),
2359 account_id.as_ref(),
2360 side,
2361 )
2362 .into_iter()
2363 .map(|o| order_any_to_pyobject(py, o.clone()))
2364 .collect()
2365 }
2366
2367 #[pyo3(name = "orders_for_exec_spawn")]
2369 fn py_orders_for_exec_spawn(
2370 &self,
2371 py: Python,
2372 exec_spawn_id: ClientOrderId,
2373 ) -> PyResult<Vec<Py<PyAny>>> {
2374 self.orders_for_exec_spawn(&exec_spawn_id)
2375 .into_iter()
2376 .map(|o| order_any_to_pyobject(py, o.clone()))
2377 .collect()
2378 }
2379
2380 #[pyo3(name = "exec_spawn_total_quantity")]
2382 fn py_exec_spawn_total_quantity(
2383 &self,
2384 exec_spawn_id: ClientOrderId,
2385 active_only: bool,
2386 ) -> Option<Quantity> {
2387 self.exec_spawn_total_quantity(&exec_spawn_id, active_only)
2388 }
2389
2390 #[pyo3(name = "exec_spawn_total_filled_qty")]
2392 fn py_exec_spawn_total_filled_qty(
2393 &self,
2394 exec_spawn_id: ClientOrderId,
2395 active_only: bool,
2396 ) -> Option<Quantity> {
2397 self.exec_spawn_total_filled_qty(&exec_spawn_id, active_only)
2398 }
2399
2400 #[pyo3(name = "exec_spawn_total_leaves_qty")]
2402 fn py_exec_spawn_total_leaves_qty(
2403 &self,
2404 exec_spawn_id: ClientOrderId,
2405 active_only: bool,
2406 ) -> Option<Quantity> {
2407 self.exec_spawn_total_leaves_qty(&exec_spawn_id, active_only)
2408 }
2409
2410 #[pyo3(name = "position_for_order")]
2414 fn py_position_for_order(
2415 &self,
2416 py: Python,
2417 client_order_id: ClientOrderId,
2418 ) -> PyResult<Option<Py<PyAny>>> {
2419 match self.position_for_order(&client_order_id) {
2420 Some(position) => Ok(Some(position.clone().into_pyobject(py)?.into())),
2421 None => Ok(None),
2422 }
2423 }
2424
2425 #[pyo3(name = "position_id")]
2427 fn py_position_id(&self, client_order_id: ClientOrderId) -> Option<PositionId> {
2428 self.position_id(&client_order_id).copied()
2429 }
2430
2431 #[pyo3(name = "positions")]
2435 fn py_positions(
2436 &self,
2437 py: Python,
2438 venue: Option<Venue>,
2439 instrument_id: Option<InstrumentId>,
2440 strategy_id: Option<StrategyId>,
2441 account_id: Option<AccountId>,
2442 side: Option<PositionSide>,
2443 ) -> PyResult<Vec<Py<PyAny>>> {
2444 self.positions(
2445 venue.as_ref(),
2446 instrument_id.as_ref(),
2447 strategy_id.as_ref(),
2448 account_id.as_ref(),
2449 side,
2450 )
2451 .into_iter()
2452 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
2453 .collect()
2454 }
2455
2456 #[pyo3(name = "positions_open")]
2460 fn py_positions_open(
2461 &self,
2462 py: Python,
2463 venue: Option<Venue>,
2464 instrument_id: Option<InstrumentId>,
2465 strategy_id: Option<StrategyId>,
2466 account_id: Option<AccountId>,
2467 side: Option<PositionSide>,
2468 ) -> PyResult<Vec<Py<PyAny>>> {
2469 self.positions_open(
2470 venue.as_ref(),
2471 instrument_id.as_ref(),
2472 strategy_id.as_ref(),
2473 account_id.as_ref(),
2474 side,
2475 )
2476 .into_iter()
2477 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
2478 .collect()
2479 }
2480
2481 #[pyo3(name = "positions_closed")]
2485 fn py_positions_closed(
2486 &self,
2487 py: Python,
2488 venue: Option<Venue>,
2489 instrument_id: Option<InstrumentId>,
2490 strategy_id: Option<StrategyId>,
2491 account_id: Option<AccountId>,
2492 side: Option<PositionSide>,
2493 ) -> PyResult<Vec<Py<PyAny>>> {
2494 self.positions_closed(
2495 venue.as_ref(),
2496 instrument_id.as_ref(),
2497 strategy_id.as_ref(),
2498 account_id.as_ref(),
2499 side,
2500 )
2501 .into_iter()
2502 .map(|p| Ok(p.clone().into_pyobject(py)?.into()))
2503 .collect()
2504 }
2505
2506 #[pyo3(name = "strategy_id_for_order")]
2508 fn py_strategy_id_for_order(&self, client_order_id: ClientOrderId) -> Option<StrategyId> {
2509 self.strategy_id_for_order(&client_order_id).copied()
2510 }
2511
2512 #[pyo3(name = "strategy_id_for_position")]
2514 fn py_strategy_id_for_position(&self, position_id: PositionId) -> Option<StrategyId> {
2515 self.strategy_id_for_position(&position_id).copied()
2516 }
2517
2518 #[pyo3(name = "position_snapshot_bytes")]
2523 fn py_position_snapshot_bytes(&self, position_id: PositionId) -> Option<Vec<Vec<u8>>> {
2524 self.position_snapshot_bytes(&position_id)
2525 }
2526
2527 #[pyo3(name = "position_snapshots", signature = (position_id=None, account_id=None))]
2533 fn py_position_snapshots(
2534 &self,
2535 py: Python,
2536 position_id: Option<PositionId>,
2537 account_id: Option<AccountId>,
2538 ) -> PyResult<Vec<Py<PyAny>>> {
2539 self.position_snapshots(position_id.as_ref(), account_id.as_ref())
2540 .into_iter()
2541 .map(|p| Ok(p.into_pyobject(py)?.into()))
2542 .collect()
2543 }
2544
2545 #[pyo3(name = "account")]
2549 fn py_account(&self, py: Python, account_id: AccountId) -> PyResult<Option<Py<PyAny>>> {
2550 match self.account(&account_id) {
2551 Some(account) => Ok(Some(account_any_to_pyobject(py, account.clone())?)),
2552 None => Ok(None),
2553 }
2554 }
2555
2556 #[pyo3(name = "account_for_venue")]
2558 fn py_account_for_venue(&self, py: Python, venue: Venue) -> PyResult<Option<Py<PyAny>>> {
2559 match self.account_for_venue(&venue) {
2560 Some(account) => Ok(Some(account_any_to_pyobject(py, account.clone())?)),
2561 None => Ok(None),
2562 }
2563 }
2564
2565 #[pyo3(name = "account_id")]
2567 fn py_account_id(&self, venue: Venue) -> Option<AccountId> {
2568 self.account_id(&venue).copied()
2569 }
2570
2571 #[pyo3(name = "get")]
2577 fn py_get(&self, key: &str) -> PyResult<Option<Vec<u8>>> {
2578 match self.get(key).map_err(to_pyvalue_err)? {
2579 Some(bytes) => Ok(Some(bytes.to_vec())),
2580 None => Ok(None),
2581 }
2582 }
2583
2584 #[pyo3(name = "add")]
2586 fn py_add_general(&mut self, key: &str, value: Vec<u8>) -> PyResult<()> {
2587 self.add(key, Bytes::from(value)).map_err(to_pyvalue_err)
2588 }
2589
2590 #[pyo3(name = "price")]
2592 fn py_price(&self, instrument_id: InstrumentId, price_type: PriceType) -> Option<Price> {
2593 self.price(&instrument_id, price_type)
2594 }
2595
2596 #[pyo3(name = "get_xrate")]
2598 fn py_get_xrate(
2599 &self,
2600 venue: Venue,
2601 from_currency: Currency,
2602 to_currency: Currency,
2603 price_type: PriceType,
2604 ) -> Option<f64> {
2605 self.get_xrate(venue, from_currency, to_currency, price_type)
2606 .and_then(|rate| rate.to_f64())
2607 }
2608
2609 #[pyo3(name = "get_mark_xrate")]
2611 fn py_get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
2612 self.get_mark_xrate(from_currency, to_currency)
2613 }
2614
2615 #[pyo3(name = "set_mark_xrate")]
2617 fn py_set_mark_xrate(&mut self, from_currency: Currency, to_currency: Currency, xrate: f64) {
2618 self.set_mark_xrate(from_currency, to_currency, xrate);
2619 }
2620
2621 #[pyo3(name = "clear_mark_xrate")]
2623 fn py_clear_mark_xrate(&mut self, from_currency: Currency, to_currency: Currency) {
2624 self.clear_mark_xrate(from_currency, to_currency);
2625 }
2626
2627 #[pyo3(name = "clear_mark_xrates")]
2629 fn py_clear_mark_xrates(&mut self) {
2630 self.clear_mark_xrates();
2631 }
2632
2633 #[pyo3(name = "calculate_unrealized_pnl")]
2635 #[expect(clippy::needless_pass_by_value)]
2636 fn py_calculate_unrealized_pnl(
2637 &self,
2638 py: Python,
2639 position: Py<PyAny>,
2640 ) -> PyResult<Option<Money>> {
2641 let position = position.extract::<Position>(py)?;
2642 Ok(self.calculate_unrealized_pnl(&position))
2643 }
2644
2645 #[pyo3(name = "own_order_book")]
2647 fn py_own_order_book(&self, instrument_id: InstrumentId) -> Option<OwnOrderBook> {
2648 self.own_order_book(&instrument_id).cloned()
2649 }
2650
2651 #[pyo3(name = "update_own_order_book")]
2659 fn py_update_own_order_book(&mut self, py: Python, order: Py<PyAny>) -> PyResult<()> {
2660 let order_any = pyobject_to_order_any(py, order)?;
2661 self.update_own_order_book(&order_any);
2662 Ok(())
2663 }
2664
2665 #[pyo3(name = "force_remove_from_own_order_book")]
2671 fn py_force_remove_from_own_order_book(&mut self, client_order_id: ClientOrderId) {
2672 self.force_remove_from_own_order_book(&client_order_id);
2673 }
2674
2675 #[pyo3(name = "audit_own_order_books")]
2682 fn py_audit_own_order_books(&mut self) {
2683 self.audit_own_order_books();
2684 }
2685}
2686
2687#[cfg(feature = "defi")]
2688#[pymethods]
2689impl Cache {
2690 #[pyo3(name = "add_pool")]
2696 fn py_add_pool(&mut self, pool: Pool) -> PyResult<()> {
2697 self.add_pool(pool).map_err(to_pyvalue_err)
2698 }
2699
2700 #[pyo3(name = "pool")]
2702 fn py_pool(&self, instrument_id: InstrumentId) -> Option<Pool> {
2703 self.pool(&instrument_id).cloned()
2704 }
2705
2706 #[pyo3(name = "pool_ids")]
2708 fn py_pool_ids(&self, venue: Option<Venue>) -> Vec<InstrumentId> {
2709 self.pool_ids(venue.as_ref())
2710 }
2711
2712 #[pyo3(name = "pools")]
2714 fn py_pools(&self, venue: Option<Venue>) -> Vec<Pool> {
2715 self.pools(venue.as_ref()).into_iter().cloned().collect()
2716 }
2717
2718 #[pyo3(name = "add_pool_profiler")]
2724 fn py_add_pool_profiler(&mut self, pool_profiler: PoolProfiler) -> PyResult<()> {
2725 self.add_pool_profiler(pool_profiler)
2726 .map_err(to_pyvalue_err)
2727 }
2728
2729 #[pyo3(name = "pool_profiler")]
2731 fn py_pool_profiler(&self, instrument_id: InstrumentId) -> Option<PoolProfiler> {
2732 self.pool_profiler(&instrument_id).cloned()
2733 }
2734
2735 #[pyo3(name = "pool_profiler_ids")]
2737 fn py_pool_profiler_ids(&self, venue: Option<Venue>) -> Vec<InstrumentId> {
2738 self.pool_profiler_ids(venue.as_ref())
2739 }
2740
2741 #[pyo3(name = "pool_profilers")]
2743 fn py_pool_profilers(&self, venue: Option<Venue>) -> Vec<PoolProfiler> {
2744 self.pool_profilers(venue.as_ref())
2745 .into_iter()
2746 .cloned()
2747 .collect()
2748 }
2749}