nautilus_common/cache/api.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! User-facing read API over the platform cache.
17
18use std::{
19 cell::{Ref, RefCell},
20 fmt::Display,
21};
22
23use ahash::AHashSet;
24use bytes::Bytes;
25#[cfg(feature = "defi")]
26use nautilus_model::defi::{Pool, PoolProfiler};
27use nautilus_model::{
28 accounts::AccountAny,
29 data::{
30 Bar, BarType, FundingRateUpdate, GreeksData, IndexPriceUpdate, InstrumentClose,
31 InstrumentStatus, MarkPriceUpdate, QuoteTick, TradeTick, option_chain::OptionGreeks,
32 },
33 enums::{AggregationSource, InstrumentClass, OmsType, OrderSide, PositionSide, PriceType},
34 identifiers::{
35 AccountId, ClientId, ClientOrderId, ExecAlgorithmId, InstrumentId, OrderListId, PositionId,
36 StrategyId, Venue, VenueOrderId,
37 },
38 instruments::{InstrumentAny, SyntheticInstrument},
39 orderbook::{OrderBook, own::OwnOrderBook},
40 orders::{OrderAny, OrderList},
41 position::Position,
42 types::{Currency, Money, Price, Quantity},
43};
44use rust_decimal::Decimal;
45use ustr::Ustr;
46
47use super::{
48 Cache,
49 error::{
50 AccountLookupError, CurrencyLookupError, InstrumentLookupError, OrderBookLookupError,
51 OrderListLookupError, OrderLookupError, OwnOrderBookLookupError, PositionLookupError,
52 SyntheticInstrumentLookupError,
53 },
54};
55use crate::component::ComponentAccessError;
56
57/// User-facing cache API.
58///
59/// Point reads return owned snapshots where possible, so actor code does not retain a `Ref` into
60/// the live [`Cache`]. Plural collection reads return owned snapshots of all matching values and
61/// are intentionally named as bulk reads. Prefer the count, ID, or `has_*` methods in hot paths
62/// when a full snapshot is not needed.
63#[derive(Debug)]
64pub struct CacheApi<'a> {
65 cache: &'a RefCell<Cache>,
66}
67
68impl<'a> CacheApi<'a> {
69 pub(crate) fn new(cache: &'a RefCell<Cache>) -> Self {
70 Self { cache }
71 }
72
73 /// Returns the unrealized PnL for the `position` using cached market data.
74 ///
75 /// # Panics
76 ///
77 /// Panics if the cache is already mutably borrowed.
78 #[must_use]
79 pub fn calculate_unrealized_pnl(&self, position: &Position) -> Option<Money> {
80 self.cache().calculate_unrealized_pnl(position)
81 }
82
83 /// Returns the OMS type for the `position_id` (if known).
84 ///
85 /// # Panics
86 ///
87 /// Panics if the cache is already mutably borrowed.
88 #[must_use]
89 pub fn oms_type(&self, position_id: &PositionId) -> Option<OmsType> {
90 self.cache().oms_type(position_id)
91 }
92
93 /// Returns serialized position snapshot frames for the `position_id`.
94 ///
95 /// # Panics
96 ///
97 /// Panics if the cache is already mutably borrowed.
98 #[must_use]
99 pub fn position_snapshot_bytes(&self, position_id: &PositionId) -> Option<Vec<Vec<u8>>> {
100 self.cache().position_snapshot_bytes(position_id)
101 }
102
103 /// Returns the number of stored position snapshots for the `position_id`.
104 ///
105 /// # Panics
106 ///
107 /// Panics if the cache is already mutably borrowed.
108 #[must_use]
109 pub fn position_snapshot_count(&self, position_id: &PositionId) -> usize {
110 self.cache().position_snapshot_count(position_id)
111 }
112
113 /// Returns position snapshots matching the optional filters.
114 ///
115 /// # Panics
116 ///
117 /// Panics if the cache is already mutably borrowed.
118 #[must_use]
119 pub fn position_snapshots(
120 &self,
121 position_id: Option<&PositionId>,
122 account_id: Option<&AccountId>,
123 ) -> Vec<Position> {
124 self.cache().position_snapshots(position_id, account_id)
125 }
126
127 /// Returns position snapshots for `position_id` starting from `skip`.
128 ///
129 /// # Panics
130 ///
131 /// Panics if the cache is already mutably borrowed.
132 #[must_use]
133 pub fn position_snapshots_from(&self, position_id: &PositionId, skip: usize) -> Vec<Position> {
134 self.cache().position_snapshots_from(position_id, skip)
135 }
136
137 /// Returns position snapshot IDs for the `instrument_id`.
138 ///
139 /// # Panics
140 ///
141 /// Panics if the cache is already mutably borrowed.
142 #[must_use]
143 pub fn position_snapshot_ids(&self, instrument_id: &InstrumentId) -> AHashSet<PositionId> {
144 self.cache().position_snapshot_ids(instrument_id)
145 }
146
147 /// Returns the client order IDs of all orders matching the optional filter parameters.
148 ///
149 /// # Panics
150 ///
151 /// Panics if the cache is already mutably borrowed.
152 #[must_use]
153 pub fn client_order_ids(
154 &self,
155 venue: Option<&Venue>,
156 instrument_id: Option<&InstrumentId>,
157 strategy_id: Option<&StrategyId>,
158 account_id: Option<&AccountId>,
159 ) -> AHashSet<ClientOrderId> {
160 self.cache()
161 .client_order_ids(venue, instrument_id, strategy_id, account_id)
162 }
163
164 /// Returns the client order IDs of all open orders matching the optional filter parameters.
165 ///
166 /// # Panics
167 ///
168 /// Panics if the cache is already mutably borrowed.
169 #[must_use]
170 pub fn client_order_ids_open(
171 &self,
172 venue: Option<&Venue>,
173 instrument_id: Option<&InstrumentId>,
174 strategy_id: Option<&StrategyId>,
175 account_id: Option<&AccountId>,
176 ) -> AHashSet<ClientOrderId> {
177 self.cache()
178 .client_order_ids_open(venue, instrument_id, strategy_id, account_id)
179 }
180
181 /// Returns the client order IDs of all closed orders matching the optional filter parameters.
182 ///
183 /// # Panics
184 ///
185 /// Panics if the cache is already mutably borrowed.
186 #[must_use]
187 pub fn client_order_ids_closed(
188 &self,
189 venue: Option<&Venue>,
190 instrument_id: Option<&InstrumentId>,
191 strategy_id: Option<&StrategyId>,
192 account_id: Option<&AccountId>,
193 ) -> AHashSet<ClientOrderId> {
194 self.cache()
195 .client_order_ids_closed(venue, instrument_id, strategy_id, account_id)
196 }
197
198 /// Returns the client order IDs of all locally active orders matching the optional filter parameters.
199 ///
200 /// # Panics
201 ///
202 /// Panics if the cache is already mutably borrowed.
203 #[must_use]
204 pub fn client_order_ids_active_local(
205 &self,
206 venue: Option<&Venue>,
207 instrument_id: Option<&InstrumentId>,
208 strategy_id: Option<&StrategyId>,
209 account_id: Option<&AccountId>,
210 ) -> AHashSet<ClientOrderId> {
211 self.cache()
212 .client_order_ids_active_local(venue, instrument_id, strategy_id, account_id)
213 }
214
215 /// Returns the client order IDs of all emulated orders matching the optional filter parameters.
216 ///
217 /// # Panics
218 ///
219 /// Panics if the cache is already mutably borrowed.
220 #[must_use]
221 pub fn client_order_ids_emulated(
222 &self,
223 venue: Option<&Venue>,
224 instrument_id: Option<&InstrumentId>,
225 strategy_id: Option<&StrategyId>,
226 account_id: Option<&AccountId>,
227 ) -> AHashSet<ClientOrderId> {
228 self.cache()
229 .client_order_ids_emulated(venue, instrument_id, strategy_id, account_id)
230 }
231
232 /// Returns the client order IDs of all in-flight orders matching the optional filter parameters.
233 ///
234 /// # Panics
235 ///
236 /// Panics if the cache is already mutably borrowed.
237 #[must_use]
238 pub fn client_order_ids_inflight(
239 &self,
240 venue: Option<&Venue>,
241 instrument_id: Option<&InstrumentId>,
242 strategy_id: Option<&StrategyId>,
243 account_id: Option<&AccountId>,
244 ) -> AHashSet<ClientOrderId> {
245 self.cache()
246 .client_order_ids_inflight(venue, instrument_id, strategy_id, account_id)
247 }
248
249 /// Returns the position IDs of all positions matching the optional filter parameters.
250 ///
251 /// # Panics
252 ///
253 /// Panics if the cache is already mutably borrowed.
254 #[must_use]
255 pub fn position_ids(
256 &self,
257 venue: Option<&Venue>,
258 instrument_id: Option<&InstrumentId>,
259 strategy_id: Option<&StrategyId>,
260 account_id: Option<&AccountId>,
261 ) -> AHashSet<PositionId> {
262 self.cache()
263 .position_ids(venue, instrument_id, strategy_id, account_id)
264 }
265
266 /// Returns the position IDs of all open positions matching the optional filter parameters.
267 ///
268 /// # Panics
269 ///
270 /// Panics if the cache is already mutably borrowed.
271 #[must_use]
272 pub fn position_open_ids(
273 &self,
274 venue: Option<&Venue>,
275 instrument_id: Option<&InstrumentId>,
276 strategy_id: Option<&StrategyId>,
277 account_id: Option<&AccountId>,
278 ) -> AHashSet<PositionId> {
279 self.cache()
280 .position_open_ids(venue, instrument_id, strategy_id, account_id)
281 }
282
283 /// Returns the position IDs of all closed positions matching the optional filter parameters.
284 ///
285 /// # Panics
286 ///
287 /// Panics if the cache is already mutably borrowed.
288 #[must_use]
289 pub fn position_closed_ids(
290 &self,
291 venue: Option<&Venue>,
292 instrument_id: Option<&InstrumentId>,
293 strategy_id: Option<&StrategyId>,
294 account_id: Option<&AccountId>,
295 ) -> AHashSet<PositionId> {
296 self.cache()
297 .position_closed_ids(venue, instrument_id, strategy_id, account_id)
298 }
299
300 /// Returns the strategy IDs in the cache.
301 ///
302 /// # Panics
303 ///
304 /// Panics if the cache is already mutably borrowed.
305 #[must_use]
306 pub fn strategy_ids(&self) -> AHashSet<StrategyId> {
307 self.cache().strategy_ids()
308 }
309
310 /// Returns the execution algorithm IDs in the cache.
311 ///
312 /// # Panics
313 ///
314 /// Panics if the cache is already mutably borrowed.
315 #[must_use]
316 pub fn exec_algorithm_ids(&self) -> AHashSet<ExecAlgorithmId> {
317 self.cache().exec_algorithm_ids()
318 }
319
320 /// Returns an owned copy of the order for the `client_order_id` (if found).
321 ///
322 /// # Panics
323 ///
324 /// Panics if the cache is already mutably borrowed.
325 #[must_use]
326 pub fn order(&self, client_order_id: &ClientOrderId) -> Option<OrderAny> {
327 self.cache().order_owned(client_order_id)
328 }
329
330 /// Returns an owned copy of the order for the `client_order_id`.
331 ///
332 /// # Errors
333 ///
334 /// Returns:
335 /// - [`OrderLookupError::NotFound`] when the order is not present in the cache.
336 /// - [`OrderLookupError::Access`] if the cache is already mutably borrowed.
337 pub fn try_order(&self, client_order_id: &ClientOrderId) -> Result<OrderAny, OrderLookupError> {
338 self.try_cache("try_order")?
339 .try_order_owned(client_order_id)
340 }
341
342 /// Returns owned copies of the orders for `client_order_ids`.
343 ///
344 /// # Panics
345 ///
346 /// Panics if the cache is already mutably borrowed.
347 #[must_use]
348 pub fn orders_for_ids(
349 &self,
350 client_order_ids: &[ClientOrderId],
351 context: &dyn Display,
352 ) -> Vec<OrderAny> {
353 self.cache().orders_for_ids(client_order_ids, context)
354 }
355
356 /// Returns the client order ID for the `venue_order_id` (if found).
357 ///
358 /// # Panics
359 ///
360 /// Panics if the cache is already mutably borrowed.
361 #[must_use]
362 pub fn client_order_id(&self, venue_order_id: &VenueOrderId) -> Option<ClientOrderId> {
363 self.cache().client_order_id(venue_order_id).copied()
364 }
365
366 /// Returns the venue order ID for the `client_order_id` (if found).
367 ///
368 /// # Panics
369 ///
370 /// Panics if the cache is already mutably borrowed.
371 #[must_use]
372 pub fn venue_order_id(&self, client_order_id: &ClientOrderId) -> Option<VenueOrderId> {
373 self.cache().venue_order_id(client_order_id).copied()
374 }
375
376 /// Returns the client ID indexed for the `client_order_id` (if found).
377 ///
378 /// # Panics
379 ///
380 /// Panics if the cache is already mutably borrowed.
381 #[must_use]
382 pub fn client_id(&self, client_order_id: &ClientOrderId) -> Option<ClientId> {
383 self.cache().client_id(client_order_id).copied()
384 }
385
386 /// Returns owned copies of all orders matching the optional filter parameters.
387 ///
388 /// # Panics
389 ///
390 /// Panics if the cache is already mutably borrowed.
391 #[must_use]
392 pub fn orders(
393 &self,
394 venue: Option<&Venue>,
395 instrument_id: Option<&InstrumentId>,
396 strategy_id: Option<&StrategyId>,
397 account_id: Option<&AccountId>,
398 side: Option<OrderSide>,
399 ) -> Vec<OrderAny> {
400 self.cache()
401 .orders_refs(venue, instrument_id, strategy_id, account_id, side)
402 .into_iter()
403 .map(|order| order.cloned())
404 .collect()
405 }
406
407 /// Returns owned copies of all open orders matching the optional filter parameters.
408 ///
409 /// # Panics
410 ///
411 /// Panics if the cache is already mutably borrowed.
412 #[must_use]
413 pub fn orders_open(
414 &self,
415 venue: Option<&Venue>,
416 instrument_id: Option<&InstrumentId>,
417 strategy_id: Option<&StrategyId>,
418 account_id: Option<&AccountId>,
419 side: Option<OrderSide>,
420 ) -> Vec<OrderAny> {
421 self.cache()
422 .orders_open_refs(venue, instrument_id, strategy_id, account_id, side)
423 .into_iter()
424 .map(|order| order.cloned())
425 .collect()
426 }
427
428 /// Returns owned copies of all closed orders matching the optional filter parameters.
429 ///
430 /// # Panics
431 ///
432 /// Panics if the cache is already mutably borrowed.
433 #[must_use]
434 pub fn orders_closed(
435 &self,
436 venue: Option<&Venue>,
437 instrument_id: Option<&InstrumentId>,
438 strategy_id: Option<&StrategyId>,
439 account_id: Option<&AccountId>,
440 side: Option<OrderSide>,
441 ) -> Vec<OrderAny> {
442 self.cache()
443 .orders_closed_refs(venue, instrument_id, strategy_id, account_id, side)
444 .into_iter()
445 .map(|order| order.cloned())
446 .collect()
447 }
448
449 /// Returns owned copies of all locally active orders matching the optional filter parameters.
450 ///
451 /// # Panics
452 ///
453 /// Panics if the cache is already mutably borrowed.
454 #[must_use]
455 pub fn orders_active_local(
456 &self,
457 venue: Option<&Venue>,
458 instrument_id: Option<&InstrumentId>,
459 strategy_id: Option<&StrategyId>,
460 account_id: Option<&AccountId>,
461 side: Option<OrderSide>,
462 ) -> Vec<OrderAny> {
463 self.cache()
464 .orders_active_local_refs(venue, instrument_id, strategy_id, account_id, side)
465 .into_iter()
466 .map(|order| order.cloned())
467 .collect()
468 }
469
470 /// Returns owned copies of all emulated orders matching the optional filter parameters.
471 ///
472 /// # Panics
473 ///
474 /// Panics if the cache is already mutably borrowed.
475 #[must_use]
476 pub fn orders_emulated(
477 &self,
478 venue: Option<&Venue>,
479 instrument_id: Option<&InstrumentId>,
480 strategy_id: Option<&StrategyId>,
481 account_id: Option<&AccountId>,
482 side: Option<OrderSide>,
483 ) -> Vec<OrderAny> {
484 self.cache()
485 .orders_emulated_refs(venue, instrument_id, strategy_id, account_id, side)
486 .into_iter()
487 .map(|order| order.cloned())
488 .collect()
489 }
490
491 /// Returns owned copies of all in-flight orders matching the optional filter parameters.
492 ///
493 /// # Panics
494 ///
495 /// Panics if the cache is already mutably borrowed.
496 #[must_use]
497 pub fn orders_inflight(
498 &self,
499 venue: Option<&Venue>,
500 instrument_id: Option<&InstrumentId>,
501 strategy_id: Option<&StrategyId>,
502 account_id: Option<&AccountId>,
503 side: Option<OrderSide>,
504 ) -> Vec<OrderAny> {
505 self.cache()
506 .orders_inflight_refs(venue, instrument_id, strategy_id, account_id, side)
507 .into_iter()
508 .map(|order| order.cloned())
509 .collect()
510 }
511
512 /// Returns owned copies of all orders for the `position_id`.
513 ///
514 /// # Panics
515 ///
516 /// Panics if the cache is already mutably borrowed.
517 #[must_use]
518 pub fn orders_for_position(&self, position_id: &PositionId) -> Vec<OrderAny> {
519 self.cache()
520 .orders_for_position(position_id)
521 .into_iter()
522 .map(|order| order.cloned())
523 .collect()
524 }
525
526 /// Returns whether an order with the `client_order_id` exists.
527 ///
528 /// # Panics
529 ///
530 /// Panics if the cache is already mutably borrowed.
531 #[must_use]
532 pub fn order_exists(&self, client_order_id: &ClientOrderId) -> bool {
533 self.cache().order_exists(client_order_id)
534 }
535
536 /// Returns whether an order with the `client_order_id` is open.
537 ///
538 /// # Panics
539 ///
540 /// Panics if the cache is already mutably borrowed.
541 #[must_use]
542 pub fn is_order_open(&self, client_order_id: &ClientOrderId) -> bool {
543 self.cache().is_order_open(client_order_id)
544 }
545
546 /// Returns whether an order with the `client_order_id` is closed.
547 ///
548 /// # Panics
549 ///
550 /// Panics if the cache is already mutably borrowed.
551 #[must_use]
552 pub fn is_order_closed(&self, client_order_id: &ClientOrderId) -> bool {
553 self.cache().is_order_closed(client_order_id)
554 }
555
556 /// Returns whether an order with the `client_order_id` is locally active.
557 ///
558 /// # Panics
559 ///
560 /// Panics if the cache is already mutably borrowed.
561 #[must_use]
562 pub fn is_order_active_local(&self, client_order_id: &ClientOrderId) -> bool {
563 self.cache().is_order_active_local(client_order_id)
564 }
565
566 /// Returns whether an order with the `client_order_id` is emulated.
567 ///
568 /// # Panics
569 ///
570 /// Panics if the cache is already mutably borrowed.
571 #[must_use]
572 pub fn is_order_emulated(&self, client_order_id: &ClientOrderId) -> bool {
573 self.cache().is_order_emulated(client_order_id)
574 }
575
576 /// Returns whether an order with the `client_order_id` is in-flight.
577 ///
578 /// # Panics
579 ///
580 /// Panics if the cache is already mutably borrowed.
581 #[must_use]
582 pub fn is_order_inflight(&self, client_order_id: &ClientOrderId) -> bool {
583 self.cache().is_order_inflight(client_order_id)
584 }
585
586 /// Returns whether an order with the `client_order_id` is `PENDING_CANCEL` locally.
587 ///
588 /// # Panics
589 ///
590 /// Panics if the cache is already mutably borrowed.
591 #[must_use]
592 pub fn is_order_pending_cancel_local(&self, client_order_id: &ClientOrderId) -> bool {
593 self.cache().is_order_pending_cancel_local(client_order_id)
594 }
595
596 /// Returns the count of all open orders matching the optional filter parameters.
597 ///
598 /// # Panics
599 ///
600 /// Panics if the cache is already mutably borrowed.
601 #[must_use]
602 pub fn orders_open_count(
603 &self,
604 venue: Option<&Venue>,
605 instrument_id: Option<&InstrumentId>,
606 strategy_id: Option<&StrategyId>,
607 account_id: Option<&AccountId>,
608 side: Option<OrderSide>,
609 ) -> usize {
610 self.cache()
611 .orders_open_count(venue, instrument_id, strategy_id, account_id, side)
612 }
613
614 /// Returns the count of all closed orders matching the optional filter parameters.
615 ///
616 /// # Panics
617 ///
618 /// Panics if the cache is already mutably borrowed.
619 #[must_use]
620 pub fn orders_closed_count(
621 &self,
622 venue: Option<&Venue>,
623 instrument_id: Option<&InstrumentId>,
624 strategy_id: Option<&StrategyId>,
625 account_id: Option<&AccountId>,
626 side: Option<OrderSide>,
627 ) -> usize {
628 self.cache()
629 .orders_closed_count(venue, instrument_id, strategy_id, account_id, side)
630 }
631
632 /// Returns the count of all locally active orders matching the optional filter parameters.
633 ///
634 /// # Panics
635 ///
636 /// Panics if the cache is already mutably borrowed.
637 #[must_use]
638 pub fn orders_active_local_count(
639 &self,
640 venue: Option<&Venue>,
641 instrument_id: Option<&InstrumentId>,
642 strategy_id: Option<&StrategyId>,
643 account_id: Option<&AccountId>,
644 side: Option<OrderSide>,
645 ) -> usize {
646 self.cache()
647 .orders_active_local_count(venue, instrument_id, strategy_id, account_id, side)
648 }
649
650 /// Returns the count of all emulated orders matching the optional filter parameters.
651 ///
652 /// # Panics
653 ///
654 /// Panics if the cache is already mutably borrowed.
655 #[must_use]
656 pub fn orders_emulated_count(
657 &self,
658 venue: Option<&Venue>,
659 instrument_id: Option<&InstrumentId>,
660 strategy_id: Option<&StrategyId>,
661 account_id: Option<&AccountId>,
662 side: Option<OrderSide>,
663 ) -> usize {
664 self.cache()
665 .orders_emulated_count(venue, instrument_id, strategy_id, account_id, side)
666 }
667
668 /// Returns the count of all in-flight orders matching the optional filter parameters.
669 ///
670 /// # Panics
671 ///
672 /// Panics if the cache is already mutably borrowed.
673 #[must_use]
674 pub fn orders_inflight_count(
675 &self,
676 venue: Option<&Venue>,
677 instrument_id: Option<&InstrumentId>,
678 strategy_id: Option<&StrategyId>,
679 account_id: Option<&AccountId>,
680 side: Option<OrderSide>,
681 ) -> usize {
682 self.cache()
683 .orders_inflight_count(venue, instrument_id, strategy_id, account_id, side)
684 }
685
686 /// Returns the count of all orders matching the optional filter parameters.
687 ///
688 /// # Panics
689 ///
690 /// Panics if the cache is already mutably borrowed.
691 #[must_use]
692 pub fn orders_total_count(
693 &self,
694 venue: Option<&Venue>,
695 instrument_id: Option<&InstrumentId>,
696 strategy_id: Option<&StrategyId>,
697 account_id: Option<&AccountId>,
698 side: Option<OrderSide>,
699 ) -> usize {
700 self.cache()
701 .orders_total_count(venue, instrument_id, strategy_id, account_id, side)
702 }
703
704 /// Returns whether any open order matches the optional filter parameters.
705 ///
706 /// # Panics
707 ///
708 /// Panics if the cache is already mutably borrowed.
709 #[must_use]
710 pub fn has_orders_open(
711 &self,
712 venue: Option<&Venue>,
713 instrument_id: Option<&InstrumentId>,
714 strategy_id: Option<&StrategyId>,
715 account_id: Option<&AccountId>,
716 side: Option<OrderSide>,
717 ) -> bool {
718 self.cache()
719 .has_orders_open(venue, instrument_id, strategy_id, account_id, side)
720 }
721
722 /// Returns whether any closed order matches the optional filter parameters.
723 ///
724 /// # Panics
725 ///
726 /// Panics if the cache is already mutably borrowed.
727 #[must_use]
728 pub fn has_orders_closed(
729 &self,
730 venue: Option<&Venue>,
731 instrument_id: Option<&InstrumentId>,
732 strategy_id: Option<&StrategyId>,
733 account_id: Option<&AccountId>,
734 side: Option<OrderSide>,
735 ) -> bool {
736 self.cache()
737 .has_orders_closed(venue, instrument_id, strategy_id, account_id, side)
738 }
739
740 /// Returns whether any locally active order matches the optional filter parameters.
741 ///
742 /// # Panics
743 ///
744 /// Panics if the cache is already mutably borrowed.
745 #[must_use]
746 pub fn has_orders_active_local(
747 &self,
748 venue: Option<&Venue>,
749 instrument_id: Option<&InstrumentId>,
750 strategy_id: Option<&StrategyId>,
751 account_id: Option<&AccountId>,
752 side: Option<OrderSide>,
753 ) -> bool {
754 self.cache()
755 .has_orders_active_local(venue, instrument_id, strategy_id, account_id, side)
756 }
757
758 /// Returns whether any emulated order matches the optional filter parameters.
759 ///
760 /// # Panics
761 ///
762 /// Panics if the cache is already mutably borrowed.
763 #[must_use]
764 pub fn has_orders_emulated(
765 &self,
766 venue: Option<&Venue>,
767 instrument_id: Option<&InstrumentId>,
768 strategy_id: Option<&StrategyId>,
769 account_id: Option<&AccountId>,
770 side: Option<OrderSide>,
771 ) -> bool {
772 self.cache()
773 .has_orders_emulated(venue, instrument_id, strategy_id, account_id, side)
774 }
775
776 /// Returns whether any in-flight order matches the optional filter parameters.
777 ///
778 /// # Panics
779 ///
780 /// Panics if the cache is already mutably borrowed.
781 #[must_use]
782 pub fn has_orders_inflight(
783 &self,
784 venue: Option<&Venue>,
785 instrument_id: Option<&InstrumentId>,
786 strategy_id: Option<&StrategyId>,
787 account_id: Option<&AccountId>,
788 side: Option<OrderSide>,
789 ) -> bool {
790 self.cache()
791 .has_orders_inflight(venue, instrument_id, strategy_id, account_id, side)
792 }
793
794 /// Returns whether any order matches the optional filter parameters.
795 ///
796 /// # Panics
797 ///
798 /// Panics if the cache is already mutably borrowed.
799 #[must_use]
800 pub fn has_orders(
801 &self,
802 venue: Option<&Venue>,
803 instrument_id: Option<&InstrumentId>,
804 strategy_id: Option<&StrategyId>,
805 account_id: Option<&AccountId>,
806 side: Option<OrderSide>,
807 ) -> bool {
808 self.cache()
809 .has_orders(venue, instrument_id, strategy_id, account_id, side)
810 }
811
812 /// Returns an owned copy of the order list for the `order_list_id` (if found).
813 ///
814 /// # Panics
815 ///
816 /// Panics if the cache is already mutably borrowed.
817 #[must_use]
818 pub fn order_list(&self, order_list_id: &OrderListId) -> Option<OrderList> {
819 self.cache().order_list(order_list_id).cloned()
820 }
821
822 /// Returns an owned copy of the order list for the `order_list_id`.
823 ///
824 /// # Errors
825 ///
826 /// Returns:
827 /// - [`OrderListLookupError::NotFound`] when the order list is not present in the cache.
828 /// - [`OrderListLookupError::Access`] if the cache is already mutably borrowed.
829 pub fn try_order_list(
830 &self,
831 order_list_id: &OrderListId,
832 ) -> Result<OrderList, OrderListLookupError> {
833 self.try_cache("try_order_list")?
834 .try_order_list(order_list_id)
835 .cloned()
836 }
837
838 /// Returns owned copies of all order lists matching the optional filter parameters.
839 ///
840 /// # Panics
841 ///
842 /// Panics if the cache is already mutably borrowed.
843 #[must_use]
844 pub fn order_lists(
845 &self,
846 venue: Option<&Venue>,
847 instrument_id: Option<&InstrumentId>,
848 strategy_id: Option<&StrategyId>,
849 account_id: Option<&AccountId>,
850 ) -> Vec<OrderList> {
851 self.cache()
852 .order_lists(venue, instrument_id, strategy_id, account_id)
853 .into_iter()
854 .cloned()
855 .collect()
856 }
857
858 /// Returns whether an order list with the `order_list_id` exists.
859 ///
860 /// # Panics
861 ///
862 /// Panics if the cache is already mutably borrowed.
863 #[must_use]
864 pub fn order_list_exists(&self, order_list_id: &OrderListId) -> bool {
865 self.cache().order_list_exists(order_list_id)
866 }
867
868 /// Returns owned copies of all orders associated with the `exec_algorithm_id`.
869 ///
870 /// # Panics
871 ///
872 /// Panics if the cache is already mutably borrowed.
873 #[must_use]
874 pub fn orders_for_exec_algorithm(
875 &self,
876 exec_algorithm_id: &ExecAlgorithmId,
877 venue: Option<&Venue>,
878 instrument_id: Option<&InstrumentId>,
879 strategy_id: Option<&StrategyId>,
880 account_id: Option<&AccountId>,
881 side: Option<OrderSide>,
882 ) -> Vec<OrderAny> {
883 self.cache()
884 .orders_for_exec_algorithm(
885 exec_algorithm_id,
886 venue,
887 instrument_id,
888 strategy_id,
889 account_id,
890 side,
891 )
892 .into_iter()
893 .map(|order| order.cloned())
894 .collect()
895 }
896
897 /// Returns owned copies of all orders with the `exec_spawn_id`.
898 ///
899 /// # Panics
900 ///
901 /// Panics if the cache is already mutably borrowed.
902 #[must_use]
903 pub fn orders_for_exec_spawn(&self, exec_spawn_id: &ClientOrderId) -> Vec<OrderAny> {
904 self.cache()
905 .orders_for_exec_spawn(exec_spawn_id)
906 .into_iter()
907 .map(|order| order.cloned())
908 .collect()
909 }
910
911 /// Returns the total order quantity for the `exec_spawn_id`.
912 ///
913 /// # Panics
914 ///
915 /// Panics if the cache is already mutably borrowed.
916 #[must_use]
917 pub fn exec_spawn_total_quantity(
918 &self,
919 exec_spawn_id: &ClientOrderId,
920 active_only: bool,
921 ) -> Option<Quantity> {
922 self.cache()
923 .exec_spawn_total_quantity(exec_spawn_id, active_only)
924 }
925
926 /// Returns the total filled quantity for all orders with the `exec_spawn_id`.
927 ///
928 /// # Panics
929 ///
930 /// Panics if the cache is already mutably borrowed.
931 #[must_use]
932 pub fn exec_spawn_total_filled_qty(
933 &self,
934 exec_spawn_id: &ClientOrderId,
935 active_only: bool,
936 ) -> Option<Quantity> {
937 self.cache()
938 .exec_spawn_total_filled_qty(exec_spawn_id, active_only)
939 }
940
941 /// Returns the total leaves quantity for all orders with the `exec_spawn_id`.
942 ///
943 /// # Panics
944 ///
945 /// Panics if the cache is already mutably borrowed.
946 #[must_use]
947 pub fn exec_spawn_total_leaves_qty(
948 &self,
949 exec_spawn_id: &ClientOrderId,
950 active_only: bool,
951 ) -> Option<Quantity> {
952 self.cache()
953 .exec_spawn_total_leaves_qty(exec_spawn_id, active_only)
954 }
955
956 /// Returns an owned copy of the position for the `position_id` (if found).
957 ///
958 /// # Panics
959 ///
960 /// Panics if the cache is already mutably borrowed.
961 #[must_use]
962 pub fn position(&self, position_id: &PositionId) -> Option<Position> {
963 self.cache()
964 .position_ref(position_id)
965 .map(|position| position.cloned())
966 }
967
968 /// Returns an owned copy of the position for the `position_id`.
969 ///
970 /// # Errors
971 ///
972 /// Returns:
973 /// - [`PositionLookupError::NotFound`] when the position is not present in the cache.
974 /// - [`PositionLookupError::Access`] if the cache is already mutably borrowed.
975 pub fn try_position(&self, position_id: &PositionId) -> Result<Position, PositionLookupError> {
976 self.try_cache("try_position")?
977 .try_position_ref(position_id)
978 .map(|position| position.cloned())
979 }
980
981 /// Returns an owned copy of the position for the `client_order_id` (if found).
982 ///
983 /// # Panics
984 ///
985 /// Panics if the cache is already mutably borrowed.
986 #[must_use]
987 pub fn position_for_order(&self, client_order_id: &ClientOrderId) -> Option<Position> {
988 self.cache()
989 .position_for_order_ref(client_order_id)
990 .map(|position| position.cloned())
991 }
992
993 /// Returns the position ID for the `client_order_id` (if found).
994 ///
995 /// # Panics
996 ///
997 /// Panics if the cache is already mutably borrowed.
998 #[must_use]
999 pub fn position_id(&self, client_order_id: &ClientOrderId) -> Option<PositionId> {
1000 self.cache().position_id(client_order_id).copied()
1001 }
1002
1003 /// Returns owned copies of all positions matching the optional filter parameters.
1004 ///
1005 /// # Panics
1006 ///
1007 /// Panics if the cache is already mutably borrowed.
1008 #[must_use]
1009 pub fn positions(
1010 &self,
1011 venue: Option<&Venue>,
1012 instrument_id: Option<&InstrumentId>,
1013 strategy_id: Option<&StrategyId>,
1014 account_id: Option<&AccountId>,
1015 side: Option<PositionSide>,
1016 ) -> Vec<Position> {
1017 self.cache()
1018 .positions_refs(venue, instrument_id, strategy_id, account_id, side)
1019 .into_iter()
1020 .map(|position| position.cloned())
1021 .collect()
1022 }
1023
1024 /// Returns owned copies of all open positions matching the optional filter parameters.
1025 ///
1026 /// # Panics
1027 ///
1028 /// Panics if the cache is already mutably borrowed.
1029 #[must_use]
1030 pub fn positions_open(
1031 &self,
1032 venue: Option<&Venue>,
1033 instrument_id: Option<&InstrumentId>,
1034 strategy_id: Option<&StrategyId>,
1035 account_id: Option<&AccountId>,
1036 side: Option<PositionSide>,
1037 ) -> Vec<Position> {
1038 self.cache()
1039 .positions_open_refs(venue, instrument_id, strategy_id, account_id, side)
1040 .into_iter()
1041 .map(|position| position.cloned())
1042 .collect()
1043 }
1044
1045 /// Returns owned copies of all closed positions matching the optional filter parameters.
1046 ///
1047 /// # Panics
1048 ///
1049 /// Panics if the cache is already mutably borrowed.
1050 #[must_use]
1051 pub fn positions_closed(
1052 &self,
1053 venue: Option<&Venue>,
1054 instrument_id: Option<&InstrumentId>,
1055 strategy_id: Option<&StrategyId>,
1056 account_id: Option<&AccountId>,
1057 side: Option<PositionSide>,
1058 ) -> Vec<Position> {
1059 self.cache()
1060 .positions_closed_refs(venue, instrument_id, strategy_id, account_id, side)
1061 .into_iter()
1062 .map(|position| position.cloned())
1063 .collect()
1064 }
1065
1066 /// Returns whether a position with the `position_id` exists.
1067 ///
1068 /// # Panics
1069 ///
1070 /// Panics if the cache is already mutably borrowed.
1071 #[must_use]
1072 pub fn position_exists(&self, position_id: &PositionId) -> bool {
1073 self.cache().position_exists(position_id)
1074 }
1075
1076 /// Returns whether a position with the `position_id` is open.
1077 ///
1078 /// # Panics
1079 ///
1080 /// Panics if the cache is already mutably borrowed.
1081 #[must_use]
1082 pub fn is_position_open(&self, position_id: &PositionId) -> bool {
1083 self.cache().is_position_open(position_id)
1084 }
1085
1086 /// Returns whether a position with the `position_id` is closed.
1087 ///
1088 /// # Panics
1089 ///
1090 /// Panics if the cache is already mutably borrowed.
1091 #[must_use]
1092 pub fn is_position_closed(&self, position_id: &PositionId) -> bool {
1093 self.cache().is_position_closed(position_id)
1094 }
1095
1096 /// Returns the count of all open positions matching the optional filter parameters.
1097 ///
1098 /// # Panics
1099 ///
1100 /// Panics if the cache is already mutably borrowed.
1101 #[must_use]
1102 pub fn positions_open_count(
1103 &self,
1104 venue: Option<&Venue>,
1105 instrument_id: Option<&InstrumentId>,
1106 strategy_id: Option<&StrategyId>,
1107 account_id: Option<&AccountId>,
1108 side: Option<PositionSide>,
1109 ) -> usize {
1110 self.cache()
1111 .positions_open_count(venue, instrument_id, strategy_id, account_id, side)
1112 }
1113
1114 /// Returns the count of all closed positions matching the optional filter parameters.
1115 ///
1116 /// # Panics
1117 ///
1118 /// Panics if the cache is already mutably borrowed.
1119 #[must_use]
1120 pub fn positions_closed_count(
1121 &self,
1122 venue: Option<&Venue>,
1123 instrument_id: Option<&InstrumentId>,
1124 strategy_id: Option<&StrategyId>,
1125 account_id: Option<&AccountId>,
1126 side: Option<PositionSide>,
1127 ) -> usize {
1128 self.cache()
1129 .positions_closed_count(venue, instrument_id, strategy_id, account_id, side)
1130 }
1131
1132 /// Returns the count of all positions matching the optional filter parameters.
1133 ///
1134 /// # Panics
1135 ///
1136 /// Panics if the cache is already mutably borrowed.
1137 #[must_use]
1138 pub fn positions_total_count(
1139 &self,
1140 venue: Option<&Venue>,
1141 instrument_id: Option<&InstrumentId>,
1142 strategy_id: Option<&StrategyId>,
1143 account_id: Option<&AccountId>,
1144 side: Option<PositionSide>,
1145 ) -> usize {
1146 self.cache()
1147 .positions_total_count(venue, instrument_id, strategy_id, account_id, side)
1148 }
1149
1150 /// Returns whether any open position matches the optional filter parameters.
1151 ///
1152 /// # Panics
1153 ///
1154 /// Panics if the cache is already mutably borrowed.
1155 #[must_use]
1156 pub fn has_positions_open(
1157 &self,
1158 venue: Option<&Venue>,
1159 instrument_id: Option<&InstrumentId>,
1160 strategy_id: Option<&StrategyId>,
1161 account_id: Option<&AccountId>,
1162 side: Option<PositionSide>,
1163 ) -> bool {
1164 self.cache()
1165 .has_positions_open(venue, instrument_id, strategy_id, account_id, side)
1166 }
1167
1168 /// Returns whether any closed position matches the optional filter parameters.
1169 ///
1170 /// # Panics
1171 ///
1172 /// Panics if the cache is already mutably borrowed.
1173 #[must_use]
1174 pub fn has_positions_closed(
1175 &self,
1176 venue: Option<&Venue>,
1177 instrument_id: Option<&InstrumentId>,
1178 strategy_id: Option<&StrategyId>,
1179 account_id: Option<&AccountId>,
1180 side: Option<PositionSide>,
1181 ) -> bool {
1182 self.cache()
1183 .has_positions_closed(venue, instrument_id, strategy_id, account_id, side)
1184 }
1185
1186 /// Returns whether any position matches the optional filter parameters.
1187 ///
1188 /// # Panics
1189 ///
1190 /// Panics if the cache is already mutably borrowed.
1191 #[must_use]
1192 pub fn has_positions(
1193 &self,
1194 venue: Option<&Venue>,
1195 instrument_id: Option<&InstrumentId>,
1196 strategy_id: Option<&StrategyId>,
1197 account_id: Option<&AccountId>,
1198 side: Option<PositionSide>,
1199 ) -> bool {
1200 self.cache()
1201 .has_positions(venue, instrument_id, strategy_id, account_id, side)
1202 }
1203
1204 /// Returns the strategy ID for the `client_order_id` (if found).
1205 ///
1206 /// # Panics
1207 ///
1208 /// Panics if the cache is already mutably borrowed.
1209 #[must_use]
1210 pub fn strategy_id_for_order(&self, client_order_id: &ClientOrderId) -> Option<StrategyId> {
1211 self.cache().strategy_id_for_order(client_order_id).copied()
1212 }
1213
1214 /// Returns the strategy ID for the `position_id` (if found).
1215 ///
1216 /// # Panics
1217 ///
1218 /// Panics if the cache is already mutably borrowed.
1219 #[must_use]
1220 pub fn strategy_id_for_position(&self, position_id: &PositionId) -> Option<StrategyId> {
1221 self.cache().strategy_id_for_position(position_id).copied()
1222 }
1223
1224 /// Returns the general cache value for the `key` (if found).
1225 ///
1226 /// # Errors
1227 ///
1228 /// Returns an error if:
1229 /// - The `key` is invalid.
1230 /// - The cache is already mutably borrowed ([`ComponentAccessError`]).
1231 pub fn get(&self, key: &str) -> anyhow::Result<Option<Bytes>> {
1232 let cache = self.try_cache("get")?;
1233 let value = cache.get(key)?;
1234 Ok(value.cloned())
1235 }
1236
1237 /// Returns the price for the `instrument_id` and `price_type` (if found).
1238 ///
1239 /// # Panics
1240 ///
1241 /// Panics if the cache is already mutably borrowed, or if `price_type` is [`PriceType::Mid`]
1242 /// and the quote price precision is already at the maximum fixed precision.
1243 #[must_use]
1244 pub fn price(&self, instrument_id: &InstrumentId, price_type: PriceType) -> Option<Price> {
1245 self.cache().price(instrument_id, price_type)
1246 }
1247
1248 /// Returns all quotes for the `instrument_id` (if found).
1249 ///
1250 /// # Panics
1251 ///
1252 /// Panics if the cache is already mutably borrowed.
1253 #[must_use]
1254 pub fn quotes(&self, instrument_id: &InstrumentId) -> Option<Vec<QuoteTick>> {
1255 self.cache().quotes(instrument_id)
1256 }
1257
1258 /// Returns all trades for the `instrument_id` (if found).
1259 ///
1260 /// # Panics
1261 ///
1262 /// Panics if the cache is already mutably borrowed.
1263 #[must_use]
1264 pub fn trades(&self, instrument_id: &InstrumentId) -> Option<Vec<TradeTick>> {
1265 self.cache().trades(instrument_id)
1266 }
1267
1268 /// Returns all mark price updates for the `instrument_id` (if found).
1269 ///
1270 /// # Panics
1271 ///
1272 /// Panics if the cache is already mutably borrowed.
1273 #[must_use]
1274 pub fn mark_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
1275 self.cache().mark_prices(instrument_id)
1276 }
1277
1278 /// Returns all index price updates for the `instrument_id` (if found).
1279 ///
1280 /// # Panics
1281 ///
1282 /// Panics if the cache is already mutably borrowed.
1283 #[must_use]
1284 pub fn index_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
1285 self.cache().index_prices(instrument_id)
1286 }
1287
1288 /// Returns all funding rate updates for the `instrument_id` (if found).
1289 ///
1290 /// # Panics
1291 ///
1292 /// Panics if the cache is already mutably borrowed.
1293 #[must_use]
1294 pub fn funding_rates(&self, instrument_id: &InstrumentId) -> Option<Vec<FundingRateUpdate>> {
1295 self.cache().funding_rates(instrument_id)
1296 }
1297
1298 /// Returns all instrument status updates for the `instrument_id` (if found).
1299 ///
1300 /// # Panics
1301 ///
1302 /// Panics if the cache is already mutably borrowed.
1303 #[must_use]
1304 pub fn instrument_statuses(
1305 &self,
1306 instrument_id: &InstrumentId,
1307 ) -> Option<Vec<InstrumentStatus>> {
1308 self.cache().instrument_statuses(instrument_id)
1309 }
1310
1311 /// Returns all bars for the `bar_type` (if found).
1312 ///
1313 /// # Panics
1314 ///
1315 /// Panics if the cache is already mutably borrowed.
1316 #[must_use]
1317 pub fn bars(&self, bar_type: &BarType) -> Option<Vec<Bar>> {
1318 self.cache().bars(bar_type)
1319 }
1320
1321 /// Returns an owned copy of the order book for the `instrument_id` (if found).
1322 ///
1323 /// # Panics
1324 ///
1325 /// Panics if the cache is already mutably borrowed.
1326 #[must_use]
1327 pub fn order_book(&self, instrument_id: &InstrumentId) -> Option<OrderBook> {
1328 self.cache().order_book(instrument_id).cloned()
1329 }
1330
1331 /// Returns an owned copy of the order book for the `instrument_id`.
1332 ///
1333 /// # Errors
1334 ///
1335 /// Returns:
1336 /// - [`OrderBookLookupError::NotFound`] when the order book is not present in the cache.
1337 /// - [`OrderBookLookupError::Access`] if the cache is already mutably borrowed.
1338 pub fn try_order_book(
1339 &self,
1340 instrument_id: &InstrumentId,
1341 ) -> Result<OrderBook, OrderBookLookupError> {
1342 self.try_cache("try_order_book")?
1343 .try_order_book(instrument_id)
1344 .cloned()
1345 }
1346
1347 /// Returns an owned copy of the own order book for the `instrument_id` (if found).
1348 ///
1349 /// # Panics
1350 ///
1351 /// Panics if the cache is already mutably borrowed.
1352 #[must_use]
1353 pub fn own_order_book(&self, instrument_id: &InstrumentId) -> Option<OwnOrderBook> {
1354 self.cache().own_order_book(instrument_id).cloned()
1355 }
1356
1357 /// Returns an owned copy of the own order book for the `instrument_id`.
1358 ///
1359 /// # Errors
1360 ///
1361 /// Returns:
1362 /// - [`OwnOrderBookLookupError::NotFound`] when the own order book is not present in the cache.
1363 /// - [`OwnOrderBookLookupError::Access`] if the cache is already mutably borrowed.
1364 pub fn try_own_order_book(
1365 &self,
1366 instrument_id: &InstrumentId,
1367 ) -> Result<OwnOrderBook, OwnOrderBookLookupError> {
1368 self.try_cache("try_own_order_book")?
1369 .try_own_order_book(instrument_id)
1370 .cloned()
1371 }
1372
1373 /// Returns the latest quote for the `instrument_id` (if found).
1374 ///
1375 /// # Panics
1376 ///
1377 /// Panics if the cache is already mutably borrowed.
1378 #[must_use]
1379 pub fn quote(&self, instrument_id: &InstrumentId) -> Option<QuoteTick> {
1380 self.cache().quote(instrument_id).copied()
1381 }
1382
1383 /// Returns the quote at `index` for the `instrument_id` (if found).
1384 ///
1385 /// Index 0 is the most recent.
1386 ///
1387 /// # Panics
1388 ///
1389 /// Panics if the cache is already mutably borrowed.
1390 #[must_use]
1391 pub fn quote_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<QuoteTick> {
1392 self.cache().quote_at_index(instrument_id, index).copied()
1393 }
1394
1395 /// Returns the latest trade for the `instrument_id` (if found).
1396 ///
1397 /// # Panics
1398 ///
1399 /// Panics if the cache is already mutably borrowed.
1400 #[must_use]
1401 pub fn trade(&self, instrument_id: &InstrumentId) -> Option<TradeTick> {
1402 self.cache().trade(instrument_id).copied()
1403 }
1404
1405 /// Returns the trade at `index` for the `instrument_id` (if found).
1406 ///
1407 /// Index 0 is the most recent.
1408 ///
1409 /// # Panics
1410 ///
1411 /// Panics if the cache is already mutably borrowed.
1412 #[must_use]
1413 pub fn trade_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<TradeTick> {
1414 self.cache().trade_at_index(instrument_id, index).copied()
1415 }
1416
1417 /// Returns the latest mark price update for the `instrument_id` (if found).
1418 ///
1419 /// # Panics
1420 ///
1421 /// Panics if the cache is already mutably borrowed.
1422 #[must_use]
1423 pub fn mark_price(&self, instrument_id: &InstrumentId) -> Option<MarkPriceUpdate> {
1424 self.cache().mark_price(instrument_id).copied()
1425 }
1426
1427 /// Returns the latest index price update for the `instrument_id` (if found).
1428 ///
1429 /// # Panics
1430 ///
1431 /// Panics if the cache is already mutably borrowed.
1432 #[must_use]
1433 pub fn index_price(&self, instrument_id: &InstrumentId) -> Option<IndexPriceUpdate> {
1434 self.cache().index_price(instrument_id).copied()
1435 }
1436
1437 /// Returns the latest funding rate update for the `instrument_id` (if found).
1438 ///
1439 /// # Panics
1440 ///
1441 /// Panics if the cache is already mutably borrowed.
1442 #[must_use]
1443 pub fn funding_rate(&self, instrument_id: &InstrumentId) -> Option<FundingRateUpdate> {
1444 self.cache().funding_rate(instrument_id).copied()
1445 }
1446
1447 /// Returns the latest instrument status update for the `instrument_id` (if found).
1448 ///
1449 /// # Panics
1450 ///
1451 /// Panics if the cache is already mutably borrowed.
1452 #[must_use]
1453 pub fn instrument_status(&self, instrument_id: &InstrumentId) -> Option<InstrumentStatus> {
1454 self.cache().instrument_status(instrument_id).copied()
1455 }
1456
1457 /// Returns the cached close for the `instrument_id` (if found).
1458 ///
1459 /// # Panics
1460 ///
1461 /// Panics if the cache is already mutably borrowed.
1462 #[must_use]
1463 pub fn instrument_close(&self, instrument_id: &InstrumentId) -> Option<InstrumentClose> {
1464 self.cache().instrument_close(instrument_id).copied()
1465 }
1466
1467 /// Returns the latest bar for the `bar_type` (if found).
1468 ///
1469 /// # Panics
1470 ///
1471 /// Panics if the cache is already mutably borrowed.
1472 #[must_use]
1473 pub fn bar(&self, bar_type: &BarType) -> Option<Bar> {
1474 self.cache().bar(bar_type).copied()
1475 }
1476
1477 /// Returns the bar at `index` for the `bar_type` (if found).
1478 ///
1479 /// Index 0 is the most recent.
1480 ///
1481 /// # Panics
1482 ///
1483 /// Panics if the cache is already mutably borrowed.
1484 #[must_use]
1485 pub fn bar_at_index(&self, bar_type: &BarType, index: usize) -> Option<Bar> {
1486 self.cache().bar_at_index(bar_type, index).copied()
1487 }
1488
1489 /// Returns the order book update count for the `instrument_id`.
1490 ///
1491 /// # Panics
1492 ///
1493 /// Panics if the cache is already mutably borrowed.
1494 #[must_use]
1495 pub fn book_update_count(&self, instrument_id: &InstrumentId) -> usize {
1496 self.cache().book_update_count(instrument_id)
1497 }
1498
1499 /// Returns the quote tick count for the `instrument_id`.
1500 ///
1501 /// # Panics
1502 ///
1503 /// Panics if the cache is already mutably borrowed.
1504 #[must_use]
1505 pub fn quote_count(&self, instrument_id: &InstrumentId) -> usize {
1506 self.cache().quote_count(instrument_id)
1507 }
1508
1509 /// Returns the trade tick count for the `instrument_id`.
1510 ///
1511 /// # Panics
1512 ///
1513 /// Panics if the cache is already mutably borrowed.
1514 #[must_use]
1515 pub fn trade_count(&self, instrument_id: &InstrumentId) -> usize {
1516 self.cache().trade_count(instrument_id)
1517 }
1518
1519 /// Returns the mark price update count for the `instrument_id`.
1520 ///
1521 /// # Panics
1522 ///
1523 /// Panics if the cache is already mutably borrowed.
1524 #[must_use]
1525 pub fn mark_price_count(&self, instrument_id: &InstrumentId) -> usize {
1526 self.cache().mark_price_count(instrument_id)
1527 }
1528
1529 /// Returns the index price update count for the `instrument_id`.
1530 ///
1531 /// # Panics
1532 ///
1533 /// Panics if the cache is already mutably borrowed.
1534 #[must_use]
1535 pub fn index_price_count(&self, instrument_id: &InstrumentId) -> usize {
1536 self.cache().index_price_count(instrument_id)
1537 }
1538
1539 /// Returns the funding rate update count for the `instrument_id`.
1540 ///
1541 /// # Panics
1542 ///
1543 /// Panics if the cache is already mutably borrowed.
1544 #[must_use]
1545 pub fn funding_rate_count(&self, instrument_id: &InstrumentId) -> usize {
1546 self.cache().funding_rate_count(instrument_id)
1547 }
1548
1549 /// Returns the instrument status update count for the `instrument_id`.
1550 ///
1551 /// # Panics
1552 ///
1553 /// Panics if the cache is already mutably borrowed.
1554 #[must_use]
1555 pub fn instrument_status_count(&self, instrument_id: &InstrumentId) -> usize {
1556 self.cache().instrument_status_count(instrument_id)
1557 }
1558
1559 /// Returns the bar count for the `bar_type`.
1560 ///
1561 /// # Panics
1562 ///
1563 /// Panics if the cache is already mutably borrowed.
1564 #[must_use]
1565 pub fn bar_count(&self, bar_type: &BarType) -> usize {
1566 self.cache().bar_count(bar_type)
1567 }
1568
1569 /// Returns whether the cache contains an order book for the `instrument_id`.
1570 ///
1571 /// # Panics
1572 ///
1573 /// Panics if the cache is already mutably borrowed.
1574 #[must_use]
1575 pub fn has_order_book(&self, instrument_id: &InstrumentId) -> bool {
1576 self.cache().has_order_book(instrument_id)
1577 }
1578
1579 /// Returns whether the cache contains quotes for the `instrument_id`.
1580 ///
1581 /// # Panics
1582 ///
1583 /// Panics if the cache is already mutably borrowed.
1584 #[must_use]
1585 pub fn has_quote_ticks(&self, instrument_id: &InstrumentId) -> bool {
1586 self.cache().has_quote_ticks(instrument_id)
1587 }
1588
1589 /// Returns whether the cache contains trades for the `instrument_id`.
1590 ///
1591 /// # Panics
1592 ///
1593 /// Panics if the cache is already mutably borrowed.
1594 #[must_use]
1595 pub fn has_trade_ticks(&self, instrument_id: &InstrumentId) -> bool {
1596 self.cache().has_trade_ticks(instrument_id)
1597 }
1598
1599 /// Returns whether the cache contains mark price updates for the `instrument_id`.
1600 ///
1601 /// # Panics
1602 ///
1603 /// Panics if the cache is already mutably borrowed.
1604 #[must_use]
1605 pub fn has_mark_prices(&self, instrument_id: &InstrumentId) -> bool {
1606 self.cache().has_mark_prices(instrument_id)
1607 }
1608
1609 /// Returns whether the cache contains index price updates for the `instrument_id`.
1610 ///
1611 /// # Panics
1612 ///
1613 /// Panics if the cache is already mutably borrowed.
1614 #[must_use]
1615 pub fn has_index_prices(&self, instrument_id: &InstrumentId) -> bool {
1616 self.cache().has_index_prices(instrument_id)
1617 }
1618
1619 /// Returns whether the cache contains funding rate updates for the `instrument_id`.
1620 ///
1621 /// # Panics
1622 ///
1623 /// Panics if the cache is already mutably borrowed.
1624 #[must_use]
1625 pub fn has_funding_rates(&self, instrument_id: &InstrumentId) -> bool {
1626 self.cache().has_funding_rates(instrument_id)
1627 }
1628
1629 /// Returns whether the cache contains instrument status updates for the `instrument_id`.
1630 ///
1631 /// # Panics
1632 ///
1633 /// Panics if the cache is already mutably borrowed.
1634 #[must_use]
1635 pub fn has_instrument_statuses(&self, instrument_id: &InstrumentId) -> bool {
1636 self.cache().has_instrument_statuses(instrument_id)
1637 }
1638
1639 /// Returns whether the cache contains a close for the `instrument_id`.
1640 ///
1641 /// # Panics
1642 ///
1643 /// Panics if the cache is already mutably borrowed.
1644 #[must_use]
1645 pub fn has_instrument_close(&self, instrument_id: &InstrumentId) -> bool {
1646 self.cache().has_instrument_close(instrument_id)
1647 }
1648
1649 /// Returns whether the cache contains bars for the `bar_type`.
1650 ///
1651 /// # Panics
1652 ///
1653 /// Panics if the cache is already mutably borrowed.
1654 #[must_use]
1655 pub fn has_bars(&self, bar_type: &BarType) -> bool {
1656 self.cache().has_bars(bar_type)
1657 }
1658
1659 /// Returns the exchange rate for the given currencies and price type (if available).
1660 ///
1661 /// # Panics
1662 ///
1663 /// Panics if the cache is already mutably borrowed.
1664 #[must_use]
1665 pub fn get_xrate(
1666 &self,
1667 venue: Venue,
1668 from_currency: Currency,
1669 to_currency: Currency,
1670 price_type: PriceType,
1671 ) -> Option<Decimal> {
1672 self.cache()
1673 .get_xrate(venue, from_currency, to_currency, price_type)
1674 }
1675
1676 /// Returns the mark exchange rate for the currency pair (if set).
1677 ///
1678 /// # Panics
1679 ///
1680 /// Panics if the cache is already mutably borrowed.
1681 #[must_use]
1682 pub fn get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
1683 self.cache().get_mark_xrate(from_currency, to_currency)
1684 }
1685
1686 /// Returns the yield curve for the `key` (if found).
1687 ///
1688 /// # Panics
1689 ///
1690 /// Panics if the cache is already mutably borrowed.
1691 #[must_use]
1692 pub fn yield_curve(&self, key: &str) -> Option<Box<dyn Fn(f64) -> f64>> {
1693 self.cache().yield_curve(key)
1694 }
1695
1696 /// Returns an owned copy of the greeks data for the `instrument_id` (if found).
1697 ///
1698 /// # Panics
1699 ///
1700 /// Panics if the cache is already mutably borrowed.
1701 #[must_use]
1702 pub fn greeks(&self, instrument_id: &InstrumentId) -> Option<GreeksData> {
1703 self.cache().greeks(instrument_id)
1704 }
1705
1706 /// Returns exchange-provided option greeks for the `instrument_id` (if found).
1707 ///
1708 /// # Panics
1709 ///
1710 /// Panics if the cache is already mutably borrowed.
1711 #[must_use]
1712 pub fn option_greeks(&self, instrument_id: &InstrumentId) -> Option<OptionGreeks> {
1713 self.cache().option_greeks(instrument_id).copied()
1714 }
1715
1716 /// Returns the currency for the `code` (if found).
1717 ///
1718 /// # Panics
1719 ///
1720 /// Panics if the cache is already mutably borrowed.
1721 #[must_use]
1722 pub fn currency(&self, code: &Ustr) -> Option<Currency> {
1723 self.cache().currency(code).copied()
1724 }
1725
1726 /// Returns the currency for the `code`.
1727 ///
1728 /// # Errors
1729 ///
1730 /// Returns:
1731 /// - [`CurrencyLookupError::NotFound`] when the currency is not present in the cache.
1732 /// - [`CurrencyLookupError::Access`] if the cache is already mutably borrowed.
1733 pub fn try_currency(&self, code: &Ustr) -> Result<Currency, CurrencyLookupError> {
1734 self.try_cache("try_currency")?.try_currency(code).copied()
1735 }
1736
1737 /// Returns an owned copy of the instrument for the `instrument_id` (if found).
1738 ///
1739 /// # Panics
1740 ///
1741 /// Panics if the cache is already mutably borrowed.
1742 #[must_use]
1743 pub fn instrument(&self, instrument_id: &InstrumentId) -> Option<InstrumentAny> {
1744 self.cache().instrument(instrument_id).cloned()
1745 }
1746
1747 /// Returns an owned copy of the instrument for the `instrument_id`.
1748 ///
1749 /// # Errors
1750 ///
1751 /// Returns:
1752 /// - [`InstrumentLookupError::NotFound`] when the instrument is not present in the cache.
1753 /// - [`InstrumentLookupError::Access`] if the cache is already mutably borrowed.
1754 pub fn try_instrument(
1755 &self,
1756 instrument_id: &InstrumentId,
1757 ) -> Result<InstrumentAny, InstrumentLookupError> {
1758 self.try_cache("try_instrument")?
1759 .try_instrument(instrument_id)
1760 .cloned()
1761 }
1762
1763 /// Returns the instrument IDs in the cache, optionally filtered by `venue`.
1764 ///
1765 /// # Panics
1766 ///
1767 /// Panics if the cache is already mutably borrowed.
1768 #[must_use]
1769 pub fn instrument_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1770 self.cache()
1771 .instrument_ids(venue)
1772 .into_iter()
1773 .copied()
1774 .collect()
1775 }
1776
1777 /// Returns owned copies of all instruments for the `venue`.
1778 ///
1779 /// # Panics
1780 ///
1781 /// Panics if the cache is already mutably borrowed.
1782 #[must_use]
1783 pub fn instruments(&self, venue: &Venue, underlying: Option<&Ustr>) -> Vec<InstrumentAny> {
1784 self.cache()
1785 .instruments(venue, underlying)
1786 .into_iter()
1787 .cloned()
1788 .collect()
1789 }
1790
1791 /// Returns owned copies of all instruments for the `venue`, parent `root`, and instrument
1792 /// `class`.
1793 ///
1794 /// # Panics
1795 ///
1796 /// Panics if the cache is already mutably borrowed.
1797 #[must_use]
1798 pub fn instruments_by_parent(
1799 &self,
1800 venue: &Venue,
1801 root: &Ustr,
1802 class: InstrumentClass,
1803 ) -> Vec<InstrumentAny> {
1804 self.cache()
1805 .instruments_by_parent(venue, root, class)
1806 .into_iter()
1807 .cloned()
1808 .collect()
1809 }
1810
1811 /// Returns the bar types in the cache, optionally filtered by instrument and price type.
1812 ///
1813 /// # Panics
1814 ///
1815 /// Panics if the cache is already mutably borrowed.
1816 #[must_use]
1817 pub fn bar_types(
1818 &self,
1819 instrument_id: Option<&InstrumentId>,
1820 price_type: Option<&PriceType>,
1821 aggregation_source: AggregationSource,
1822 ) -> Vec<BarType> {
1823 self.cache()
1824 .bar_types(instrument_id, price_type, aggregation_source)
1825 .into_iter()
1826 .copied()
1827 .collect()
1828 }
1829
1830 /// Returns an owned copy of the synthetic instrument for the `instrument_id` (if found).
1831 ///
1832 /// # Panics
1833 ///
1834 /// Panics if the cache is already mutably borrowed.
1835 #[must_use]
1836 pub fn synthetic(&self, instrument_id: &InstrumentId) -> Option<SyntheticInstrument> {
1837 self.cache().synthetic(instrument_id).cloned()
1838 }
1839
1840 /// Returns an owned copy of the synthetic instrument for the `instrument_id`.
1841 ///
1842 /// # Errors
1843 ///
1844 /// Returns:
1845 /// - [`SyntheticInstrumentLookupError::NotFound`] when the synthetic instrument is not present
1846 /// in the cache.
1847 /// - [`SyntheticInstrumentLookupError::Access`] if the cache is already mutably borrowed.
1848 pub fn try_synthetic(
1849 &self,
1850 instrument_id: &InstrumentId,
1851 ) -> Result<SyntheticInstrument, SyntheticInstrumentLookupError> {
1852 self.try_cache("try_synthetic")?
1853 .try_synthetic(instrument_id)
1854 .cloned()
1855 }
1856
1857 /// Returns the synthetic instrument IDs in the cache.
1858 ///
1859 /// # Panics
1860 ///
1861 /// Panics if the cache is already mutably borrowed.
1862 #[must_use]
1863 pub fn synthetic_ids(&self) -> Vec<InstrumentId> {
1864 self.cache().synthetic_ids().into_iter().copied().collect()
1865 }
1866
1867 /// Returns owned copies of all synthetic instruments in the cache.
1868 ///
1869 /// # Panics
1870 ///
1871 /// Panics if the cache is already mutably borrowed.
1872 #[must_use]
1873 pub fn synthetics(&self) -> Vec<SyntheticInstrument> {
1874 self.cache().synthetics().into_iter().cloned().collect()
1875 }
1876
1877 /// Returns an owned copy of the pool for the `instrument_id` (if found).
1878 ///
1879 /// # Panics
1880 ///
1881 /// Panics if the cache is already mutably borrowed.
1882 #[cfg(feature = "defi")]
1883 #[must_use]
1884 pub fn pool(&self, instrument_id: &InstrumentId) -> Option<Pool> {
1885 self.cache().pool(instrument_id).cloned()
1886 }
1887
1888 /// Returns the pool instrument IDs in the cache, optionally filtered by `venue`.
1889 ///
1890 /// # Panics
1891 ///
1892 /// Panics if the cache is already mutably borrowed.
1893 #[cfg(feature = "defi")]
1894 #[must_use]
1895 pub fn pool_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1896 self.cache().pool_ids(venue)
1897 }
1898
1899 /// Returns owned copies of all pools in the cache, optionally filtered by `venue`.
1900 ///
1901 /// # Panics
1902 ///
1903 /// Panics if the cache is already mutably borrowed.
1904 #[cfg(feature = "defi")]
1905 #[must_use]
1906 pub fn pools(&self, venue: Option<&Venue>) -> Vec<Pool> {
1907 self.cache().pools(venue).into_iter().cloned().collect()
1908 }
1909
1910 /// Returns an owned copy of the pool profiler for the `instrument_id` (if found).
1911 ///
1912 /// # Panics
1913 ///
1914 /// Panics if the cache is already mutably borrowed.
1915 #[cfg(feature = "defi")]
1916 #[must_use]
1917 pub fn pool_profiler(&self, instrument_id: &InstrumentId) -> Option<PoolProfiler> {
1918 self.cache().pool_profiler(instrument_id).cloned()
1919 }
1920
1921 /// Returns the pool profiler instrument IDs in the cache, optionally filtered by `venue`.
1922 ///
1923 /// # Panics
1924 ///
1925 /// Panics if the cache is already mutably borrowed.
1926 #[cfg(feature = "defi")]
1927 #[must_use]
1928 pub fn pool_profiler_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1929 self.cache().pool_profiler_ids(venue)
1930 }
1931
1932 /// Returns owned copies of all pool profilers in the cache, optionally filtered by `venue`.
1933 ///
1934 /// # Panics
1935 ///
1936 /// Panics if the cache is already mutably borrowed.
1937 #[cfg(feature = "defi")]
1938 #[must_use]
1939 pub fn pool_profilers(&self, venue: Option<&Venue>) -> Vec<PoolProfiler> {
1940 self.cache()
1941 .pool_profilers(venue)
1942 .into_iter()
1943 .cloned()
1944 .collect()
1945 }
1946
1947 /// Returns an owned copy of the account for the `account_id` (if found).
1948 ///
1949 /// # Panics
1950 ///
1951 /// Panics if the cache is already mutably borrowed.
1952 #[must_use]
1953 pub fn account(&self, account_id: &AccountId) -> Option<AccountAny> {
1954 self.cache().account_owned(account_id)
1955 }
1956
1957 /// Returns an owned copy of the account for the `account_id`.
1958 ///
1959 /// # Errors
1960 ///
1961 /// Returns:
1962 /// - [`AccountLookupError::NotFound`] when the account is not present in the cache.
1963 /// - [`AccountLookupError::Access`] if the cache is already mutably borrowed.
1964 pub fn try_account(&self, account_id: &AccountId) -> Result<AccountAny, AccountLookupError> {
1965 self.try_cache("try_account")?
1966 .try_account(account_id)
1967 .map(|account| account.cloned())
1968 }
1969
1970 /// Returns an owned copy of the account for the `venue` (if found).
1971 ///
1972 /// # Panics
1973 ///
1974 /// Panics if the cache is already mutably borrowed.
1975 #[must_use]
1976 pub fn account_for_venue(&self, venue: &Venue) -> Option<AccountAny> {
1977 self.cache().account_for_venue_owned(venue)
1978 }
1979
1980 /// Returns the account ID for the `venue` (if found).
1981 ///
1982 /// # Panics
1983 ///
1984 /// Panics if the cache is already mutably borrowed.
1985 #[must_use]
1986 pub fn account_id(&self, venue: &Venue) -> Option<AccountId> {
1987 self.cache().account_id(venue).copied()
1988 }
1989
1990 /// Returns owned copies of all accounts matching the `account_id`.
1991 ///
1992 /// # Panics
1993 ///
1994 /// Panics if the cache is already mutably borrowed.
1995 #[must_use]
1996 pub fn accounts(&self, account_id: &AccountId) -> Vec<AccountAny> {
1997 self.cache()
1998 .accounts(account_id)
1999 .into_iter()
2000 .map(|account| account.cloned())
2001 .collect()
2002 }
2003
2004 /// Returns owned copies of every account in the cache.
2005 ///
2006 /// # Panics
2007 ///
2008 /// Panics if the cache is already mutably borrowed.
2009 #[must_use]
2010 pub fn accounts_all(&self) -> Vec<AccountAny> {
2011 self.cache().accounts_all_owned()
2012 }
2013
2014 fn cache(&self) -> Ref<'_, Cache> {
2015 self.try_cache("cache read")
2016 .unwrap_or_else(|e| panic!("{e}"))
2017 }
2018
2019 fn try_cache(&self, operation: &'static str) -> Result<Ref<'_, Cache>, ComponentAccessError> {
2020 self.cache
2021 .try_borrow()
2022 .map_err(|_| ComponentAccessError::ReadConflict {
2023 resource: "cache",
2024 operation,
2025 })
2026 }
2027}