Skip to main content

hypercall_db/traits/
instruments.rs

1//! Instrument persistence traits.
2//!
3//! Sync because instruments are loaded at engine startup and mutated
4//! through the engine event loop (both blocking contexts).
5
6use anyhow::Result;
7
8use crate::InstrumentRecord;
9
10/// Read-only instrument queries.
11pub trait InstrumentReader: Send + Sync {
12    /// Load all instruments regardless of status.
13    fn get_all_instruments_sync(&self) -> Result<Vec<InstrumentRecord>>;
14    /// Load instruments filtered by status (e.g. "ACTIVE", "PENDING_SETTLEMENT").
15    fn get_instruments_by_status_sync(&self, status: &str) -> Result<Vec<InstrumentRecord>>;
16    /// Load active instruments whose expiry timestamp is at or before `now_ts_secs`.
17    fn get_active_instruments_expired_by_sync(
18        &self,
19        now_ts_secs: u64,
20    ) -> Result<Vec<InstrumentRecord>> {
21        let active = self.get_instruments_by_status_sync("ACTIVE")?;
22        let mut expired = Vec::new();
23
24        for instrument in active {
25            let expiry_code = u64::try_from(instrument.expiry).map_err(|_| {
26                anyhow::anyhow!(
27                    "Invalid negative expiry {} for active instrument {}",
28                    instrument.expiry,
29                    instrument.id
30                )
31            })?;
32            let expiry_ts = hypercall_types::expiry_date_to_timestamp_checked(
33                &instrument.underlying,
34                expiry_code,
35            )
36            .map_err(|error| {
37                anyhow::anyhow!(
38                    "Invalid expiry {} for active instrument {}: {}",
39                    instrument.expiry,
40                    instrument.id,
41                    error
42                )
43            })?;
44            if expiry_ts <= now_ts_secs {
45                expired.push(instrument);
46            }
47        }
48
49        Ok(expired)
50    }
51    /// Count instruments grouped by status.
52    fn get_instrument_status_counts_sync(&self) -> Result<Vec<(String, i64)>>;
53    /// Count markets (underlying+expiry) expiring within `seconds` from now.
54    fn get_markets_expiring_within_sync(&self, seconds: i64) -> Result<i64>;
55}
56
57/// Instrument mutations.
58pub trait InstrumentWriter: InstrumentReader {
59    /// Persist a new instrument and its parent market. Only used for new
60    /// ACTIVE instruments -- status transitions on existing instruments go
61    /// through `update_instrument_status_sync`.
62    fn save_market_and_instrument_sync(
63        &self,
64        underlying: &str,
65        expiry: i64,
66        instrument: &InstrumentRecord,
67    ) -> Result<()>;
68    /// Delete an instrument and its parent market row.
69    fn delete_market_and_instrument_sync(&self, symbol: &str) -> Result<()>;
70    /// Batch-update instrument status. Returns number of rows updated.
71    fn update_instrument_status_sync(&self, symbols: &[String], status: &str) -> Result<usize>;
72    /// Transition only instruments that are still ACTIVE to EXPIRED_PENDING_PRICE.
73    /// Returns number of rows updated.
74    fn transition_active_instruments_to_expired_pending_sync(
75        &self,
76        symbols: &[String],
77    ) -> Result<usize>;
78}