hypercall/rsm/
engine_vol_oracle.rs1use crate::vol_oracle::risk_oracle::{
2 RiskVolOracle, VolLookupError, VolOracleStatus, VolProviderKind, VolSurfaceSnapshot,
3};
4use crate::vol_oracle::vol_surface_cache::VolatilitySurface;
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7
8pub struct EngineVolOracle {
15 surfaces: Arc<RwLock<HashMap<String, VolatilitySurface>>>,
16}
17
18impl EngineVolOracle {
19 pub fn new(surfaces: Arc<RwLock<HashMap<String, VolatilitySurface>>>) -> Self {
20 Self { surfaces }
21 }
22}
23
24impl RiskVolOracle for EngineVolOracle {
25 fn get_iv(&self, underlying: &str, strike: f64, expiry_ts: i64) -> Result<f64, VolLookupError> {
26 let surfaces = self
27 .surfaces
28 .read()
29 .expect("engine vol oracle lock poisoned");
30
31 let surface =
32 surfaces
33 .get(underlying)
34 .ok_or_else(|| VolLookupError::UnsupportedUnderlying {
35 underlying: underlying.to_string(),
36 })?;
37
38 surface
39 .get_interpolated(strike, expiry_ts)
40 .ok_or_else(|| VolLookupError::MissingSurface {
41 underlying: underlying.to_string(),
42 provider: VolProviderKind::Fixed,
43 strike,
44 expiry_ts,
45 })
46 }
47
48 fn statuses(&self) -> Vec<VolOracleStatus> {
49 let surfaces = self
50 .surfaces
51 .read()
52 .expect("engine vol oracle lock poisoned");
53 surfaces
54 .keys()
55 .map(|underlying| VolOracleStatus {
56 underlying: underlying.clone(),
57 provider: VolProviderKind::Fixed,
58 route_facing: true,
59 connected: true,
60 ready: true,
61 last_update_ts_ms: None,
62 staleness_seconds: Some(0.0),
63 staleness_threshold_seconds: None,
64 surface_points: 0,
65 messages_received: 0,
66 last_error: None,
67 })
68 .collect()
69 }
70
71 fn get_surface_snapshot(&self, _underlying: &str) -> Option<VolSurfaceSnapshot> {
72 None
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 #[test]
81 fn missing_underlying_fails_closed() {
82 let oracle = EngineVolOracle::new(Arc::new(RwLock::new(HashMap::new())));
83
84 assert!(matches!(
85 oracle.get_iv("GOLD", 4700.0, 1_800_000_000),
86 Err(VolLookupError::UnsupportedUnderlying { .. })
87 ));
88 }
89
90 #[test]
91 fn missing_surface_point_returns_missing_surface() {
92 let mut surfaces = HashMap::new();
93 surfaces.insert("GOLD".to_string(), VolatilitySurface::new());
94 let oracle = EngineVolOracle::new(Arc::new(RwLock::new(surfaces)));
95
96 assert!(matches!(
97 oracle.get_iv("GOLD", 4700.0, 1_800_000_000),
98 Err(VolLookupError::MissingSurface { .. })
99 ));
100 }
101}