scuriolus 0.1.0

Scuriolus is a modular trading bot platform. It can apply different strategies to various markets, as described below.
Documentation
use anyhow::Error;
use chrono::{DateTime, TimeZone as _, Utc};
use scuriolus::{
    app::App,
    clock::{CheatClockFactory as _, RunningCheatClockFactory},
    core::Core,
    market::mexc_base::TestWithMexc,
    order::{Amount, Crypto},
    strategy::{strict_buy::StrictBuyFactory, StrategyFactory as _},
};

const QUOTE: Crypto = Crypto::USDT;
const ASSET: Crypto = Crypto::BTC;
const AMOUNT: Amount = Amount::from_parts(1000, 0, 0, false, 0);

const SECS_PER_YEAR: Amount = Amount::from_parts(60 * 60 * 24 * 365, 0, 0, false, 0);

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let start = Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap();
    let end = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap();

    let earning = test_perf(start, end).await.unwrap();
    let ratio =
        earning * SECS_PER_YEAR / (Amount::from(end.timestamp() - start.timestamp()) * AMOUNT);
    println!("APY: {}%", ratio.round_dp(2));
    Ok(())
}

async fn test_perf(start: DateTime<Utc>, end: DateTime<Utc>) -> Result<Amount, Error> {
    let (remote, clock) = RunningCheatClockFactory {}.get_clock(start).unwrap();
    let market = TestWithMexc::new(clock).await;
    let core = Core::new("perfo".to_string(), market).await.unwrap();

    let mut strat_factory = Box::new(StrictBuyFactory::<TestWithMexc>::new(QUOTE, AMOUNT, ASSET));

    strat_factory.as_mut().set_core(core);

    let mut app = App::new(strat_factory, Some(remote)).await;
    let early_stat = app.get_stats().await?;
    app.run();

    app.advance_toward(end);
    app.wait_for_the_bot().await;

    let final_stat = app.terminate().await?;
    Ok(final_stat.quote.free - early_stat.quote.free)
}