scuriolus 0.3.0

Scuriolus is a modular trading bot platform.
Documentation
// pub mod periodic_decision; //TODO when market separazted from klines
pub mod strict_buy;
pub mod trend_tunnel;

use std::{error::Error, fmt, future::Future, pin::Pin, sync::Arc};

use atomic_enum::atomic_enum;
use chrono::{DateTime, Utc};
use strum_macros::Display;
use tokio::sync::{Notify, watch::Receiver};

use crate::{
    clock::Clock,
    core::{
        Core,
        market::{Balance, Market},
    },
};

/// A [`StratStat`] is a snapshot of the current ownings of the strategy.
#[derive(Debug, Clone)]
pub struct StratStat {
    pub asset: Balance,
    pub quote: Balance,
    pub time: DateTime<Utc>,
}

impl StratStat {
    pub fn new(asset: Balance, quote: Balance, time: DateTime<Utc>) -> Self {
        Self { asset, quote, time }
    }
}

/// An [`ErrorInStrat`] is the error format when computing the [`StratStat`] fails.
#[derive(Debug, Clone)]
pub struct ErrorInStrat {
    error: String,
    time: DateTime<Utc>,
}

impl fmt::Display for ErrorInStrat {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Error in stat (at internal time {}): {}",
            self.time, self.error
        )
    }
}

impl Error for ErrorInStrat {}

impl ErrorInStrat {
    pub fn new(error: String, time: DateTime<Utc>) -> Self {
        Self { error, time }
    }
}

/// The [`State`] of the [`Strategy`]
#[atomic_enum(AtomicState)]
#[derive(PartialEq, Display)]
pub enum State {
    Starting,
    Running,
    Stats,
    Paused,
    Stopped,
    Terminated,
    Killed,
}

/// A [`Strategy`] is a trading strategy.
pub trait Strategy: Send + Sync + 'static {
    type _Clock: Clock;
    type _Market: Market<_Clock = Self::_Clock>;

    fn run(&mut self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;

    fn state(&self) -> &Arc<AtomicState>;
    fn notify(&self) -> &Arc<Notify>;
    fn stat_channel(&self) -> Receiver<Result<StratStat, ErrorInStrat>>;
}

/// A [`StrategyFactory`] is a factory of [`Strategy`].
pub trait StrategyFactory: Send {
    type _Strategy: Strategy;
    fn with_core(
        self,
        core: Core<<Self::_Strategy as Strategy>::_Clock, <Self::_Strategy as Strategy>::_Market>,
    ) -> Self;
    fn build(self) -> Self::_Strategy;
}