use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use avin_core::{Action, Asset, Event, TimeFrame};
use avin_strategy::Strategy;
use super::{Test, TestStatus, VirtualBroker};
pub struct Tester {
tx: UnboundedSender<Action>,
rx: UnboundedReceiver<Action>,
}
impl Tester {
pub fn new() -> Self {
let (tx, rx) = mpsc::unbounded_channel();
Tester { tx, rx }
}
pub async fn run(
&mut self,
mut strategy: impl Strategy,
test: &mut Test,
) {
log::info!(":: Tester clear test");
test.clear();
log::info!(":: Tester load broker");
let mut broker = VirtualBroker::new(test);
let broker_tx = broker.get_sender();
log::info!(":: Tester load account");
let account = broker.get_virtual_account();
log::info!(":: Tester load asset");
let mut asset = Asset::from_iid(test.iid.clone());
self.load_charts(&mut asset);
log::info!(":: Tester load strategys");
let sender = self.tx.clone();
strategy.init(sender, account, asset.iid().clone());
log::info!(":: Tester start main loop");
test.status = TestStatus::Process;
while let Some(e) = broker.next_event() {
match e {
Event::Bar(e) => {
if e.tf == TimeFrame::M1 {
asset.bar_event(e);
strategy.process(&asset);
} else {
asset.bar_event(e);
}
}
Event::Tic(e) => {
asset.tic_event(e);
}
Event::Order(e) => strategy.order_event(e),
}
while let Ok(a) = self.rx.try_recv() {
match a {
Action::TradeClosed(trade) => {
test.trade_list.add(trade);
}
other => broker_tx.send(other).unwrap(),
}
}
}
test.status = TestStatus::Complete;
Test::save(test).unwrap();
}
fn load_charts(&mut self, asset: &mut Asset) {
log::info!(":: Tester load charts {asset}");
for tf in TimeFrame::all() {
log::info!(" {}", tf);
asset.load_chart_empty(&tf);
}
}
}
impl Default for Tester {
fn default() -> Self {
Tester::new()
}
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone, Utc};
use super::*;
use avin_strategy::Every;
#[tokio::test]
async fn run_test() {
let strategy = Every::default();
let asset = Asset::new("moex_share_sber").unwrap();
let mut test = Test::new(&strategy, asset.iid());
test.set_begin(&Utc.with_ymd_and_hms(2023, 8, 1, 7, 0, 0).unwrap());
test.set_end(&Utc.with_ymd_and_hms(2023, 8, 1, 7, 10, 0).unwrap());
assert_eq!(test.status, TestStatus::New);
let mut tester = Tester::new();
tester.run(strategy, &mut test).await;
assert_eq!(test.status, TestStatus::Complete);
assert_eq!(test.trade_list.len(), 5);
Test::delete(&test).unwrap();
}
}