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::fmt;
use std::future::Future;

use chrono::{DateTime, Utc};
use mexc_rs::spot::v3::enums::KlineInterval;

use strum_macros::Display;
use thiserror::Error;

use super::clock::Clock;
use super::order::{Amount, Crypto, Order};

#[cfg(test)]
use mockall::automock;

pub mod mexc_base;
pub use mexc_rs::spot::v3::{
    cancel_order::CancelOrderOutput, klines::Kline, query_order::QueryOrderOutput,
};

/// Cryptocurrency balance
#[derive(Debug, Clone, Copy)]
pub struct Balance {
    pub free: Amount,
    pub locked: Amount,
}

/// [`Market`] manipulation errors
#[derive(Debug, Error)]
pub enum MarketError {
    #[error("Mexc API error: {0}")]
    MexcApiError(#[from] anyhow::Error),

    #[error("Safety error")]
    SafetyError,
}

/// [`Market`] kind for [`Order`] to know which market they are linked to
#[derive(Debug, Clone, Copy, Display, serde::Serialize, serde::Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub enum MarketKind {
    None,
    Mexc,
    TestMexc,
}

/// [`Kline`] params
#[derive(Debug, Clone)]
pub struct KlinesParams {
    pub symbol: String,
    pub interval: KlineInterval,
    pub start_time: Option<DateTime<Utc>>,
    pub end_time: Option<DateTime<Utc>>,
    /// default 500; max 1000
    pub limit: Option<u32>,
}

#[cfg_attr(test, automock)]
pub trait Market: Send + Sync + fmt::Debug + 'static {
    fn clock(&self) -> Box<dyn Clock>;
    fn klines(
        &self,
        params: KlinesParams,
    ) -> impl Future<Output = Result<Vec<Kline>, MarketError>> + Send;
    fn get_balance(
        &self,
        crypto: Crypto,
    ) -> impl Future<Output = Result<Balance, MarketError>> + Send;
    fn send_order(&self, order: &Order)
        -> impl Future<Output = Result<String, MarketError>> + Send;
    fn cancel_order(
        &self,
        order: &Order,
    ) -> impl Future<Output = Result<CancelOrderOutput, MarketError>> + Send;
    fn update_order(
        &self,
        order: &Order,
    ) -> impl Future<Output = Result<QueryOrderOutput, MarketError>> + Send;
}