bot_engine/testing/
quote_source.rs1use bot_core::{InstrumentId, Quote};
9use std::collections::HashMap;
10
11#[async_trait::async_trait]
18pub trait QuoteSource: Send + Sync {
19 async fn poll_quotes(&self, instruments: &[InstrumentId]) -> Vec<Quote>;
21
22 fn last_quote(&self, instrument: &InstrumentId) -> Option<Quote>;
24
25 fn set_time(&mut self, time_ms: i64);
27
28 fn current_time_ms(&self) -> i64;
30}
31
32pub struct MockQuoteSource {
34 quotes: HashMap<InstrumentId, Quote>,
35 time_ms: i64,
36}
37
38impl MockQuoteSource {
39 pub fn new() -> Self {
41 Self {
42 quotes: HashMap::new(),
43 time_ms: bot_core::now_ms(),
44 }
45 }
46
47 pub fn set_quote(&mut self, quote: Quote) {
49 self.quotes.insert(quote.instrument.clone(), quote);
50 }
51
52 pub fn clear(&mut self) {
54 self.quotes.clear();
55 }
56}
57
58impl Default for MockQuoteSource {
59 fn default() -> Self {
60 Self::new()
61 }
62}
63
64#[async_trait::async_trait]
65impl QuoteSource for MockQuoteSource {
66 async fn poll_quotes(&self, instruments: &[InstrumentId]) -> Vec<Quote> {
67 instruments
68 .iter()
69 .filter_map(|inst| self.quotes.get(inst).cloned())
70 .collect()
71 }
72
73 fn last_quote(&self, instrument: &InstrumentId) -> Option<Quote> {
74 self.quotes.get(instrument).cloned()
75 }
76
77 fn set_time(&mut self, time_ms: i64) {
78 self.time_ms = time_ms;
79 }
80
81 fn current_time_ms(&self) -> i64 {
82 self.time_ms
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use bot_core::{Price, Qty};
90
91 #[tokio::test]
92 async fn test_mock_quote_source() {
93 let mut source = MockQuoteSource::new();
94
95 let instrument = InstrumentId::new("BTC-PERP");
96 let quote = Quote {
97 instrument: instrument.clone(),
98 bid: Price::new(rust_decimal::Decimal::new(50000, 0)),
99 ask: Price::new(rust_decimal::Decimal::new(50010, 0)),
100 bid_size: Qty::new(rust_decimal::Decimal::new(1, 0)),
101 ask_size: Qty::new(rust_decimal::Decimal::new(1, 0)),
102 ts: 0,
103 };
104
105 source.set_quote(quote.clone());
106
107 let quotes = source.poll_quotes(&[instrument.clone()]).await;
108 assert_eq!(quotes.len(), 1);
109 assert_eq!(quotes[0].bid.0, rust_decimal::Decimal::new(50000, 0));
110 }
111}