wickra_core/indicators/
weighted_close.rs1use crate::ohlcv::Candle;
4use crate::traits::Indicator;
5
6#[derive(Debug, Clone, Default)]
29pub struct WeightedClose {
30 has_emitted: bool,
31}
32
33impl WeightedClose {
34 pub const fn new() -> Self {
36 Self { has_emitted: false }
37 }
38}
39
40impl Indicator for WeightedClose {
41 type Input = Candle;
42 type Output = f64;
43
44 #[inline]
45 fn update(&mut self, candle: Candle) -> Option<f64> {
46 self.has_emitted = true;
47 Some(candle.weighted_close())
48 }
49
50 fn reset(&mut self) {
51 self.has_emitted = false;
52 }
53
54 #[inline]
55 fn warmup_period(&self) -> usize {
56 1
57 }
58
59 #[inline]
60 fn is_ready(&self) -> bool {
61 self.has_emitted
62 }
63
64 #[inline]
65 fn name(&self) -> &'static str {
66 "WeightedClose"
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::traits::BatchExt;
74 use approx::assert_relative_eq;
75
76 fn candle(open: f64, high: f64, low: f64, close: f64, ts: i64) -> Candle {
77 Candle::new(open, high, low, close, 1.0, ts).unwrap()
78 }
79
80 #[test]
81 fn reference_value() {
82 let mut wc = WeightedClose::new();
84 assert_relative_eq!(
85 wc.update(candle(10.0, 12.0, 8.0, 11.0, 0)).unwrap(),
86 10.5,
87 epsilon = 1e-12
88 );
89 }
90
91 #[test]
93 fn name_metadata() {
94 let wc = WeightedClose::new();
95 assert_eq!(wc.name(), "WeightedClose");
96 }
97
98 #[test]
99 fn emits_from_first_candle() {
100 let mut wc = WeightedClose::new();
101 assert_eq!(wc.warmup_period(), 1);
102 assert!(!wc.is_ready());
103 assert!(wc.update(candle(10.0, 11.0, 9.0, 10.0, 0)).is_some());
104 assert!(wc.is_ready());
105 }
106
107 #[test]
108 fn reset_clears_state() {
109 let mut wc = WeightedClose::new();
110 wc.update(candle(10.0, 11.0, 9.0, 10.0, 0));
111 assert!(wc.is_ready());
112 wc.reset();
113 assert!(!wc.is_ready());
114 }
115
116 #[test]
117 fn batch_equals_streaming() {
118 let candles: Vec<Candle> = (0..40)
119 .map(|i| {
120 let base = 100.0 + i as f64;
121 candle(base, base + 2.0, base - 2.0, base + 1.0, i)
122 })
123 .collect();
124 let mut a = WeightedClose::new();
125 let mut b = WeightedClose::new();
126 assert_eq!(
127 a.batch(&candles),
128 candles.iter().map(|x| b.update(*x)).collect::<Vec<_>>()
129 );
130 }
131}