sandbox_quant/strategy/
store.rs1use std::collections::BTreeMap;
2
3use chrono::Utc;
4
5use crate::app::bootstrap::BinanceMode;
6use crate::domain::instrument::Instrument;
7use crate::error::strategy_error::StrategyError;
8use crate::strategy::command::StrategyStartConfig;
9use crate::strategy::model::{StrategyTemplate, StrategyWatch, StrategyWatchState};
10
11#[derive(Debug, Default, Clone, PartialEq)]
12pub struct StrategyStore {
13 next_watch_id: u64,
14 active: BTreeMap<u64, StrategyWatch>,
15 history: Vec<StrategyWatch>,
16}
17
18impl StrategyStore {
19 pub fn create_watch(
20 &mut self,
21 mode: BinanceMode,
22 template: StrategyTemplate,
23 instrument: Instrument,
24 config: StrategyStartConfig,
25 ) -> Result<StrategyWatch, StrategyError> {
26 if self.active.values().any(|watch| {
27 watch.mode == mode
28 && watch.template == template
29 && watch.instrument == instrument
30 && watch.state == StrategyWatchState::Armed
31 }) {
32 return Err(StrategyError::DuplicateWatch {
33 template: template.slug(),
34 instrument: instrument.0.clone(),
35 });
36 }
37
38 let id = self.next_id();
39 let watch = StrategyWatch::new(id, mode, template, instrument, config);
40 self.active.insert(id, watch.clone());
41 Ok(watch)
42 }
43
44 pub fn active_watches(&self, mode: BinanceMode) -> Vec<&StrategyWatch> {
45 self.active
46 .values()
47 .filter(|watch| watch.mode == mode)
48 .collect()
49 }
50
51 pub fn history(&self, mode: BinanceMode) -> Vec<&StrategyWatch> {
52 self.history
53 .iter()
54 .filter(|watch| watch.mode == mode)
55 .collect()
56 }
57
58 pub fn get(&self, mode: BinanceMode, watch_id: u64) -> Option<&StrategyWatch> {
59 self.active
60 .get(&watch_id)
61 .filter(|watch| watch.mode == mode)
62 .or_else(|| self.history.iter().rev().find(|watch| watch.id == watch_id))
63 .filter(|watch| watch.mode == mode)
64 }
65
66 pub fn stop_watch(
67 &mut self,
68 mode: BinanceMode,
69 watch_id: u64,
70 ) -> Result<StrategyWatch, StrategyError> {
71 if self.active.get(&watch_id).map(|watch| watch.mode) != Some(mode) {
72 return Err(StrategyError::WatchNotFound(watch_id));
73 }
74 let mut watch = self
75 .active
76 .remove(&watch_id)
77 .ok_or(StrategyError::WatchNotFound(watch_id))?;
78 watch.state = StrategyWatchState::Stopped;
79 watch.updated_at = Utc::now();
80 self.history.push(watch.clone());
81 Ok(watch)
82 }
83
84 fn next_id(&mut self) -> u64 {
85 self.next_watch_id += 1;
86 self.next_watch_id
87 }
88}