Skip to main content

sandbox_quant/strategy/
store.rs

1use 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}