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 an error if:
335 /// - The order is not present in the cache.
336 /// - 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 an error if:
827 /// - The order list is not present in the cache.
828 /// - 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 an error if:
973 /// - The position is not present in the cache.
974 /// - 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.
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 /// For `Mid`, returns `None` if no quote is cached or either price is a sentinel.
1240 /// For quote precision `p`, the midpoint has precision `p + 1` when exactly representable,
1241 /// otherwise `p`, rounded half-even if necessary. The fallback applies when the precision
1242 /// limit or raw range rules out `p + 1`, and when `p` is the maximum float precision (16),
1243 /// so a midpoint of a float-convertible quote stays float-convertible.
1244 ///
1245 /// # Panics
1246 ///
1247 /// Panics if the cache is already mutably borrowed.
1248 #[must_use]
1249 pub fn price(&self, instrument_id: &InstrumentId, price_type: PriceType) -> Option<Price> {
1250 self.cache().price(instrument_id, price_type)
1251 }
1252
1253 /// Returns all quotes for the `instrument_id` (if found).
1254 ///
1255 /// # Panics
1256 ///
1257 /// Panics if the cache is already mutably borrowed.
1258 #[must_use]
1259 pub fn quotes(&self, instrument_id: &InstrumentId) -> Option<Vec<QuoteTick>> {
1260 self.cache().quotes(instrument_id)
1261 }
1262
1263 /// Returns all trades for the `instrument_id` (if found).
1264 ///
1265 /// # Panics
1266 ///
1267 /// Panics if the cache is already mutably borrowed.
1268 #[must_use]
1269 pub fn trades(&self, instrument_id: &InstrumentId) -> Option<Vec<TradeTick>> {
1270 self.cache().trades(instrument_id)
1271 }
1272
1273 /// Returns all mark price updates for the `instrument_id` (if found).
1274 ///
1275 /// # Panics
1276 ///
1277 /// Panics if the cache is already mutably borrowed.
1278 #[must_use]
1279 pub fn mark_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<MarkPriceUpdate>> {
1280 self.cache().mark_prices(instrument_id)
1281 }
1282
1283 /// Returns all index price updates for the `instrument_id` (if found).
1284 ///
1285 /// # Panics
1286 ///
1287 /// Panics if the cache is already mutably borrowed.
1288 #[must_use]
1289 pub fn index_prices(&self, instrument_id: &InstrumentId) -> Option<Vec<IndexPriceUpdate>> {
1290 self.cache().index_prices(instrument_id)
1291 }
1292
1293 /// Returns all funding rate updates for the `instrument_id` (if found).
1294 ///
1295 /// # Panics
1296 ///
1297 /// Panics if the cache is already mutably borrowed.
1298 #[must_use]
1299 pub fn funding_rates(&self, instrument_id: &InstrumentId) -> Option<Vec<FundingRateUpdate>> {
1300 self.cache().funding_rates(instrument_id)
1301 }
1302
1303 /// Returns all instrument status updates for the `instrument_id` (if found).
1304 ///
1305 /// # Panics
1306 ///
1307 /// Panics if the cache is already mutably borrowed.
1308 #[must_use]
1309 pub fn instrument_statuses(
1310 &self,
1311 instrument_id: &InstrumentId,
1312 ) -> Option<Vec<InstrumentStatus>> {
1313 self.cache().instrument_statuses(instrument_id)
1314 }
1315
1316 /// Returns all bars for the `bar_type` (if found).
1317 ///
1318 /// # Panics
1319 ///
1320 /// Panics if the cache is already mutably borrowed.
1321 #[must_use]
1322 pub fn bars(&self, bar_type: &BarType) -> Option<Vec<Bar>> {
1323 self.cache().bars(bar_type)
1324 }
1325
1326 /// Returns an owned copy of the order book for the `instrument_id` (if found).
1327 ///
1328 /// # Panics
1329 ///
1330 /// Panics if the cache is already mutably borrowed.
1331 #[must_use]
1332 pub fn order_book(&self, instrument_id: &InstrumentId) -> Option<OrderBook> {
1333 self.cache().order_book(instrument_id).cloned()
1334 }
1335
1336 /// Returns an owned copy of the order book for the `instrument_id`.
1337 ///
1338 /// # Errors
1339 ///
1340 /// Returns an error if:
1341 /// - The order book is not present in the cache.
1342 /// - The cache is already mutably borrowed.
1343 pub fn try_order_book(
1344 &self,
1345 instrument_id: &InstrumentId,
1346 ) -> Result<OrderBook, OrderBookLookupError> {
1347 self.try_cache("try_order_book")?
1348 .try_order_book(instrument_id)
1349 .cloned()
1350 }
1351
1352 /// Returns an owned copy of the own order book for the `instrument_id` (if found).
1353 ///
1354 /// # Panics
1355 ///
1356 /// Panics if the cache is already mutably borrowed.
1357 #[must_use]
1358 pub fn own_order_book(&self, instrument_id: &InstrumentId) -> Option<OwnOrderBook> {
1359 self.cache().own_order_book(instrument_id).cloned()
1360 }
1361
1362 /// Returns an owned copy of the own order book for the `instrument_id`.
1363 ///
1364 /// # Errors
1365 ///
1366 /// Returns an error if:
1367 /// - The own order book is not present in the cache.
1368 /// - The cache is already mutably borrowed.
1369 pub fn try_own_order_book(
1370 &self,
1371 instrument_id: &InstrumentId,
1372 ) -> Result<OwnOrderBook, OwnOrderBookLookupError> {
1373 self.try_cache("try_own_order_book")?
1374 .try_own_order_book(instrument_id)
1375 .cloned()
1376 }
1377
1378 /// Returns the latest quote for the `instrument_id` (if found).
1379 ///
1380 /// # Panics
1381 ///
1382 /// Panics if the cache is already mutably borrowed.
1383 #[must_use]
1384 pub fn quote(&self, instrument_id: &InstrumentId) -> Option<QuoteTick> {
1385 self.cache().quote(instrument_id).copied()
1386 }
1387
1388 /// Returns the quote at `index` for the `instrument_id` (if found).
1389 ///
1390 /// Index 0 is the most recent.
1391 ///
1392 /// # Panics
1393 ///
1394 /// Panics if the cache is already mutably borrowed.
1395 #[must_use]
1396 pub fn quote_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<QuoteTick> {
1397 self.cache().quote_at_index(instrument_id, index).copied()
1398 }
1399
1400 /// Returns the latest trade for the `instrument_id` (if found).
1401 ///
1402 /// # Panics
1403 ///
1404 /// Panics if the cache is already mutably borrowed.
1405 #[must_use]
1406 pub fn trade(&self, instrument_id: &InstrumentId) -> Option<TradeTick> {
1407 self.cache().trade(instrument_id).copied()
1408 }
1409
1410 /// Returns the trade at `index` for the `instrument_id` (if found).
1411 ///
1412 /// Index 0 is the most recent.
1413 ///
1414 /// # Panics
1415 ///
1416 /// Panics if the cache is already mutably borrowed.
1417 #[must_use]
1418 pub fn trade_at_index(&self, instrument_id: &InstrumentId, index: usize) -> Option<TradeTick> {
1419 self.cache().trade_at_index(instrument_id, index).copied()
1420 }
1421
1422 /// Returns the latest mark price update for the `instrument_id` (if found).
1423 ///
1424 /// # Panics
1425 ///
1426 /// Panics if the cache is already mutably borrowed.
1427 #[must_use]
1428 pub fn mark_price(&self, instrument_id: &InstrumentId) -> Option<MarkPriceUpdate> {
1429 self.cache().mark_price(instrument_id).copied()
1430 }
1431
1432 /// Returns the latest index price update for the `instrument_id` (if found).
1433 ///
1434 /// # Panics
1435 ///
1436 /// Panics if the cache is already mutably borrowed.
1437 #[must_use]
1438 pub fn index_price(&self, instrument_id: &InstrumentId) -> Option<IndexPriceUpdate> {
1439 self.cache().index_price(instrument_id).copied()
1440 }
1441
1442 /// Returns the latest funding rate update for the `instrument_id` (if found).
1443 ///
1444 /// # Panics
1445 ///
1446 /// Panics if the cache is already mutably borrowed.
1447 #[must_use]
1448 pub fn funding_rate(&self, instrument_id: &InstrumentId) -> Option<FundingRateUpdate> {
1449 self.cache().funding_rate(instrument_id).copied()
1450 }
1451
1452 /// Returns the latest instrument status update for the `instrument_id` (if found).
1453 ///
1454 /// # Panics
1455 ///
1456 /// Panics if the cache is already mutably borrowed.
1457 #[must_use]
1458 pub fn instrument_status(&self, instrument_id: &InstrumentId) -> Option<InstrumentStatus> {
1459 self.cache().instrument_status(instrument_id).copied()
1460 }
1461
1462 /// Returns the cached close for the `instrument_id` (if found).
1463 ///
1464 /// # Panics
1465 ///
1466 /// Panics if the cache is already mutably borrowed.
1467 #[must_use]
1468 pub fn instrument_close(&self, instrument_id: &InstrumentId) -> Option<InstrumentClose> {
1469 self.cache().instrument_close(instrument_id).copied()
1470 }
1471
1472 /// Returns the latest bar for the `bar_type` (if found).
1473 ///
1474 /// # Panics
1475 ///
1476 /// Panics if the cache is already mutably borrowed.
1477 #[must_use]
1478 pub fn bar(&self, bar_type: &BarType) -> Option<Bar> {
1479 self.cache().bar(bar_type).copied()
1480 }
1481
1482 /// Returns the bar at `index` for the `bar_type` (if found).
1483 ///
1484 /// Index 0 is the most recent.
1485 ///
1486 /// # Panics
1487 ///
1488 /// Panics if the cache is already mutably borrowed.
1489 #[must_use]
1490 pub fn bar_at_index(&self, bar_type: &BarType, index: usize) -> Option<Bar> {
1491 self.cache().bar_at_index(bar_type, index).copied()
1492 }
1493
1494 /// Returns the order book update count for the `instrument_id`.
1495 ///
1496 /// # Panics
1497 ///
1498 /// Panics if the cache is already mutably borrowed.
1499 #[must_use]
1500 pub fn book_update_count(&self, instrument_id: &InstrumentId) -> usize {
1501 self.cache().book_update_count(instrument_id)
1502 }
1503
1504 /// Returns the quote tick count for the `instrument_id`.
1505 ///
1506 /// # Panics
1507 ///
1508 /// Panics if the cache is already mutably borrowed.
1509 #[must_use]
1510 pub fn quote_count(&self, instrument_id: &InstrumentId) -> usize {
1511 self.cache().quote_count(instrument_id)
1512 }
1513
1514 /// Returns the trade tick count for the `instrument_id`.
1515 ///
1516 /// # Panics
1517 ///
1518 /// Panics if the cache is already mutably borrowed.
1519 #[must_use]
1520 pub fn trade_count(&self, instrument_id: &InstrumentId) -> usize {
1521 self.cache().trade_count(instrument_id)
1522 }
1523
1524 /// Returns the mark price update count for the `instrument_id`.
1525 ///
1526 /// # Panics
1527 ///
1528 /// Panics if the cache is already mutably borrowed.
1529 #[must_use]
1530 pub fn mark_price_count(&self, instrument_id: &InstrumentId) -> usize {
1531 self.cache().mark_price_count(instrument_id)
1532 }
1533
1534 /// Returns the index price update count for the `instrument_id`.
1535 ///
1536 /// # Panics
1537 ///
1538 /// Panics if the cache is already mutably borrowed.
1539 #[must_use]
1540 pub fn index_price_count(&self, instrument_id: &InstrumentId) -> usize {
1541 self.cache().index_price_count(instrument_id)
1542 }
1543
1544 /// Returns the funding rate update count for the `instrument_id`.
1545 ///
1546 /// # Panics
1547 ///
1548 /// Panics if the cache is already mutably borrowed.
1549 #[must_use]
1550 pub fn funding_rate_count(&self, instrument_id: &InstrumentId) -> usize {
1551 self.cache().funding_rate_count(instrument_id)
1552 }
1553
1554 /// Returns the instrument status update count for the `instrument_id`.
1555 ///
1556 /// # Panics
1557 ///
1558 /// Panics if the cache is already mutably borrowed.
1559 #[must_use]
1560 pub fn instrument_status_count(&self, instrument_id: &InstrumentId) -> usize {
1561 self.cache().instrument_status_count(instrument_id)
1562 }
1563
1564 /// Returns the bar count for the `bar_type`.
1565 ///
1566 /// # Panics
1567 ///
1568 /// Panics if the cache is already mutably borrowed.
1569 #[must_use]
1570 pub fn bar_count(&self, bar_type: &BarType) -> usize {
1571 self.cache().bar_count(bar_type)
1572 }
1573
1574 /// Returns whether the cache contains an order book for the `instrument_id`.
1575 ///
1576 /// # Panics
1577 ///
1578 /// Panics if the cache is already mutably borrowed.
1579 #[must_use]
1580 pub fn has_order_book(&self, instrument_id: &InstrumentId) -> bool {
1581 self.cache().has_order_book(instrument_id)
1582 }
1583
1584 /// Returns whether the cache contains quotes for the `instrument_id`.
1585 ///
1586 /// # Panics
1587 ///
1588 /// Panics if the cache is already mutably borrowed.
1589 #[must_use]
1590 pub fn has_quote_ticks(&self, instrument_id: &InstrumentId) -> bool {
1591 self.cache().has_quote_ticks(instrument_id)
1592 }
1593
1594 /// Returns whether the cache contains trades for the `instrument_id`.
1595 ///
1596 /// # Panics
1597 ///
1598 /// Panics if the cache is already mutably borrowed.
1599 #[must_use]
1600 pub fn has_trade_ticks(&self, instrument_id: &InstrumentId) -> bool {
1601 self.cache().has_trade_ticks(instrument_id)
1602 }
1603
1604 /// Returns whether the cache contains mark price updates for the `instrument_id`.
1605 ///
1606 /// # Panics
1607 ///
1608 /// Panics if the cache is already mutably borrowed.
1609 #[must_use]
1610 pub fn has_mark_prices(&self, instrument_id: &InstrumentId) -> bool {
1611 self.cache().has_mark_prices(instrument_id)
1612 }
1613
1614 /// Returns whether the cache contains index price updates for the `instrument_id`.
1615 ///
1616 /// # Panics
1617 ///
1618 /// Panics if the cache is already mutably borrowed.
1619 #[must_use]
1620 pub fn has_index_prices(&self, instrument_id: &InstrumentId) -> bool {
1621 self.cache().has_index_prices(instrument_id)
1622 }
1623
1624 /// Returns whether the cache contains funding rate updates for the `instrument_id`.
1625 ///
1626 /// # Panics
1627 ///
1628 /// Panics if the cache is already mutably borrowed.
1629 #[must_use]
1630 pub fn has_funding_rates(&self, instrument_id: &InstrumentId) -> bool {
1631 self.cache().has_funding_rates(instrument_id)
1632 }
1633
1634 /// Returns whether the cache contains instrument status updates for the `instrument_id`.
1635 ///
1636 /// # Panics
1637 ///
1638 /// Panics if the cache is already mutably borrowed.
1639 #[must_use]
1640 pub fn has_instrument_statuses(&self, instrument_id: &InstrumentId) -> bool {
1641 self.cache().has_instrument_statuses(instrument_id)
1642 }
1643
1644 /// Returns whether the cache contains a close for the `instrument_id`.
1645 ///
1646 /// # Panics
1647 ///
1648 /// Panics if the cache is already mutably borrowed.
1649 #[must_use]
1650 pub fn has_instrument_close(&self, instrument_id: &InstrumentId) -> bool {
1651 self.cache().has_instrument_close(instrument_id)
1652 }
1653
1654 /// Returns whether the cache contains bars for the `bar_type`.
1655 ///
1656 /// # Panics
1657 ///
1658 /// Panics if the cache is already mutably borrowed.
1659 #[must_use]
1660 pub fn has_bars(&self, bar_type: &BarType) -> bool {
1661 self.cache().has_bars(bar_type)
1662 }
1663
1664 /// Returns the exchange rate for the given currencies and price type (if available).
1665 ///
1666 /// # Panics
1667 ///
1668 /// Panics if the cache is already mutably borrowed.
1669 #[must_use]
1670 pub fn get_xrate(
1671 &self,
1672 venue: Venue,
1673 from_currency: Currency,
1674 to_currency: Currency,
1675 price_type: PriceType,
1676 ) -> Option<Decimal> {
1677 self.cache()
1678 .get_xrate(venue, from_currency, to_currency, price_type)
1679 }
1680
1681 /// Returns the mark exchange rate for the currency pair (if set).
1682 ///
1683 /// # Panics
1684 ///
1685 /// Panics if the cache is already mutably borrowed.
1686 #[must_use]
1687 pub fn get_mark_xrate(&self, from_currency: Currency, to_currency: Currency) -> Option<f64> {
1688 self.cache().get_mark_xrate(from_currency, to_currency)
1689 }
1690
1691 /// Returns the yield curve for the `key` (if found).
1692 ///
1693 /// # Panics
1694 ///
1695 /// Panics if the cache is already mutably borrowed.
1696 #[must_use]
1697 pub fn yield_curve(&self, key: &str) -> Option<Box<dyn Fn(f64) -> f64>> {
1698 self.cache().yield_curve(key)
1699 }
1700
1701 /// Returns an owned copy of the greeks data for the `instrument_id` (if found).
1702 ///
1703 /// # Panics
1704 ///
1705 /// Panics if the cache is already mutably borrowed.
1706 #[must_use]
1707 pub fn greeks(&self, instrument_id: &InstrumentId) -> Option<GreeksData> {
1708 self.cache().greeks(instrument_id)
1709 }
1710
1711 /// Returns exchange-provided option greeks for the `instrument_id` (if found).
1712 ///
1713 /// # Panics
1714 ///
1715 /// Panics if the cache is already mutably borrowed.
1716 #[must_use]
1717 pub fn option_greeks(&self, instrument_id: &InstrumentId) -> Option<OptionGreeks> {
1718 self.cache().option_greeks(instrument_id).copied()
1719 }
1720
1721 /// Returns the currency for the `code` (if found).
1722 ///
1723 /// # Panics
1724 ///
1725 /// Panics if the cache is already mutably borrowed.
1726 #[must_use]
1727 pub fn currency(&self, code: &Ustr) -> Option<Currency> {
1728 self.cache().currency(code).copied()
1729 }
1730
1731 /// Returns the currency for the `code`.
1732 ///
1733 /// # Errors
1734 ///
1735 /// Returns an error if:
1736 /// - The currency is not present in the cache.
1737 /// - The cache is already mutably borrowed.
1738 pub fn try_currency(&self, code: &Ustr) -> Result<Currency, CurrencyLookupError> {
1739 self.try_cache("try_currency")?.try_currency(code).copied()
1740 }
1741
1742 /// Returns an owned copy of the instrument for the `instrument_id` (if found).
1743 ///
1744 /// # Panics
1745 ///
1746 /// Panics if the cache is already mutably borrowed.
1747 #[must_use]
1748 pub fn instrument(&self, instrument_id: &InstrumentId) -> Option<InstrumentAny> {
1749 self.cache().instrument(instrument_id).cloned()
1750 }
1751
1752 /// Returns an owned copy of the instrument for the `instrument_id`.
1753 ///
1754 /// # Errors
1755 ///
1756 /// Returns an error if:
1757 /// - The instrument is not present in the cache.
1758 /// - The cache is already mutably borrowed.
1759 pub fn try_instrument(
1760 &self,
1761 instrument_id: &InstrumentId,
1762 ) -> Result<InstrumentAny, InstrumentLookupError> {
1763 self.try_cache("try_instrument")?
1764 .try_instrument(instrument_id)
1765 .cloned()
1766 }
1767
1768 /// Returns the instrument IDs in the cache, optionally filtered by `venue`.
1769 ///
1770 /// # Panics
1771 ///
1772 /// Panics if the cache is already mutably borrowed.
1773 #[must_use]
1774 pub fn instrument_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1775 self.cache()
1776 .instrument_ids(venue)
1777 .into_iter()
1778 .copied()
1779 .collect()
1780 }
1781
1782 /// Returns owned copies of all instruments for the `venue`.
1783 ///
1784 /// # Panics
1785 ///
1786 /// Panics if the cache is already mutably borrowed.
1787 #[must_use]
1788 pub fn instruments(&self, venue: &Venue, underlying: Option<&Ustr>) -> Vec<InstrumentAny> {
1789 self.cache()
1790 .instruments(venue, underlying)
1791 .into_iter()
1792 .cloned()
1793 .collect()
1794 }
1795
1796 /// Returns owned copies of all instruments for the `venue`, parent `root`, and instrument
1797 /// `class`.
1798 ///
1799 /// # Panics
1800 ///
1801 /// Panics if the cache is already mutably borrowed.
1802 #[must_use]
1803 pub fn instruments_by_parent(
1804 &self,
1805 venue: &Venue,
1806 root: &Ustr,
1807 class: InstrumentClass,
1808 ) -> Vec<InstrumentAny> {
1809 self.cache()
1810 .instruments_by_parent(venue, root, class)
1811 .into_iter()
1812 .cloned()
1813 .collect()
1814 }
1815
1816 /// Returns the bar types in the cache, optionally filtered by instrument and price type.
1817 ///
1818 /// # Panics
1819 ///
1820 /// Panics if the cache is already mutably borrowed.
1821 #[must_use]
1822 pub fn bar_types(
1823 &self,
1824 instrument_id: Option<&InstrumentId>,
1825 price_type: Option<&PriceType>,
1826 aggregation_source: AggregationSource,
1827 ) -> Vec<BarType> {
1828 self.cache()
1829 .bar_types(instrument_id, price_type, aggregation_source)
1830 .into_iter()
1831 .copied()
1832 .collect()
1833 }
1834
1835 /// Returns an owned copy of the synthetic instrument for the `instrument_id` (if found).
1836 ///
1837 /// # Panics
1838 ///
1839 /// Panics if the cache is already mutably borrowed.
1840 #[must_use]
1841 pub fn synthetic(&self, instrument_id: &InstrumentId) -> Option<SyntheticInstrument> {
1842 self.cache().synthetic(instrument_id).cloned()
1843 }
1844
1845 /// Returns an owned copy of the synthetic instrument for the `instrument_id`.
1846 ///
1847 /// # Errors
1848 ///
1849 /// Returns an error if:
1850 /// - The synthetic instrument is not present
1851 /// in the cache.
1852 /// - The cache is already mutably borrowed.
1853 pub fn try_synthetic(
1854 &self,
1855 instrument_id: &InstrumentId,
1856 ) -> Result<SyntheticInstrument, SyntheticInstrumentLookupError> {
1857 self.try_cache("try_synthetic")?
1858 .try_synthetic(instrument_id)
1859 .cloned()
1860 }
1861
1862 /// Returns the synthetic instrument IDs in the cache.
1863 ///
1864 /// # Panics
1865 ///
1866 /// Panics if the cache is already mutably borrowed.
1867 #[must_use]
1868 pub fn synthetic_ids(&self) -> Vec<InstrumentId> {
1869 self.cache().synthetic_ids().into_iter().copied().collect()
1870 }
1871
1872 /// Returns owned copies of all synthetic instruments in the cache.
1873 ///
1874 /// # Panics
1875 ///
1876 /// Panics if the cache is already mutably borrowed.
1877 #[must_use]
1878 pub fn synthetics(&self) -> Vec<SyntheticInstrument> {
1879 self.cache().synthetics().into_iter().cloned().collect()
1880 }
1881
1882 /// Returns an owned copy of the pool for the `instrument_id` (if found).
1883 ///
1884 /// # Panics
1885 ///
1886 /// Panics if the cache is already mutably borrowed.
1887 #[cfg(feature = "defi")]
1888 #[must_use]
1889 pub fn pool(&self, instrument_id: &InstrumentId) -> Option<Pool> {
1890 self.cache().pool(instrument_id).cloned()
1891 }
1892
1893 /// Returns the pool instrument IDs in the cache, optionally filtered by `venue`.
1894 ///
1895 /// # Panics
1896 ///
1897 /// Panics if the cache is already mutably borrowed.
1898 #[cfg(feature = "defi")]
1899 #[must_use]
1900 pub fn pool_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1901 self.cache().pool_ids(venue)
1902 }
1903
1904 /// Returns owned copies of all pools in the cache, optionally filtered by `venue`.
1905 ///
1906 /// # Panics
1907 ///
1908 /// Panics if the cache is already mutably borrowed.
1909 #[cfg(feature = "defi")]
1910 #[must_use]
1911 pub fn pools(&self, venue: Option<&Venue>) -> Vec<Pool> {
1912 self.cache().pools(venue).into_iter().cloned().collect()
1913 }
1914
1915 /// Returns an owned copy of the pool profiler for the `instrument_id` (if found).
1916 ///
1917 /// # Panics
1918 ///
1919 /// Panics if the cache is already mutably borrowed.
1920 #[cfg(feature = "defi")]
1921 #[must_use]
1922 pub fn pool_profiler(&self, instrument_id: &InstrumentId) -> Option<PoolProfiler> {
1923 self.cache().pool_profiler(instrument_id).cloned()
1924 }
1925
1926 /// Returns the pool profiler instrument IDs in the cache, optionally filtered by `venue`.
1927 ///
1928 /// # Panics
1929 ///
1930 /// Panics if the cache is already mutably borrowed.
1931 #[cfg(feature = "defi")]
1932 #[must_use]
1933 pub fn pool_profiler_ids(&self, venue: Option<&Venue>) -> Vec<InstrumentId> {
1934 self.cache().pool_profiler_ids(venue)
1935 }
1936
1937 /// Returns owned copies of all pool profilers in the cache, optionally filtered by `venue`.
1938 ///
1939 /// # Panics
1940 ///
1941 /// Panics if the cache is already mutably borrowed.
1942 #[cfg(feature = "defi")]
1943 #[must_use]
1944 pub fn pool_profilers(&self, venue: Option<&Venue>) -> Vec<PoolProfiler> {
1945 self.cache()
1946 .pool_profilers(venue)
1947 .into_iter()
1948 .cloned()
1949 .collect()
1950 }
1951
1952 /// Returns an owned copy of the account for the `account_id` (if found).
1953 ///
1954 /// # Panics
1955 ///
1956 /// Panics if the cache is already mutably borrowed.
1957 #[must_use]
1958 pub fn account(&self, account_id: &AccountId) -> Option<AccountAny> {
1959 self.cache().account_owned(account_id)
1960 }
1961
1962 /// Returns an owned copy of the account for the `account_id`.
1963 ///
1964 /// # Errors
1965 ///
1966 /// Returns an error if:
1967 /// - The account is not present in the cache.
1968 /// - The cache is already mutably borrowed.
1969 pub fn try_account(&self, account_id: &AccountId) -> Result<AccountAny, AccountLookupError> {
1970 self.try_cache("try_account")?
1971 .try_account(account_id)
1972 .map(|account| account.cloned())
1973 }
1974
1975 /// Returns an owned copy of the account for the `venue` (if found).
1976 ///
1977 /// Returns `None` when more than one account is issued under the `venue`.
1978 ///
1979 /// # Panics
1980 ///
1981 /// Panics if the cache is already mutably borrowed.
1982 #[must_use]
1983 pub fn account_for_venue(&self, venue: &Venue) -> Option<AccountAny> {
1984 self.cache().account_for_venue_owned(venue)
1985 }
1986
1987 /// Returns the account ID for the `venue` (if found).
1988 ///
1989 /// Returns `None` when more than one account is issued under the `venue`.
1990 ///
1991 /// # Panics
1992 ///
1993 /// Panics if the cache is already mutably borrowed.
1994 #[must_use]
1995 pub fn account_id(&self, venue: &Venue) -> Option<AccountId> {
1996 self.cache().account_id(venue).copied()
1997 }
1998
1999 /// Returns owned copies of all accounts matching the `account_id`.
2000 ///
2001 /// # Panics
2002 ///
2003 /// Panics if the cache is already mutably borrowed.
2004 #[must_use]
2005 pub fn accounts(&self, account_id: &AccountId) -> Vec<AccountAny> {
2006 self.cache()
2007 .accounts(account_id)
2008 .into_iter()
2009 .map(|account| account.cloned())
2010 .collect()
2011 }
2012
2013 /// Returns owned copies of every account in the cache.
2014 ///
2015 /// # Panics
2016 ///
2017 /// Panics if the cache is already mutably borrowed.
2018 #[must_use]
2019 pub fn accounts_all(&self) -> Vec<AccountAny> {
2020 self.cache().accounts_all_owned()
2021 }
2022
2023 fn cache(&self) -> Ref<'_, Cache> {
2024 self.try_cache("cache read")
2025 .unwrap_or_else(|e| panic!("{e}"))
2026 }
2027
2028 fn try_cache(&self, operation: &'static str) -> Result<Ref<'_, Cache>, ComponentAccessError> {
2029 self.cache
2030 .try_borrow()
2031 .map_err(|_| ComponentAccessError::ReadConflict {
2032 resource: "cache",
2033 operation,
2034 })
2035 }
2036}