Skip to main content

nautilus_common/cache/
database.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//! Provides a `Cache` database backing.
17
18use std::fmt::Debug;
19
20use ahash::AHashMap;
21use bytes::Bytes;
22use nautilus_core::{UUID4, UnixNanos};
23use nautilus_model::{
24    accounts::AccountAny,
25    data::{
26        Bar, CustomData, DataType, FundingRateUpdate, QuoteTick, TradeTick,
27        greeks::{GreeksData, YieldCurveData},
28    },
29    events::{OrderEventAny, OrderSnapshot, position::snapshot::PositionSnapshot},
30    identifiers::{
31        AccountId, ClientId, ClientOrderId, ComponentId, InstrumentId, PositionId, StrategyId,
32        TraderId, VenueOrderId,
33    },
34    instruments::{InstrumentAny, SyntheticInstrument},
35    orderbook::OrderBook,
36    orders::OrderAny,
37    position::Position,
38    types::{Currency, Money},
39};
40use ustr::Ustr;
41
42use super::config::CacheConfig;
43use crate::signal::Signal;
44
45#[derive(Debug, Default)]
46pub struct CacheMap {
47    pub currencies: AHashMap<Ustr, Currency>,
48    pub instruments: AHashMap<InstrumentId, InstrumentAny>,
49    pub synthetics: AHashMap<InstrumentId, SyntheticInstrument>,
50    pub accounts: AHashMap<AccountId, AccountAny>,
51    pub orders: AHashMap<ClientOrderId, OrderAny>,
52    pub positions: AHashMap<PositionId, Position>,
53    pub greeks: AHashMap<InstrumentId, GreeksData>,
54    pub yield_curves: AHashMap<String, YieldCurveData>,
55}
56
57/// Factory for constructing cache database adapters at runtime.
58///
59/// Implementations own the concrete database configuration and return the transport-neutral
60/// [`CacheDatabaseAdapter`] surface used by the cache.
61#[async_trait::async_trait]
62pub trait CacheDatabaseFactory: Debug + Send + Sync {
63    /// Creates a cache database adapter for the given cache runtime.
64    ///
65    /// # Errors
66    ///
67    /// Returns an error if adapter construction or connection setup fails.
68    async fn create(
69        &self,
70        trader_id: TraderId,
71        instance_id: UUID4,
72        config: CacheConfig,
73    ) -> anyhow::Result<Box<dyn CacheDatabaseAdapter>>;
74}
75
76#[async_trait::async_trait]
77pub trait CacheDatabaseAdapter {
78    /// Closes the cache database connection.
79    ///
80    /// # Errors
81    ///
82    /// Returns an error if the database fails to close properly.
83    fn close(&mut self) -> anyhow::Result<()>;
84
85    /// Flushes any pending changes to the database.
86    ///
87    /// # Errors
88    ///
89    /// Returns an error if flushing changes fails.
90    fn flush(&mut self) -> anyhow::Result<()>;
91
92    /// Loads all cached data into memory.
93    ///
94    /// # Errors
95    ///
96    /// Returns an error if loading data from the database fails.
97    async fn load_all(&self) -> anyhow::Result<CacheMap>;
98
99    /// Loads raw key-value data from the database.
100    ///
101    /// # Errors
102    ///
103    /// Returns an error if the load operation fails.
104    fn load(&self) -> anyhow::Result<AHashMap<String, Bytes>>;
105
106    /// Loads all currencies from the cache.
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if loading currencies fails.
111    async fn load_currencies(&self) -> anyhow::Result<AHashMap<Ustr, Currency>>;
112
113    /// Loads all instruments from the cache.
114    ///
115    /// # Errors
116    ///
117    /// Returns an error if loading instruments fails.
118    async fn load_instruments(&self) -> anyhow::Result<AHashMap<InstrumentId, InstrumentAny>>;
119
120    /// Loads all synthetic instruments from the cache.
121    ///
122    /// # Errors
123    ///
124    /// Returns an error if loading synthetic instruments fails.
125    async fn load_synthetics(&self) -> anyhow::Result<AHashMap<InstrumentId, SyntheticInstrument>>;
126
127    /// Loads all accounts from the cache.
128    ///
129    /// # Errors
130    ///
131    /// Returns an error if loading accounts fails.
132    async fn load_accounts(&self) -> anyhow::Result<AHashMap<AccountId, AccountAny>>;
133
134    /// Loads all orders from the cache.
135    ///
136    /// # Errors
137    ///
138    /// Returns an error if loading orders fails.
139    async fn load_orders(&self) -> anyhow::Result<AHashMap<ClientOrderId, OrderAny>>;
140
141    /// Loads all positions from the cache.
142    ///
143    /// # Errors
144    ///
145    /// Returns an error if loading positions fails.
146    async fn load_positions(&self) -> anyhow::Result<AHashMap<PositionId, Position>>;
147
148    /// Loads all [`GreeksData`] from the cache.
149    ///
150    /// # Errors
151    ///
152    /// Returns an error if loading greeks data fails.
153    async fn load_greeks(&self) -> anyhow::Result<AHashMap<InstrumentId, GreeksData>> {
154        Ok(AHashMap::new())
155    }
156
157    /// Loads all [`YieldCurveData`] from the cache.
158    ///
159    /// # Errors
160    ///
161    /// Returns an error if loading yield curve data fails.
162    async fn load_yield_curves(&self) -> anyhow::Result<AHashMap<String, YieldCurveData>> {
163        Ok(AHashMap::new())
164    }
165
166    /// Loads mapping from order IDs to position IDs.
167    ///
168    /// # Errors
169    ///
170    /// Returns an error if loading the index order-position mapping fails.
171    fn load_index_order_position(&self) -> anyhow::Result<AHashMap<ClientOrderId, PositionId>>;
172
173    /// Loads mapping from order IDs to client IDs.
174    ///
175    /// # Errors
176    ///
177    /// Returns an error if loading the index order-client mapping fails.
178    fn load_index_order_client(&self) -> anyhow::Result<AHashMap<ClientOrderId, ClientId>>;
179
180    /// Loads a single currency by code.
181    ///
182    /// # Errors
183    ///
184    /// Returns an error if loading a single currency fails.
185    async fn load_currency(&self, code: &Ustr) -> anyhow::Result<Option<Currency>>;
186
187    /// Loads a single instrument by ID.
188    ///
189    /// # Errors
190    ///
191    /// Returns an error if loading a single instrument fails.
192    async fn load_instrument(
193        &self,
194        instrument_id: &InstrumentId,
195    ) -> anyhow::Result<Option<InstrumentAny>>;
196
197    /// Loads a single synthetic instrument by ID.
198    ///
199    /// # Errors
200    ///
201    /// Returns an error if loading a single synthetic instrument fails.
202    async fn load_synthetic(
203        &self,
204        instrument_id: &InstrumentId,
205    ) -> anyhow::Result<Option<SyntheticInstrument>>;
206
207    /// Loads a single account by ID.
208    ///
209    /// # Errors
210    ///
211    /// Returns an error if loading a single account fails.
212    async fn load_account(&self, account_id: &AccountId) -> anyhow::Result<Option<AccountAny>>;
213
214    /// Loads a single order by client order ID.
215    ///
216    /// # Errors
217    ///
218    /// Returns an error if loading a single order fails.
219    async fn load_order(&self, client_order_id: &ClientOrderId)
220    -> anyhow::Result<Option<OrderAny>>;
221
222    /// Loads a single position by position ID.
223    ///
224    /// # Errors
225    ///
226    /// Returns an error if loading a single position fails.
227    async fn load_position(&self, position_id: &PositionId) -> anyhow::Result<Option<Position>>;
228
229    /// Loads actor state by component ID.
230    ///
231    /// # Errors
232    ///
233    /// Returns an error if loading actor state fails.
234    fn load_actor(&self, component_id: &ComponentId) -> anyhow::Result<AHashMap<String, Bytes>>;
235
236    /// Loads strategy state by strategy ID.
237    ///
238    /// # Errors
239    ///
240    /// Returns an error if loading strategy state fails.
241    fn load_strategy(&self, strategy_id: &StrategyId) -> anyhow::Result<AHashMap<String, Bytes>>;
242
243    /// Loads signals by name.
244    ///
245    /// # Errors
246    ///
247    /// Returns an error if loading signals fails.
248    fn load_signals(&self, name: &str) -> anyhow::Result<Vec<Signal>>;
249
250    /// Loads custom data by data type.
251    ///
252    /// # Errors
253    ///
254    /// Returns an error if loading custom data fails.
255    fn load_custom_data(&self, data_type: &DataType) -> anyhow::Result<Vec<CustomData>>;
256
257    /// Loads an order snapshot by client order ID.
258    ///
259    /// # Errors
260    ///
261    /// Returns an error if loading the order snapshot fails.
262    fn load_order_snapshot(
263        &self,
264        client_order_id: &ClientOrderId,
265    ) -> anyhow::Result<Option<OrderSnapshot>>;
266
267    /// Loads a position snapshot by position ID.
268    ///
269    /// # Errors
270    ///
271    /// Returns an error if loading the position snapshot fails.
272    fn load_position_snapshot(
273        &self,
274        position_id: &PositionId,
275    ) -> anyhow::Result<Option<PositionSnapshot>>;
276
277    /// Loads quote ticks by instrument ID.
278    ///
279    /// # Errors
280    ///
281    /// Returns an error if loading quotes fails.
282    fn load_quotes(&self, instrument_id: &InstrumentId) -> anyhow::Result<Vec<QuoteTick>>;
283
284    /// Loads trade ticks by instrument ID.
285    ///
286    /// # Errors
287    ///
288    /// Returns an error if loading trades fails.
289    fn load_trades(&self, instrument_id: &InstrumentId) -> anyhow::Result<Vec<TradeTick>>;
290
291    /// Loads funding rate updates by instrument ID.
292    ///
293    /// # Errors
294    ///
295    /// Returns an error if loading funding rates fails.
296    fn load_funding_rates(
297        &self,
298        instrument_id: &InstrumentId,
299    ) -> anyhow::Result<Vec<FundingRateUpdate>>;
300
301    /// Loads bars by instrument ID.
302    ///
303    /// # Errors
304    ///
305    /// Returns an error if loading bars fails.
306    fn load_bars(&self, instrument_id: &InstrumentId) -> anyhow::Result<Vec<Bar>>;
307
308    /// Adds a generic key-value pair to the cache.
309    ///
310    /// # Errors
311    ///
312    /// Returns an error if adding a generic key/value fails.
313    fn add(&self, key: String, value: Bytes) -> anyhow::Result<()>;
314
315    /// Adds a currency to the cache.
316    ///
317    /// # Errors
318    ///
319    /// Returns an error if adding a currency fails.
320    fn add_currency(&self, currency: &Currency) -> anyhow::Result<()>;
321
322    /// Adds an instrument to the cache.
323    ///
324    /// # Errors
325    ///
326    /// Returns an error if adding an instrument fails.
327    fn add_instrument(&self, instrument: &InstrumentAny) -> anyhow::Result<()>;
328
329    /// Adds a synthetic instrument to the cache.
330    ///
331    /// # Errors
332    ///
333    /// Returns an error if adding a synthetic instrument fails.
334    fn add_synthetic(&self, synthetic: &SyntheticInstrument) -> anyhow::Result<()>;
335
336    /// Adds an account to the cache.
337    ///
338    /// # Errors
339    ///
340    /// Returns an error if adding an account fails.
341    fn add_account(&self, account: &AccountAny) -> anyhow::Result<()>;
342
343    /// Adds an order to the cache.
344    ///
345    /// # Errors
346    ///
347    /// Returns an error if adding an order fails.
348    fn add_order(&self, order: &OrderAny, client_id: Option<ClientId>) -> anyhow::Result<()>;
349
350    /// Adds an order snapshot to the cache.
351    ///
352    /// # Errors
353    ///
354    /// Returns an error if adding an order snapshot fails.
355    fn add_order_snapshot(&self, snapshot: &OrderSnapshot) -> anyhow::Result<()>;
356
357    /// Adds a position to the cache.
358    ///
359    /// # Errors
360    ///
361    /// Returns an error if adding a position fails.
362    fn add_position(&self, position: &Position) -> anyhow::Result<()>;
363
364    /// Adds a position snapshot to the cache.
365    ///
366    /// # Errors
367    ///
368    /// Returns an error if adding a position snapshot fails.
369    fn add_position_snapshot(&self, snapshot: &PositionSnapshot) -> anyhow::Result<()>;
370
371    /// Adds an order book to the cache.
372    ///
373    /// # Errors
374    ///
375    /// Returns an error if adding an order book fails.
376    fn add_order_book(&self, order_book: &OrderBook) -> anyhow::Result<()>;
377
378    /// Adds a signal to the cache.
379    ///
380    /// # Errors
381    ///
382    /// Returns an error if adding a signal fails.
383    fn add_signal(&self, signal: &Signal) -> anyhow::Result<()>;
384
385    /// Adds custom data to the cache.
386    ///
387    /// # Errors
388    ///
389    /// Returns an error if adding custom data fails.
390    fn add_custom_data(&self, data: &CustomData) -> anyhow::Result<()>;
391
392    /// Adds a quote tick to the cache.
393    ///
394    /// # Errors
395    ///
396    /// Returns an error if adding a quote tick fails.
397    fn add_quote(&self, quote: &QuoteTick) -> anyhow::Result<()>;
398
399    /// Adds a trade tick to the cache.
400    ///
401    /// # Errors
402    ///
403    /// Returns an error if adding a trade tick fails.
404    fn add_trade(&self, trade: &TradeTick) -> anyhow::Result<()>;
405
406    /// Adds a funding rate update to the cache.
407    ///
408    /// # Errors
409    ///
410    /// Returns an error if adding a funding rate update fails.
411    fn add_funding_rate(&self, funding_rate: &FundingRateUpdate) -> anyhow::Result<()>;
412
413    /// Adds a bar to the cache.
414    ///
415    /// # Errors
416    ///
417    /// Returns an error if adding a bar fails.
418    fn add_bar(&self, bar: &Bar) -> anyhow::Result<()>;
419
420    /// Adds greeks data to the cache.
421    ///
422    /// # Errors
423    ///
424    /// Returns an error if adding greeks data fails.
425    fn add_greeks(&self, _greeks: &GreeksData) -> anyhow::Result<()> {
426        Ok(())
427    }
428
429    /// Adds yield curve data to the cache.
430    ///
431    /// # Errors
432    ///
433    /// Returns an error if adding yield curve data fails.
434    fn add_yield_curve(&self, _yield_curve: &YieldCurveData) -> anyhow::Result<()> {
435        Ok(())
436    }
437
438    /// Deletes actor state from the cache.
439    ///
440    /// # Errors
441    ///
442    /// Returns an error if deleting actor state fails.
443    fn delete_actor(&self, component_id: &ComponentId) -> anyhow::Result<()>;
444
445    /// Deletes strategy state from the cache.
446    ///
447    /// # Errors
448    ///
449    /// Returns an error if deleting strategy state fails.
450    fn delete_strategy(&self, component_id: &StrategyId) -> anyhow::Result<()>;
451
452    /// Deletes an order from the cache.
453    ///
454    /// # Errors
455    ///
456    /// Returns an error if deleting an order fails.
457    fn delete_order(&self, client_order_id: &ClientOrderId) -> anyhow::Result<()>;
458
459    /// Deletes a position from the cache.
460    ///
461    /// # Errors
462    ///
463    /// Returns an error if deleting a position fails.
464    fn delete_position(&self, position_id: &PositionId) -> anyhow::Result<()>;
465
466    /// Deletes an account event from the cache.
467    ///
468    /// # Errors
469    ///
470    /// Returns an error if deleting account events fails.
471    fn delete_account_event(&self, account_id: &AccountId, event_id: &str) -> anyhow::Result<()>;
472
473    /// Indexes a venue order ID with its client order ID.
474    ///
475    /// # Errors
476    ///
477    /// Returns an error if indexing venue order ID fails.
478    fn index_venue_order_id(
479        &self,
480        client_order_id: ClientOrderId,
481        venue_order_id: VenueOrderId,
482    ) -> anyhow::Result<()>;
483
484    /// Indexes an order-position mapping.
485    ///
486    /// # Errors
487    ///
488    /// Returns an error if indexing order-position mapping fails.
489    fn index_order_position(
490        &self,
491        client_order_id: ClientOrderId,
492        position_id: PositionId,
493    ) -> anyhow::Result<()>;
494
495    /// Updates actor state in the cache.
496    ///
497    /// # Errors
498    ///
499    /// Returns an error if updating actor state fails.
500    fn update_actor(
501        &self,
502        component_id: &ComponentId,
503        state: &AHashMap<String, Bytes>,
504    ) -> anyhow::Result<()>;
505
506    /// Updates strategy state in the cache.
507    ///
508    /// # Errors
509    ///
510    /// Returns an error if updating strategy state fails.
511    fn update_strategy(
512        &self,
513        strategy_id: &StrategyId,
514        state: &AHashMap<String, Bytes>,
515    ) -> anyhow::Result<()>;
516
517    /// Updates an account in the cache.
518    ///
519    /// # Errors
520    ///
521    /// Returns an error if updating an account fails.
522    fn update_account(&self, account: &AccountAny) -> anyhow::Result<()>;
523
524    /// Updates an order in the cache with an order event.
525    ///
526    /// # Errors
527    ///
528    /// Returns an error if updating an order fails.
529    fn update_order(&self, order_event: &OrderEventAny) -> anyhow::Result<()>;
530
531    /// Updates a position in the cache.
532    ///
533    /// # Errors
534    ///
535    /// Returns an error if updating a position fails.
536    fn update_position(&self, position: &Position) -> anyhow::Result<()>;
537
538    /// Creates a snapshot of order state.
539    ///
540    /// # Errors
541    ///
542    /// Returns an error if snapshotting order state fails.
543    fn snapshot_order_state(&self, order: &OrderAny) -> anyhow::Result<()>;
544
545    /// Creates a snapshot of position state.
546    ///
547    /// # Errors
548    ///
549    /// Returns an error if snapshotting position state fails.
550    fn snapshot_position_state(
551        &self,
552        position: &Position,
553        ts_snapshot: UnixNanos,
554        unrealized_pnl: Option<Money>,
555    ) -> anyhow::Result<()>;
556
557    /// Records a heartbeat timestamp.
558    ///
559    /// # Errors
560    ///
561    /// Returns an error if heartbeat recording fails.
562    fn heartbeat(&self, timestamp: UnixNanos) -> anyhow::Result<()>;
563}