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}