sandbox_quant/model/
candle.rs1#[derive(Debug, Clone)]
2pub struct Candle {
3 pub open: f64,
4 pub high: f64,
5 pub low: f64,
6 pub close: f64,
7 pub open_time: u64,
8 pub close_time: u64,
9}
10
11impl Candle {
12 pub fn is_bullish(&self) -> bool {
13 self.close >= self.open
14 }
15}
16
17#[derive(Debug, Clone)]
19pub struct CandleBuilder {
20 pub open: f64,
21 pub high: f64,
22 pub low: f64,
23 pub close: f64,
24 pub open_time: u64,
25 pub close_time: u64,
26}
27
28impl CandleBuilder {
29 pub fn new(price: f64, timestamp_ms: u64, interval_ms: u64) -> Self {
31 let open_time = timestamp_ms - (timestamp_ms % interval_ms);
32 Self {
33 open: price,
34 high: price,
35 low: price,
36 close: price,
37 open_time,
38 close_time: open_time + interval_ms,
39 }
40 }
41
42 pub fn update(&mut self, price: f64) {
44 self.high = self.high.max(price);
45 self.low = self.low.min(price);
46 self.close = price;
47 }
48
49 pub fn contains(&self, timestamp_ms: u64) -> bool {
51 timestamp_ms >= self.open_time && timestamp_ms < self.close_time
52 }
53
54 pub fn finish(&self) -> Candle {
56 Candle {
57 open: self.open,
58 high: self.high,
59 low: self.low,
60 close: self.close,
61 open_time: self.open_time,
62 close_time: self.close_time,
63 }
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn candle_builder_basics() {
73 let mut cb = CandleBuilder::new(100.0, 60_500, 60_000);
74 assert_eq!(cb.open_time, 60_000);
75 assert_eq!(cb.close_time, 120_000);
76 assert!(cb.contains(60_500));
77 assert!(cb.contains(119_999));
78 assert!(!cb.contains(120_000));
79
80 cb.update(105.0);
81 cb.update(95.0);
82 cb.update(102.0);
83
84 let candle = cb.finish();
85 assert!((candle.open - 100.0).abs() < f64::EPSILON);
86 assert!((candle.high - 105.0).abs() < f64::EPSILON);
87 assert!((candle.low - 95.0).abs() < f64::EPSILON);
88 assert!((candle.close - 102.0).abs() < f64::EPSILON);
89 assert!(candle.is_bullish());
90 }
91
92 #[test]
93 fn bearish_candle() {
94 let candle = Candle {
95 open: 100.0,
96 high: 105.0,
97 low: 90.0,
98 close: 95.0,
99 open_time: 0,
100 close_time: 60_000,
101 };
102 assert!(!candle.is_bullish());
103 }
104}