scuriolus 0.1.0

Scuriolus is a modular trading bot platform. It can apply different strategies to various markets, as described below.
Documentation
use std::{future::Future, pin::Pin, time::Duration};

use chrono::{DateTime, TimeDelta, Utc};
use tokio::time::{sleep, sleep_until, Instant};

use super::{Clock, ClockBase};

/// Standard [`Clock`] based on [`Utc`].
#[derive(Debug, Clone)]
pub struct TrueClock;

impl TrueClock {
    pub fn new() -> Self {
        Self {}
    }
}

impl Default for TrueClock {
    fn default() -> Self {
        Self::new()
    }
}

impl ClockBase for TrueClock {
    fn now(&self) -> DateTime<Utc> {
        Utc::now()
    }
}

impl Clock for TrueClock {
    fn sleep(&self, delay: TimeDelta) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        tracing::trace!("Sleeping for {}", delay.to_string());
        Box::pin(sleep(
            Duration::from_millis(delay.num_milliseconds() as u64),
        ))
    }

    fn sleep_until(&self, deadline: DateTime<Utc>) -> Pin<Box<dyn Future<Output = ()> + Send>> {
        tracing::trace!("Sleeping until {}", deadline.to_string());
        Box::pin(sleep_until(
            Instant::now()
                + deadline
                    .signed_duration_since(Utc::now())
                    .to_std()
                    .unwrap_or_default(),
        ))
    }

    fn clone_box(&self) -> Box<dyn Clock> {
        Box::new(Self::new())
    }

    fn synchronize(&self) {}
}

#[cfg(test)]
mod tests {
    use chrono::{TimeDelta, Utc};

    use super::{Clock as _, ClockBase as _, TrueClock};

    const TOLERANCE: TimeDelta = TimeDelta::milliseconds(10);
    const DELAY: TimeDelta = TimeDelta::milliseconds(100);

    #[tokio::test]
    async fn true_clock() {
        let clock = TrueClock::new();
        assert!(clock.now() - Utc::now() < TOLERANCE);

        let before = Utc::now();
        clock.sleep(DELAY).await;
        let after = Utc::now();

        assert!(after - before > DELAY - TOLERANCE);
        assert!(after - before < DELAY + TOLERANCE);

        assert!(clock.now() - Utc::now() < TOLERANCE);
    }
}