opendeviationbar-streaming 13.79.0

Real-time streaming engine for open deviation bar processing
Documentation
//! Clock implementations for the unified engine (Issue #178)

use super::traits::EngineClock;

/// Wall-clock time for live streaming.
pub struct LiveClock;

impl EngineClock for LiveClock {
    fn now_ms(&self) -> i64 {
        chrono::Utc::now().timestamp_millis()
    }
}

/// Event-time clock for historical replay / backtesting.
/// Advances only when explicitly set (deterministic).
pub struct HistoricalClock {
    current_ms: std::sync::atomic::AtomicI64,
}

impl HistoricalClock {
    pub fn new(initial_ms: i64) -> Self {
        Self {
            current_ms: std::sync::atomic::AtomicI64::new(initial_ms),
        }
    }

    pub fn advance_to(&self, ms: i64) {
        let prev = self.current_ms.load(std::sync::atomic::Ordering::Relaxed);
        if ms < prev {
            tracing::warn!(
                prev_ms = prev,
                new_ms = ms,
                "HistoricalClock: backward time jump"
            );
        }
        self.current_ms
            .store(ms, std::sync::atomic::Ordering::Relaxed);
    }
}

impl EngineClock for HistoricalClock {
    fn now_ms(&self) -> i64 {
        self.current_ms.load(std::sync::atomic::Ordering::Relaxed)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_live_clock_advances() {
        let clock = LiveClock;
        let t1 = clock.now_ms();
        std::thread::sleep(std::time::Duration::from_millis(10));
        let t2 = clock.now_ms();
        assert!(t2 >= t1);
    }

    #[test]
    fn test_historical_clock_returns_set_time() {
        let clock = HistoricalClock::new(1_700_000_000_000);
        assert_eq!(clock.now_ms(), 1_700_000_000_000);

        clock.advance_to(1_700_000_001_000);
        assert_eq!(clock.now_ms(), 1_700_000_001_000);
    }

    #[test]
    fn test_historical_clock_backward_jump() {
        let clock = HistoricalClock::new(1_700_000_001_000);
        // Should not panic, just warn
        clock.advance_to(1_700_000_000_000);
        assert_eq!(clock.now_ms(), 1_700_000_000_000);
    }
}